diff options
author | peter <peter@FreeBSD.org> | 1999-11-30 02:43:11 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1999-11-30 02:43:11 +0000 |
commit | 4ef23ce6957fc75fc005885496d605fed48213e1 (patch) | |
tree | 7828b08c74ef918938b1b853c98f0cb41edac52c | |
parent | 67e0f3ce71726dc4058c2f80a813341a59244dbd (diff) | |
download | FreeBSD-src-4ef23ce6957fc75fc005885496d605fed48213e1.zip FreeBSD-src-4ef23ce6957fc75fc005885496d605fed48213e1.tar.gz |
Import bind v8.2.2.p5, minus the crypto for the time being. The bind
package does have BXA export approval, but the licensing strings on the
dnssafe code are a bit unpleasant. The crypto is easy to restore and bind
will run without it - just without full dnssec support.
Obtained from: The Internet Software Consortium (www.isc.org)
327 files changed, 57465 insertions, 8009 deletions
diff --git a/contrib/bind/CHANGES b/contrib/bind/CHANGES index f987e5c..f98fb18 100644 --- a/contrib/bind/CHANGES +++ b/contrib/bind/CHANGES @@ -1,3 +1,1282 @@ + --- 8.2.2-P5 released --- + + 895. [port] minor NT build and documentation improvements. + + 894. [bug] incorrect "key" statements in named.conf weren't + handled properly. + + --- 8.2.2-P4 released --- + + 893. [bug] DNSSEC logic in bin/host broke -t any + + 892. [bug] multiple SOA on AXFR bug + + --- 8.2.2-P3 released --- + + 891. [bug] options { also-notify { ... }; }; resulted in wrong + pointer being memput with the wrong size on reload. + + 890. [port] A/UX portability improved. + + 889. [port] added IPv6 portability for OpenBSD, NetBSD, FreeBSD. + + --- 8.2.2-P2 released (internal release) --- + + 888. [support] add default: all tag to top src/Makefile so that "make" + will work properly in some OS'. + + 887. [bug] "dig ... axfr" was printing spurious "TSIG ok" msgs. + + 886. [support] top-level Makefile now included in all tarballs. + + 885. [support] IXFR improvements. + + 884. [bug] some deprecated NXT RR forms weren't ignored properly. + + 883. [support] "host" command can now try to verify dnssec signatures. + + 882. [contrib] dns_signer/ had some last minute problems (by author). + + 881. [bug] possible sprintf() overflow prevented. + + 880. [support] minor tweak to bin/dig/dig.c TSIG code to clarify + whether res_nsend or res_nsendsigned is being used. + + 879. [support] add "noesw" target to top-level Makefile (for PL1). + + 878. [port] aix4 HAS_INET6_STRUCTS was not being set based on the + existance of _IN6_ADDR_STRUCT. + + 877. [port] freebsd + KAME need a different Makefile.set + see INSTALL notes. + + 876. [port] IPv6 probe for MPE/IX, NetBSD. + + 875. [bug] bad NAPTR RRs could be loaded from zone files. + + 874. [port] update irix_patch in irix port. + + 873. [port] add SRC/tools to sco's make [std]links. + + --- 8.2.2-REL released --- + + 872. [bug] named-xfer could free() a string twice. + + 871. [port] linux support for broken IPv6. + + 870. [port] more NT fixes and improvements from larry at bay. + + 869. [bug] disable client side IXFR (in named-xfer) for now. + + 868. [bug] updated named-bootconf to handle case insensitive parts + of named.boot. added stubs support. class was not + being reset. + + 867. [support] updated INSTALL notes. + + 866. [port] More NT fixes from larry at bay. + + 865. [port] add #include <limits.h> to next's port_before.h + + 864. [port] change solaris' Makefile.set files to use yacc and lex. + also clean up install and binary paths. + + 863. [bug] lib/isc/ctl_srvr.c needed fcntl.h #included + + --- 8.2.2-T8B (RC2) released --- + + 862. [port] another NT infusion from larry over at bay. + + 861. [support] improve support for tsig'd updates. + + 860. [port] add IPv6 probing to: decunix hpux irix lynxos mpe + netbsd qnx rhapsody sco50 + + 859. [bug] set control sockets to close-on-exec; + potential file descriptor leaks in ctl_srvr. + + 858. [bug] make ns_samename() and use it instead of strcasecmp(). + + 857. [bug] unset update-log can lead to debugging msg mishaps. + + --- 8.2.2-T7B (RC1) released --- + + 856. [bug] IXFR finally works and is reenabled. + + 855. [port] more win/nt changes from bay. + + 854. [bug] /etc/hosts lines longer than 8K can crash gethostent(). + + 853. [bug] another linked list bug shaken out of ns_update. + + 852. [bug] compiled in pathname for nslookup help file was wrong. + + 851. [bug] ns_update had an off by 2 bug when checking names in + SRV records causing unexpected failures. + + 850. [bug] empty updates triggered an overambitious INSIST(). + + --- 8.2.2-T6B released --- + + 849. [support] print rcode on failed UPDATE messages. + + 848. [port] paths.h and port_before.h tweaks from SCO for unixware7. + + 847. [port] add SRC/irix_patch to make links in IRIX + + 846. [support] restore some diagnotics lost when #634 was done. + + 845. [support] WATSQ patch from Ted Rule of Flextech Television. + + 844. [support] added src/DNSSEC with a note about BIND-8.1.2 interop. + + 843. [bug] IXFR fixes. + + 842. [bug] pointer arithmetic on (void *) not ANSI C. + + 841. [port] sco50: make install: libport.a not longer exists. + + 840. [bug] turning on touch_timer() in ctl_clnt.c found a bug. + + 839. [contrib] new version of contrib/host (from author). + + 838. [support] improve error reporting; remove lint. + + 837. [bug] bin/host/host.c was not RFC2317 compliant. + + 836. [port] hpux portability and speed improvements. + + 835. [port] some shell's "cd" produce output - fix in port/systype. + + --- 8.2.2-T5A released --- + + 834. [support] massive changes to dynupd API. + + 833. [port] more Win/NT. + + 832. [feature] boolean: treat-cr-as-space. If yes, BIND will treat + '\r' the same as it treats ' ' and '\t' in zone files. + + 831. [bugs] DNSSEC/CAIRN workshop results (in addition to #826): + - invalid size passed into b64_ntop in SIG parser + - Invalid TSIG keys are now logged and ignored + instead of panicing. + - trusted-keys didn't work if a trailing dot + was present + - a DST problem that occurs when one of the + multiprecision integers begins with a 0 byte. + - TSIG signed truncated responses were mishandled. + - minor RFC2535 changes. + + 830. [doc] Minor updates to INSTALL + + 829. [support] we need to cache SOA NXDOMAIN queries if only for a + clock tick. + + 828. [support] multiple zone warning clearer. + + 827. [bug] the ctl interface was clearing already-cleared timers. + + 826. [contrib] various improvements to contrib/dns_signer (from TIS). + + 825. [support] change __NAMESER and __RES to 19991006. + + 824. [port] sco50 needed #define __BIND_RES_TEXT in port_after.h + + 823. [bug] named-xfer missed a SIG text format change + + 822. [bug] TSIG signed truncated responses crashed the server + + 821. [bug] potential reference after free bugs. + + 820. [port] ultrix finally works again. + + 819. [bug] removed test for missing glue from nslookup() + as it got false matches. There is no simple + test for missing glue. + + 818. [bug] back out #790, there was no memory leak. + + 817. [port] Solaris needed #define BSD_COMP in port_before.h. + + --- 8.2.2-T4B released --- + + 816. [bug] you could not raise the number of available file + descriptors after the first call to res_send() and + make use of them. + + 815. [feature] report version via command line option (-v). + + 814. [feature] getipnodebyname, getipnodebyaddr and freehostent added. + These are RFC 2553 newcomers to the RFC 2133 set. + + 813. [support] better diagnostics when trying to clean up old + unix control socket. + + 812. [bug] uninitalised variable. + + 811. [port] sco50 make links was not linking resolv.h.diffs + + 810. [bug] zone transfer did not transfer all DNSSEC records + at delegation points. + + 809. [support] res_[n]sendupdate has died before it could be used. + + 808. [bug] res_send() wasn't checking for EINTR after select(). + + 807. [support] it's now possible to send TSIG'd updates. + + 806. [support] ns_parserr() was uncompressing from the wrong base + in a certain corner case trod on by res_findzonecut(). + + 805. [bug] only set SO_LINGER if required by the OS, + #define DO_SO_LINGER to do so. + + 804. [bug] another swath of IXFR fixes. + + 803. [port] Compaq Tru64 UNIX 4.0B with ZK3's experimental IPv6 kit + installed will at least build, but hasn't been tested. + + 802. [support] we no longer cache NXDOMAIN if the QTYPE was SOA. + + 801. [bug] our negative caching logic would log spurious errors + if the response had an empty question section. + + 800. [bug] #764 was too aggressive in one case. + + 799. [port] ultrix is a still-moving target. + + 798. [support] QRYLOG now logs the QCLASS + + 797. [bug] closing a thread which had called get*by*() would + leak memory. + + 796. [support] deallocate_on_exit now frees memory allocated by irs. + + 795. [port] solaris 2.4 SO_REUSEADDR generates errors on + unix domain sockets. + + 794. [bug] ixfr_have_log() was logging wrong file name. + + 793. [bug] clean_cache() was not alway removing complete RRsets. + + 792. [bug] deallocate-on-exit caused references to freed memory. + + 791. [support] MEMCLUSTER_DEBUG had an array size error. + + 790. [bug] fix minor memory leak in ixfr code. + + 789. [bug] #669 was too aggressive. more than cached data was + removed. + + 788. [bugs] improvements to tsig and dnssec. + + 787. [port] win/nt lint. + + 786. [port] IRIX and emul_ioctl(). + + 785. [bug] #780 broke A record update support. + + 784. [bugs] still trying to get IXFR working again. + + --- 8.2.2-T3B released --- + + 783. [support] make res_send() more friendly to the java scheduler. + + 782. [support] dangling cnames aren't errors, stop logging them. + + 781. [support] add -n option to ndc command, to run nonstandard named. + + 780. [bug] UPDATE did not support the AAAA RR. + + 779. [bug] miscellaneous IXFR fixes. + + 778. [support] don't complain to syslog about negative caching RRs. + + --- 8.2.2-T2B released --- + + 777. [bug] getword() didn't increment lineno at EOF. + + 776. [bug] the NOERROR_NODATA cookie overlapped a valid rcode. + + 775. [protocol] we weren't sending properly formated FORMERR responses. + + 774. [bug] UPDATE did not support the SRV RR. + + 773. [bug] named-xfer was calling inet_ntoa in one printf. + + 772. [typo] Typo in ns_parser.y on maybe_zero_port: line. + + 771. [lint] UNLINK now performs a INIT_LINK so explicit INIT_LINK's + are nolonger needed after UNLINK. + + 770. [protocol] dynamic update prerequisites were inappropiately + matching wildcards, at variance with RFC 2136. + + 769. [bug] ordering of CNAMES was driven by original query type. + + 768. [support] MINROOTS is now a configuration option "min-roots". + + 767. [clarity] adjust XFR log messages to be more clear about cause. + + 766. [support] add "serial-queries" option to dynamify MAXQSERIAL. + + 765. [feature] added evInitID() and evTestID() for NOTIFY work. + + 764. [bug] DNSSEC changed the semantics of match() without + changing all the call sites that cared about it. + + 763. [bug] NOTIFY events caused by dynamic update weren't being + deferred, and multiple NOTIFY events weren't being + coalesced. + + 762. [support] don't rotate log file versions on server startup. + + 761. [port] named-xfer's openlog() was unconditionally using the + LOG_CONS option. now it does what named does. + + --- 8.2.2-T1A released --- + + 760. [port] preliminary win/nt from baynetworks (thanks!) + + 759. [support] new compile time option BIND_IXFR, defaults to "off", + since our testing has shown up some problems with it. + + 758. [feature] new "ndc reconfig" command only finds new/gone zones, + doesn't stat() master files or qserial() slave SOA's. + + 757. [support] FORCED_RELOAD is no longer optional. + + 756. [support] fixed output format of hmac keys; removed DST chaff. + + 755. [feature] "also-notify" is now a global option. + + 754. [bug] the control socket was not checked for event lib + compatability. + + 753. [feature] "ndc help" now returns one line command summaries. + + 752. [feature] "ndc trace" now takes an optional "level" argument. + + 751. [support] debugging output could segfault in ns_print.c::addstr. + + 750. [port] A/UX 3.1.1. + + 749. [port] #9 has now been done for all Makefiles. + + 748. [feature] "transfer-source" is now a global option. + + 747. [support] SORT_RESPONSE is no longer a compile time option, since + the behaviour can be turned off at runtime with the + "rrset_order fixed;" option. + + 746. [bug] don't bother rescanning the interfaces if setuid!=root. + + 745. [protocol] IXFR transmission was just plain wrong in some cases. + + 744. [support] allow the calling location of strings to be recorded. + + 743. [feature] $GENERATE now supports more record types, and options. + + 742. [port] port/sco50 was using /usr/local/etc for its ndc socket. + + 741. [port] HPUX needed __BIND_RES_TEXT. + + 740. [bug] #634 had the unfortunate side effect of disabling IXFR. + + 739. [port] probe for IPv6 structures, solaris openbsd freebsd + + 738. [bug] invalidate pointers back into linked list when element + is removed. + + 737. [port] solaris: expr is sensitive to LC_COLLATE + + 736. [bug] potential single file descriptor leak opening + /dev/random. + + 735. [bug] memory leak: having rrset-order set and reconfiguring + the server results in a memory leak. + + 734. [port] linux only fills in as many entries as will fill the + buffer with SIOCGIFCONF. + + 733. [bug] RD is not being set on first message to first forwarder + resulting in false "Lame Server" reports and degraded + service. + + 732. [bug] errors reading keys from master files could cause the + the server to drop core. + + 731. [bug] highestFD was not reflecting the highest value the + library could cope with. + + 730. [port] rand() does not modify the LSB on BSD based systems. + + 729. [bug] allow-query responses were dependent upon cache + contents. + + 728. [bug] it wasn't possible to specify the flags of trusted keys + in hex, which was inconvenient since dig prints hex. + + 727. [bug] TSIG keys weren't properly shared with named-xfer if + the zone named contained a slash (/). + + 726. [bug] TSIG keys weren't reloaded correctly with 'ndc reload'. + + 725. [bug] only the first key in an acl was matched correctly. + + 724. [bug] "ndc restart" needed a short delay before checking + for the health of a newly started name server. + + 723. [bug] TSIG signed zone transfer failed on especially + large zones. + + 722. [doc] the example named.conf file had invalid TSIG usage. + + 721. [bug] duplicate records were tripping the cname-and-otherdata + test, which wasn't necessary since they'll be ignored. + + 720. [port] solaris doesn't have gethostid() the way we build. + + 719. [lint] lots of lint fixed by bob and paul. + + 718. [bug] multiple CNAME support was not cycling the cnames in + an RRset properly. + + 717. [bug] wrong /bin/ps flags in solaris prand_conf.h. minor + tweak to ports/prand_conf/prand_conf.c to ensure proper + flags in future ports. + + 716. [bug] log files are now closed/reopened on a size basis. + + 715. [clarity] root servers don't need to be primed. + + 714. [typo] extra "q" in a message in ns_maint.c. + + --- 8.2.1 released --- + + 713. [bug] don't loop on untimely eof within config file. + + 712. [port] hp-ux signals; aix bit types. + + 711. [perf] don't call find_zone() four times from within qnew(). + + --- 8.2.1-t7b released --- + + 710. [bug] can fetch zone from own address if port is different. + + 709. [bug] make sure zones are properly reinited when they die. + + 708. [bug] end marker or sizeof, but not both please. + + --- 8.2.1-t7a released --- + + 707. [port] AIX, HPUX, SunOS. + + 706. [feature] zone forwarding can now be applied to master, slave + and stub zones as well as forward zones. + + 705. [bug] some zone options were not being copied. + + 704. [bug] very obscure problem fixed in res_update(). + + 703. [bug] single-zone reload was stomping freed memory. + + --- 8.2.1-t6b released --- + + 702. [port] solaris vs. enum; linux vs. IPv6. + + 701. [bug] NOTIFY rejection logic still wasn't correct. + + 700. [bug] complete #697 + + --- 8.2.1-t5b (rc2) released --- + + 699. [bug] if getting the ixfr change log fails send a axfr style + response. + + 698. [bug] res_notify() was rejecting valid NOTIFY messages. + re-organise code so that logged messages are more + appropriate. + + 697. [port] linux. + some versions define _GNU_SOURCE in features.h + some version require the compiler to set the byte order + when probing for IPv6 structures. + + 696. [bug] don't use NULL file pointer if IXFR transaction log + cannot be opened due to permission errors. + + 695. [lint] another considerable amount of lint was removed. + + 694. [bug] only the last two forwarders would be used. + + 693. [bug] nsfwdadd() needed to continue outer loop. + + 692. [bug] RD was not being cleared by ns_forw(). this could + cause DNS storms between lame servers. + + 691. [bug] We still had some leftover named-xfer ixfr tmp files. + + 690. [bug] return IXFR in question section of AXFR style IXFR + response. + + 689. [bug] we now return "up to date" response to IXFR queries + when required. + + 688. [bug] UDP IXFR now tells the client to use TCP. + + 687. [bug] IXFR was incorrectly reporting errors on DNSSEC RRs. + + 686. [port] hpux Makefile.set improvement (+O2 -> +ESlit). + + 685. [feature] mark recursive queries in query log. + + 684. [bug] named-xfer now ignores out-of-class glue. + + --- 8.2.1-t4b (RC1) released --- + + 683. [lint] considerable lint was removed. + + 682. [perf] another round of performance tweaks from HP (thanks!). + + 681. [bug] SIG wasn't being ignored when generating NOTIFY msgs. + + 680. [feature] delay parent reload as long as we can after removing + child zone to save multiple parent reloads. + + 679. [port] port probe now recognizes SCO 5.0.5. + + 678. [doc] not all man pages were being installed. + + 677. [feature] lost feature "allow-recursion" added back in. + + 676. [bug] "100" was too small for ndc message sizes. + + 675. [bug] we weren't storing a (needed) extra copy of the zname. + + 674. [bug] SIGTERM wasn't working the first time it was sent. + + --- 8.2.1-t3b released --- + + 673. [bug] nslookup wasn't accepting _ at the beginning of names. + + 672. [bug] ndc was only passing the verb across the command + channel and not the arguements. Reload of a single + zone "really" works now. + + 671. [feature] you can reload multiple zones with a single ndc reload + command. e.g. ndc reload zone1 zone2 ... + + 670. [bug] db_load did not work unless a RR had the class defined. + + 669. [bug] the cache is now purged when a forwarder is {re}loaded. + + 668. [bug] complete #652. + + 667. [bug] allow-query wasn't being allowed for stub zones. + + 666. [usability] only try to chown()/chmod() a control socket when the + owner or permissions _change_ between reloads. + + 665. [bug] "options topology" is now possible to set. + + 664. [security] add important solaris-related security note to README. + + 663. [bug] "ndc -q" now turns off initial header and EOF printing. + + --- 8.2.1-t2b released --- + + 662. [usability] src/conf/ added, containing some of ISC's config files. + + 661. [protocol] we weren't sending AAAA RR's as AXFR glue. + + 660. [port] IRIX. + + 659. [contrib] author-submitted changes to dnssigner, new cider2named. + + 658. [protocol] print better messages wrt TSIG. add p_rcode(). + remove _res_resultcodes[]. improve key handling. + + 657. [port] apply cpp to /usr/include/netinet/in.h to work out if + struct sockaddr_in6 and struct in6_addr/inaddr6 are + defined. + + 656. [bug] Classless IN-ADDR support was broken. + + 655. [bug] major overhaul of IXFR code. + + 654. [bug] dynamic update of non top of zone SOA now ZONEERR. + + 653. [feature] check-names now applied dynamic updates as if + the zone was being loaded. REFUSED returned. + + 652. [port/bug] many operating systems allow more descriptors than + their default FD_SETSIZE has room for. we catch this + now, both by asking the operating system not to do this + and by treating as invalid any out-of-range descriptor. + + 651. [protocol] any soft failures in res_send() will now cause the + final return value to be TRY_AGAIN. previously the + last server response received was the one returned. + + 650. [doc] resolver.5 man page clarified and corrected; res_init() + made to do what the man page now says it does. + + 649. [port] make header files c++ compatible. + + 648. [bug] multiple options definitions of allow-query / + allow-transfer / sortlist / blackist / topology + are not allowed. warn rather than silently applying + the last definition. + + 647. [bug] options max-ixfr-log-size was not being applied. + + 646. [feature] memcluster debugging support improved. + -DRECORD_MEMCLUSTER to enable. + + 645. [bug] memory leaks + + 644. [bug] res_update() could not delete the first CNAME + in a chain. + + 643. [bug] res_update() did not correctly handle labels + with periods. + + 642. [port] SCO 5.0 portability improved. + + 641. [feature] $TTL now takes TTLs of the form 1w6d7h32m20s. + + 640. [bug] was returning NODATA rather than NXDOMAIN after a + dynamic update removed the last RR from a childless + node. + + 639. [bug] another fix for "rrset_order fixed". + + --- 8.2.1-t1a released --- + + 638. [bug] ixfr was still creating the wrong file names sometimes. + + 637. [bug] bin/dnsquery/dnsquery.c wasn't init'ing the resolver + correctly befloew calling gethostbyname(). + + 636. [port] inet_ntoa() had to go back to being non-const for now. + + 635. [bug] AXFR wasn't forcing an autoincrement of SOA.SERIAL + following a batch of UPDATE requests. + + 634. [feature] check all master soa's and use best serial, rather + than trying them in order and grabbing the first + one who answers with one better than the local one. + + 633. [port] SunOS 4.1.4 has a broken recvfrom() with non-blocking + sockets. + + 632. [bug] res_mkupdate() signed/unsigned stupidity. + + 631. [bug] HMAC-MD5 fixes + + 630. [bug] NSTATS output was spaceless. + + 629. [misc] improvements to TSIG error logging. + + 628. [bug] "rrset_order fixed" was LIFO rather than FIFO. + + 627. [bug] TSIG signed zone transfers broken. + + 626. [bug] multiple CNAME support was broken. + + 625. [bug] key names are really domains so they need to be + made canonical. + + 624. [bug] ns_name_pton() accepted domains of the form + "example.." when it should have rejected them. + + 623. [feature] it is occasionally useful to know the local address + used to perform a zone transfer. this is now logged. + + 622. [bug] missing check for malloc() failures in strndup(). + + 621. [bug] various things were wrong with nslookup's "ls -d" cmd. + + 620. [feature] forwarders are now retried like queries to the + delegated nameservers. forward only should be + more robust as a result. + + 619. [protocol] don't refresh TTL's from delegation information. + + 618. [feature] ndc is now quiet and verbose when it should be. + + 617. [bug] SOA counters now have minima as well as maxima. + + 616. [bug] needs were not always processed in a timely fashion. + + 615. [bug] ns_shutdown() memput() the wrong amount of memory + when freeing the zones array. + + 614. [feature] ndc can now reload single zones including the root + zone. + + 613. [bug] check for old unix domain socket / fifo prior to + attempting to establish control channel. error + message no longer just noise. + + 612. [port] Solaris UNIX domain sockets return different error + codes and also may use FIFOs. + + 611. [bug] extend control timeout to 10 minutes. reloads can + take a long time. + + 610. [bug] when reloading via the control channel we were + reporting that we were about to reload after the + reload was performed. Ensure message is set prior + to reloading. + + 609. [bug] zoneTypeString() could be called with NULL pointer. + + 608. [bug] set various pointers to NULL after associated + memory has been released to prevent accidental use. + + 607. [bug] finddata() was returning SIG's inappropriately. + + 606. [bug] fix two memory leaks in db_sec.c. + + 605. [feature] better error reporting from named-xfer. + + 604. [bug] fix a bug in the handling of $TTL's absence. + + 603. [port] add contributed/untested rhapsody port. + + 602. [bug] multiple "type hint" zones are now supported. + + 601. [bug] z_ftime wasn't being reset when fopen() failed. + + 600. [bug] gen_res_get() was initializing the wrong variable. + + 599. [bug] "ndc reload" exercised an uninitialized variable. + + 598. [bug] "nslookup reports danger" was reported ambiguously. + + 597. [bug] we weren't priming the cache in forward-only mode. + + 596. [bugs] many small bugs in DNSSEC handling were fixed. + + 595. [bug] nsupdate failed to support quite a few rr types: + sig,key,nxt,eid,numloc,srv,atma,naptr,kx,cert + + 594. [proto] BADID removed per I-D. + + 593. [bug] mk_update() didn't support SIG. + + 592. [bug] lcl_pr and lcl_ho were using uninitialized bufsizes. + + 591. [port] linux. + + 590. [port] irix. + + 589. [doc] hesiod(3) man page contrib'd in 1996 finally put in. + + 588. [bug] too many lame servers at once was fatal. + + --- 8.2 released --- + + 587. [perf] uses about 5% less memory than 8.1.2 now. + + 586. [perf] faster at tcp, therefore less blocking on udp. + + 585. [misc] various releng lint. + + 584. [bug] IXFR wasn't doing DNSSEC RRtypes. + + 583. [bug] dnskeygen now fully qualifies its names; better usage. + + 582. [port] irix needed some patches applied during the build. + + 581. [bug] match_order() could dump core after "ndc reload". + + 580. [bug] ip_match_is_none() could dump core. + + 579. [bug] state names were off by one in src/lib/isc/ctl_srvr.c. + + 578. [misc] try without "transfer-source" if axfr connect() fails. + + 577. [contrib] sqlbind-8. + + 576. [bug] insecure updates weren't supported. + + 575. [doc] better documentation of key, trusted-key, zone pubkey. + + 574. [bug] was freeing freed memory on exit. + + 573. [port] nextstep. + + 572. [misc] centralize the name hashing logic (widen in some cases) + + 571. [perf] the new db_marshal() code was taking too much memory. + + 570. [perf] the lame server storage was taking too much memory. + + 569. [bug] src/lib/isc/ctl_srvr.c had an incomplete assertion. + + 568. [doc] Brent Baccala contributed an nsupdate man page. + + 567. [port] mpe, nextstep. + + 566. [protocol] upgrade to tsig draft 08. + + 565. [lint] use right relative paths for dnssafe includes in dst. + + 564. [bug] default security level for update rr's wasn't set. + + 563. [bug] debugging output in dprint_key_info() could panic us. + + 562. [perf] 8.2-t6b used 30% more memory on root name servers than + 8.1.2 did. most of that was db_marshal hash tables. + + --- 8.2-T6B released --- + + 561. [bug] DST more graceful in handling unsupported algorithms. + + 560. [feature] lame server ttl now a configuration option. Re-enable + lame server negative caching. + + 559. [bug] sysquery() was still using the child's name when it + switched to using the parent's NS list causing false + lame server reports. + + 558. [bug] disable lame server negative caching for the present. + + 557. [bug] undersized tcp messages are now detected early. + + 556. [bug] DNSSEC fine tuning. + + 555. [bug] the named.conf lexer was depending on two characters + worth of putback buffer, ansi c guarantees one char. + + 554. [port] port to "next" contributed by jack bryans. + + 553. [contrib] added "snoof", another script kiddie toy. + + 552. [bug] allow-query didn't interact well with external cnames. + + 551. [bug] validate_zone could crash the server. + + 550. [lint] ns_maint was using ns_log_default, not ns_log_in_xfer. + + 549. [port] netbsd and openbsd improved. prand_conf improved. + + 548. [bug] ns_resp was using the wrong logging category. + + 547. [bug] dig was reinit'ing its resolver flags incorrectly. + + 546. [bug] nsupdate didn't handle HINFO,ISDN,TXT,X25 correctly. + + 545. [feature] added dnssafe back in. + + 544. [feature] removed DES encryption support. + + 543. [port] cleaned cylink of non used definitons in headerfiles. + + 542. [bug] include/dst no longer needed + + 541. [bug] CERT records are allowed to have alg == 0. + + 540. [doc] Removed outdated doc/secure, updated dnssigner + documentation, updated dnskeygen.1 + + 539. [bug] db_dump() was misparsing CERT records. + + 538. [feature] The KEY set is along with SOA, NS, A, AAAA records. + + 537. [bug] Multiple signatures are handled correctly. + + 536. [bug] SIG record expiration should be checked when the + SIG is verified. + + 535. [bug] Queries for SIG records of non-authoritative + names should not look in the cache or cache the + results. + + 534. [bug] DNSSEC SIG records are dropped when they don't + sign any data correctly. + + 533. [bug] SIG and NXT records are correctly handled when + received in responses by named + + 532. [bug] dynamic update data is now always considered + insecure, rather than having no security status. + + 531. [bug] dynamic update can again remove all data associated + with a name (type ANY, class ANY). + + 530. [lint] downgraded "ctl: unexpected eof" from error to debug. + + 529. [port] unixware 7 port received. + + 528. [bug] timeouts could make ctl_srvr dump core. + + 527. [bug] we were not reliably reaping our children. + + 526. [bug] Cached CNAMES pointing to servers returning Type 3/4 + NXDOMAIN are translated to Type 3 NODATA responses. + + 525. [bug] nscount could be short if we had to recurse after + following a cname and we got a negative response. + NS rrset got split between AU and AD sections. + + 524. [protocol] RFC 2308 support added. + + 523. [feature] mark lame servers as such and don't use them for NTTL. + + 522. [port] solaris 7 is now known to work. + + 521. [port] sunos4 should be supported now. + + 520. [bug] inet_pton() was allowing some bad ipv6 addresses in. + + 519. [bug] refuse duplicate also-notify's; optimize logging. + + 518. [port] hpux portability fixes. + + 517. [contrib] dnswalk wasn't copying with 8.* "dig" output. + + 516. [port] MPE portability fix. + + --- 8.2-T5B released --- + + 515. [security] lib/dnssafe code removed; now a separate patch. + + 514. [port] freebsd patches. + + 513. [bug] memory leak in res_mkupdate(). + + 512. [bug] $GENERATE could use an unset ttl. + + 511. [bug] $TTL warning test was wrong. + + 510. [port] bugs and things found by the netbsd folks. + + 509. [bug] The labels field in the SIG record may be less than + the number of labels in the domain name if the + owner of the SIG is a wildcard. + + 508. [bug] rrset ordering contained an off-by-one error + + 507. [bug] NXT set processing was not distinguishing + between the upper and lower sets at delegation + points. + + 506. [contrib] more script-kiddie toys, this time contrib/adm. + + 505. [bug] the ixfr changes to named-xfer destabilized stubs. + + 504. [port] some IRIX problems fixed. + + 503. [bug] ixfr wasn't correctly setting up its qsp. + + --- 8.2-T4A released --- + + 502. [bug] some config file parsing was still using malloc(). + + 501. [feature] named sets the AD bit in the header when returning + authenticated data + + 500. [bug] dst_verify_data returns the documented error codes + + 499. [bug] verify_set now verifies the correct data + + 498. [bug] ixfr was not completely finished. + + 497. [bug] don't put zone 0 on the free list. + + 496. [bug] Losing all but last RR of RRset. + + 495. [port] random portability noise. + + 494. [bug] sysquery() should not let nlookup() change its data. + + 493. [feature] add "options ... rrset_order ... cyclic|random|etc". + this allows round robin to be turned off selectively, + or replaced with pseudorandom ordering, or whatever. + + 492. [bug] src/bin/named/db_sec.c was memputting objects twice. + + 491. [feature] add IRP (Information Retrieval Protocol) and daemon. + this is functionally similar to solaris "nscd". + + 490. [bug] lib/isc/ctl_srvr.c couldn't overlap read and write. + (also: add session context set/get.) + + 489. [bug] "cname and other data" was more complex than thought. + + 488. [port] some netbsd portability stuff. (still not working?) + + 487. [port] digital unix 3.2 wasn't working (4.0d was though). + + 486. [feature] add "sortlist", which may yet be merged/renamed into + the "topology" verb. + + 485. [bug] do not complain about default TTLs unless a master. + + 484. [contrib] add contrib/z0ne, a useful tool for crackers. + + 483. [contrib] add contrib/query-loc[-*] to look up LOC RR's. + + 482. [bug] all RR's must now be of the same class as the zone. + + 481. [bug] outbound zone transfers are killed on any UPDATE. + + --- 8.2-T3A released --- + + 480. [bug] ns_update was corrupting TXT records + + 479. [bug] res_mkupdate was not handling WKS, HINFO, TXT, + X25, ISDN, NSAP and LOC records. + + 478. [bug] name_pack could leave a bad compression pointer. + + 477. [port] improved support for FreeBSD 3.0. + + 476. [bug] BSDI contributed some fixes to the /etc/group parsing. + + 475. [bug] another memory leak in hesiod_resolve(). + + 474. [bug] SRV RR names were being compressed on output. + + 473. [feature] IXFR is no longer optional and has been cleaned up. + + 472. [bug] IXFR was disabling USE_PID_FILE. + + 471. [feature] add support for CERT records. + + 470. [bug] rrset_db_upgrade was updating the wrong cache. + + 469. [performance] use a free list for unused zones. + + 468. [feature] add getaddrinfo, courtesy of WIDE. + + 467. [lint] include/dst/dst.h moved to include/isc/dst.h. + + 466. [bug] fix core dump introduced with tsig glue. + + --- 8.2-T2A released --- + + 465. [bug] ref counting bug in ns_xfr. + + 464. [bug] correct cut&pasteo in IXFR config syntax. + + 463. [lint] clean psf files after top level "make tar". + + --- 8.2-T1A released --- + + 462. [feature] we now use randomized query id's. + + 461. [feature] new option "version" added. + + 460. [feature] add initial IXFR support from Check Point Technologies. + + 459. [bug] res_update() was putting debugging info on stderr. + + 458. [doc] add named.conf(5), improve doc/html. + + 457. [feature] named-bootconf is now written in /bin/sh and it is + now installed in ${DESTSBIN}. + + 456. [bug] res->defdname[] wasn't always properly \0 terminated. + + 455. [bug] _PATH_MEMSTATS was never being used. + + 454. [doc] the html docs weren't clear about logging having to + be specified first in the named.conf file. + + 453. [feature] add zone type "forward" for selective forwarding + (sometimes called "split horizon" or "fake root"). + + 452. [bug] lib/irs/* was generally not coping with + oversized lines and files not ending in \n. + + 451. [port] BSD/OS 2.* is now a separate port. + + 450. [Feature] added DNS key generator in bin/dnskeygen. + + 449. [contrib] added DNS zone signer in contrib/dns_signer. + + 448. [doc] sample named.conf and html documentation include + examples of DNSSEC / TSIG configurations. + + 447. [feature] named verifies TSIG records on incoming messages, and + generates TSIG records on outgoing messages. + + 446. [feature] res_nsendsigned, res_nfindprimary, res_nsendupdate + provide TSIG aware resolver functions. + + 445. [feature] ns_sign and ns_verify generate/authenticate TSIG + signatures on DNS messages. ns_sign_tcp, + ns_sign_tcp_init, ns_verify_tcp, and + ns_verify_tcp_init are used for tcp transfers. + + 444. [feature] acls can now include shared key names. + + 443. [feature] added DNSSEC verification of zone data on load and + partial verification of signed data received over + the wire. + + 442. [feature] lib/dst (TIS digital signature toolkit), lib/dnssafe, + and lib/cylink added to provide functionality + needed for DNSSEC and transaction signatures. + + 441. [bug] fixed memory leak in hesoid support. + + 440. [bug] support for res in lib irs was a mess. _res now + controls the behaviour of get*by*() again. + + 439. [bug] fix *END_RESULT macros in port/solaris/port_before.h. + + 438. [feature] permit the install user and group to be overridden. + + 437. [feature] TCP truncation now reports IP address of the server. + + 436. [bug] memory leaks in nsupdate. + + 435. [doc] updated resolver.3 + + 434. [bug] named.run was not always being created when ndc trace + was run. + + 433. [bug] req_notify required the slave zone to have been loaded. + this may not be the case when a zone has expired or + is being established over a dial on demand link. + + 432. [feature] blackhole queries from these nets. do not use these + nets to resolve queries. + + 431. [feature] loop breaking with UDP based well known services. + + 430. [bug] memory leaks in dispatch_message. + + 429. [feature] fast retries on host/net unreachable. + + 428. [bug] CNAME and other data is now a hard error. + + 427. [feature] support very large numbers of virtual interfaces. + + 426. [bug] bring named closer into line with the data ranking + in RFC 2181, Section 5.4.1. + + 425. [bug] removed spurious debug statment that generated a lot + false bug reports. + + 424. [bug] closed file descriptor leaks in ns_update. + + 423. [feature] loc_ntoa() can now accept NULL like other _ntoa's. + + 422. [feature] you can now specify a port on the master statement + to allow transfers from a non standard port. + + 421. [feature] warn when the root hints do not match reality. + + 420. [misc] added support for bcc (bounds checking compiler). + + 419. [feature] bring negative caching into RFC 2308 compliance. + + 418. [bug] expire now behaviour now as per RFC 1034/1035. + + 417. [bug] updates and zone transfers weren't locking eachother. + + 416. [port] support added for HPUX B.11.* + + 415. [feature] ndc is a C program now, uses new "controls" subsystem. + + 414. [feature] "controls" element of named.conf now live and working. + + 413. [feature] octal and hexadecimal numbers now parsed in named.conf. + + 412. [bug] we now support 2**24-1 (16M) zones. (need namespaces!) + + 411. [bug] fix *END_RESULT macros in port/bsdos/port_before.h + + 410. [feature] added support for dial on demand links between + servers. + + 409. [port] remove aggregious use of snprintf(). + + 408. [feature] add -b option to dig to set srcaddr of tcp connects. + + 407. [feature] added $GENERATE to generate sets of RR's that only + differ by an interator. + + 406. [doc] added manpage for inet_cidr_ntop() inet_cidr_pton(). + + 405. [bug] res_nsend() closed sockets unnecessarily on timeout. + handle change NS list and RES_STAYOPEN generically. + + 404. [bug] inet_addr/inet_aton/inet_network accepted illegal + inputs as legal. Also enforce octal input. + + 403. [bug] inet_cidr_ntop() was not producing correct output for + all possible inputs. + + 402. [bug] fix retry/retransmit logic in face of network errors. + + 401. [doc] the "transfer-source" zone option wasn't documented. + + 400. [bug] bin/host was dumping core - converted to use getopt. + + 399. [port] use time() rather than gettimeofday() in dig. + + 398. [bug] named could exit silently on assertion failures, + now assertion failures are logged using INSIST. + + 397. [port] add an AIX 3.2 port (requires GNU utilities). + + 396. [bug] dig and nslookup allowed sscanf/sprintf overflows. + + 395. [bug] dig and nslookup were unable to deal with 64KB answers. + + 394. [feature] add RES_NOCHECKNAME and "options no-check-names" (in + resolv.conf) to turn off modern host/mail name checks. + + 393. [bug] lib/isc/tree.c was missing a critical \ (#if DEBUG). + + 392. [bug] inet_aton() wasn't requiring nonterminal octets to + be in the range of octets, i.e., 1.300.1.1. + + 391. [bug] fix bug in MAX_XFERS_RUNNING logic. + + 390. [bug] ns_update() was capable of renaming an open file. + + 389. [feature] libbind.a now has a "ctl" subsystem, which is planned + to replace signals as a the communication path between + "ndc" and "named". preliminary support is in "named". + + 388. [feature] preliminary/nonfunctional/nonstandard ZXFR support. + + 387. [feature] inet_cidr_pton() and inet_cidr_ntop() added. + + 386. [bug] inet_net_pton() was not parsing hex correctly. + + 385. [feature] three new options for the RES_OPTIONS environment var + or for the "options" directive in /etc/resolv.conf: + attempts:NN default res.retry + timeout:NN default res.retrans + rotate use ALL listed nameservers + + 384. [feature] there is now a nearly-thread-safe resolver API, with + the old non-thread-safe API being a set of stubs on + top of this. it is possible to program without _res. + note: the documentation has not been updated. also + note: IRS is a thread-ready API, get*by*() is not. + (see ../contrib/manyhosts for an example application.) + + 383. [contrib] bsdi contributed an /etc/services.db hack, which is + currently conditionalized for bsd/os but would work + on any modern BSD-derived system (DB, snprintf, etc). + + 382. [port] bsd/os 4.0 defines its own pselect(), which differs + from the one we simulated. we now simulate the right + one, and use the right one. + + 381. [contrib] added contrib/srv, the beginnings of SRV client side. --- 8.1.2 released --- diff --git a/contrib/bind/DNSSEC b/contrib/bind/DNSSEC new file mode 100644 index 0000000..9230f86 --- /dev/null +++ b/contrib/bind/DNSSEC @@ -0,0 +1,39 @@ +$Id: DNSSEC,v 8.2 1999/10/12 18:23:27 ogud Exp $ + +DNSSEC Notes: + +This file contains description of two interoperabilty problems related +to DNSSEC that only affect sites using DNSSEC. + +1. All versions of bind-8 older than 8.2.2 + +Between versions 8.2.1 and 8.2.2 the printed format of SIG records +changed. As a result, using a signer, named and named-xfer of +differrent versions will cause parsing errors on signed zonefiles. +Included is an AWK program that converts old signed zone files to new +new format, see contrib/dns_signer/add_labels.awk +Usage: awk -f <path>/contrib/dns_signer/add_labels.awk <signed_zone >fixed_zone + +2. BIND-8.1 BIND-8.1.1 BIND-8.1.2 Interoperability + +If you wish to use BIND-8.1.x as a master server (either primary or +secondary) for DNSSEC signed zone you MUST apply the following patch +to the file src/bin/named/db_load.c. It fixes a bug that rejects +valid RSA signatures on load. +You can patch the file by running following command from this directory + patch -d bin/named <DNSSEC + +--- db_load.c.old Mon Oct 11 15:21:24 1999 ++++ db_load.c Mon Oct 11 15:21:38 1999 +@@ -1123,9 +1123,6 @@ + ERRTO("Signature too short"); + if (siglen > (NS_MD5RSA_MAX_BITS + 7) / 8) + ERRTO("Signature too long"); +- /* We rely on cp from parse */ +- if (*cp == 0) +- ERRTO("Signature starts with zeroes"); + break; + + case NS_ALG_EXPIRE_ONLY: + + diff --git a/contrib/bind/INSTALL b/contrib/bind/INSTALL index 5672a6d..165f529 100644 --- a/contrib/bind/INSTALL +++ b/contrib/bind/INSTALL @@ -1,11 +1,19 @@ -Supported Systems +Systems it is known to compile and run on: + + BSD/OS 3.1, 4.0.1 + FreeBSD 3.1, 3.2, 3.3 + RH Linux 5.2 (don't use "make links" when building, though) + Debian GNU/Linux 2.2.9 ("unreleased") + Digital UNIX 3.2C, 4.0, 5.0 + NetBSD/i386 1.3.2, 1.4 + SunOS 5.6 (Solaris 2.6), SunOS 5.7 (Solaris 7) + SCO UnixWare 7.0, 7.0.1, 7.1 + +Systems it has been known in the past to compile and run on: AIX 4.x A/UX 3.1.1 - BSD/OS 2.1, 3.x Digital ULTRIX 4.5 - Digital UNIX 3.2C, 4.0 - FreeBSD 2.x, 3.0 HP MPE HP-UX 9.x, 10.20 IRIX 5.3, 6.2, 6.4 @@ -13,10 +21,9 @@ Supported Systems NetBSD 1.2, 1.3 OpenBSD 2.1 QNX - Red Hat Linux 4.x, 5.0 SCO UNIX 3.2v4.2, SCO OSE 5.0.4, UnixWare 2.0.x, 2.1.2 SunOS 4.1.4 - SunOS 5.5 (Solaris 2.5), 5.6 (Solaris 2.6) + SunOS 5.5 (Solaris 2.5) See port/README for information on porting BIND 8 to other systems. @@ -50,9 +57,11 @@ Building make depend + NOTE: "make depend" is a NO-OP for these platforms: AIX, HPUX and NeXT. + Finally, - make + make all Installation @@ -69,15 +78,20 @@ Installation DESTDIR prefix used in front of all other DEST variables. The default is the - empty prefix. + empty prefix. (for non-root installs; + not equivalent to autoconf's --prefix) + DESTLIB libraries DESTINC include files DESTBIN ordinary binaries (e.g. dig, nslookup) DESTSBIN system binaries (e.g. named) DESTEXEC helper binaries (e.g. named-xfer) DESTHELP place to put nslookup's help file + DESTMAN man file location DESTETC configuration file - DESTRUN PID file location + DESTRUN PID file location and "ndc" control + channel location. This cannot be the + same directory as DESTSBIN. These variables should be specified in the Makefile.set for your port (e.g. if you use Solaris, in src/port/solaris/Makefile.set). @@ -120,6 +134,10 @@ Operating System Notes Build problems have been reported with the AIX "make". We recommend using GNU "make" instead. + + FreeBSD, NetBSD, OpenBSD and BSDI + The kit should compile even if you have intalled the KAME + IPv6 kit. Linux @@ -157,6 +175,10 @@ Operating System Notes An ANSI/ISO C compiler is required; we used gcc 2.7.2.1. + NeXT + + Read src/port/next/README.FIRST before trying to build. + Certain older versions of FreeBSD, NetBSD and BSD/OS These systems have a /bin/sh based on "ash", which doesn't diff --git a/contrib/bind/LICENSE b/contrib/bind/LICENSE new file mode 100644 index 0000000..36174cd --- /dev/null +++ b/contrib/bind/LICENSE @@ -0,0 +1,22 @@ +## Copyright (c) 1993-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. + + Internet Software Consortium + 950 Charter Street + Redwood City, CA 94063 + Tel: 1-888-868-1001 (toll free in U.S.) + Tel: 1-650-779-7091 + Fax: 1-650-779-7055 + Email: info@isc.org diff --git a/contrib/bind/Makefile b/contrib/bind/Makefile index 2a95287..5df7fdc 100644 --- a/contrib/bind/Makefile +++ b/contrib/bind/Makefile @@ -1,4 +1,4 @@ -## Copyright (c) 1996 by Internet Software Consortium. +## 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 @@ -13,13 +13,15 @@ ## ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ## SOFTWARE. -# $Id: Makefile,v 8.46 1998/01/28 23:42:06 halley Exp $ +# $Id: Makefile,v 8.51 1999/11/06 03:24:02 vixie Exp $ TOP= SUBDIRS= include port lib bin SH=sh +default: all + all clean depend install distclean:: FRC @set -e; \ version=`cat ${TOP}Version`; \ @@ -46,7 +48,7 @@ links: FRC @set -e; mkdir ${DST}; cd ${DST}; pwd; ln -s ${SRC} SRC; \ ln -s SRC/Version .; cp SRC/Makefile .; chmod +w Makefile; \ systype=`${SH} SRC/port/systype`; \ - for x in ${SUBDIRS}; do \ + for x in ${SUBDIRS} ; do \ ( mkdir $$x; cd $$x; pwd; ln -s ../SRC/$$x SRC; \ cp SRC/Makefile Makefile; chmod +w Makefile; \ ${MAKE} ${MARGS} SYSTYPE=$$systype links; \ @@ -61,6 +63,6 @@ stdlinks: FRC uplinks: FRC @set -e; systype=`${SH} ${TOP}port/systype`; pwd=`pwd`; \ - ${MAKE} ${MARGS} SRC=$$pwd "DST=`dirname $$pwd`/$$systype" links + ${MAKE} ${MARGS} SRC=../`basename $$pwd` "DST=../$$systype" links FRC: diff --git a/contrib/bind/README b/contrib/bind/README index d3831d1..10a3f3b 100644 --- a/contrib/bind/README +++ b/contrib/bind/README @@ -1,8 +1,76 @@ -This is the source portion of BIND version 8.1.2. Its companions are -"doc" and "contrib" so you are probably not missing anything. +This is the source portion of BIND version 8.2.2, Patchlevel 5. Its +companions are "doc" and "contrib" so you are probably not missing anything. See the CHANGES file for a detailed listing of all changes. See the INSTALL -file for information on building and installing BIND 8.1.2. +file for information on building and installing BIND. + +See the SUPPORT file for information on obtaining commercial support for ISC +artifacts including BIND, INN, and DHCP. + +SECURITY NOTE: + + Solaris and other pre-4.4BSD kernels do not respect ownership or + protections on UNIX-domain sockets. This means that the default + path for the NDC control socket (/var/run/ndc) is such that any + user (root or other) on such systems can issue any NDC command + except "start" and "restart". The short term fix for this is to + override the default path and put such control sockets into root- + owned directories which do not permit non-root to r/w/x through them. + The medium term fix is for BIND to enforce this requirement internally. + The long term fix is for all kernels to upgrade to 4.4BSD semantics. + +BIND 8.2.2 patchlevel 5 Highlights + + Bug in named-xfer (from patchlevel 4). + Portability to IPv6 versions of FreeBSD, OpenBSD, NetBSD. + Portability improvements (A/UX, AIX, IRIX, NetBSD, SCO, MPE/IX, NT). + "also-notify" option could cause memory allocation errors. + IXFR improvements (though client-side is still disabled). + Contributed software upgraded (including TIS's "dns_signer"). + Several latent denial-of-service bugs fixed (from audits, not abuse). + New "make noesw" top-level target for removing encumbered components. + +BIND 8.2.2 Highlights + + Interoperability with MS-Win2K has been improved. + Server-side IXFR is now known to work even under high load. + Support for Windows/NT (thanks to BayNetworks). + More fixes, especially to DNSSEC, TSIG, IXFR, and selective forwarding. + More portability improvements and lint removal (A/UX 3.1.1, SCO 5.0). + Better NOTIFY behaviour, especially with large update volume. + Better UPDATE handling, including SRV RR support and RFC compliance. + Fix for "ndc reload ZONENAME" (specific zone reload) problems. + Fix for round robin when multiple CNAMEs are in use. + New "min-roots" (MINROOTS) and "serial-queries" (MAXQSERIAL) options. + Log files are no longer auto-rotated every time the server starts up. + New "ndc reconfig" command only finds new/deleted zones, no stat()ing. + New global options for "transfer-source" and "also-notify". + $GENERATE now supports more record types, and options. + + +BIND 8.2.1 Highlights + + Bug fixes, especially to DNSSEC, TSIG, IXFR, and selective forwarding. + Portability improvements and lint removal. + Use best SOA rather than first-better when selecting an AXFR master. + $TTL now accepts symbolic time values (such as "$TTL 1h30m"). + "ndc reload" now accepts a zone argument, for single-zone reloads. + ndc is better behaved; is verbose or quiet when appropriate. + event and error reporting improvements. + +BIND 8.2 Highlights + + RFC 2308 (Negative Caching) + RFC 2181 (DNS Clarifications) + RFC 2065 (DNS Security) + TSIG (Transaction SIGnatures) + support for multiple virtual name servers + NDC uses a "control channel" now (no more signals) + "Split DNS" via zone type "forward". + + Many bug fixes + Documentation improvements + Performance enhancements BIND 8.1.2 Highlights diff --git a/contrib/bind/SUPPORT b/contrib/bind/SUPPORT new file mode 100644 index 0000000..1f12ba8 --- /dev/null +++ b/contrib/bind/SUPPORT @@ -0,0 +1,10 @@ +> The Internet Software Consortium now offers support agreements for ISC +> software. Under these programs, organizations using BIND, DHCP or INN +> from ISC can obtain a range of on call assistance, bug fixes, training and +> consultation services. These programs are documented on our web page at: +> +> http://www.isc.org/support.html +> +> Discussion about programs to meet your needs is welcome at +> clientservices@isc.org. Please forward your questions there or call us at +> +1 650 779-7018 to speak with the Director of Client Services. diff --git a/contrib/bind/Version b/contrib/bind/Version index 6b409d9..b14fd71 100644 --- a/contrib/bind/Version +++ b/contrib/bind/Version @@ -1 +1 @@ -8.1.2 +8.2.2-P5-NOESW diff --git a/contrib/bind/bin/Makefile b/contrib/bind/bin/Makefile index b330286..ffe01a3 100644 --- a/contrib/bind/bin/Makefile +++ b/contrib/bind/bin/Makefile @@ -1,4 +1,4 @@ -## Copyright (c) 1996 by Internet Software Consortium +## 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 @@ -13,7 +13,7 @@ ## ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ## SOFTWARE. -# $Id: Makefile,v 8.17 1998/03/20 00:40:13 halley Exp $ +# $Id: Makefile,v 8.27 1999/08/08 17:13:24 vixie Exp $ DESTDIR= CC= cc @@ -33,32 +33,35 @@ PORTINCL = ${TOP}/port/${SYSTYPE}/include LEX = lex -I YACC = yacc SYSLIBS = -ll -lutil -PIDDIR = /var/run DESTBIN = /usr/local/bin DESTSBIN = /usr/local/sbin DESTEXEC = /usr/local/libexec DESTMAN = /usr/share/man DESTHELP= /usr/share/misc -AR= ar cruv +AR= ar cru +INSTALL_EXEC= +INSTALL_LIB=-o bin -g bin LDFLAGS= MARGS = "SYSTYPE=${SYSTYPE}" "SHELL=${SHELL}" "A=${A}" "O=${O}" \ "CC=${CC}" "LEX=${LEX}" "YACC=${YACC}" "CDEBUG=${CDEBUG}" \ "SYSLIBS=${SYSLIBS}" "LDFLAGS=${LDFLAGS}" \ - "DESTDIR=${DESTDIR}" "PIDDIR=${PIDDIR}" "DESTMAN=${DESTMAN}" \ + "DESTDIR=${DESTDIR}" "DESTMAN=${DESTMAN}" \ "DESTBIN=${DESTBIN}" "DESTSBIN=${DESTSBIN}" "DESTEXEC=${DESTEXEC}" \ "DESTLIB=${DESTLIB}" "DESTINC=${DESTINC}" "DESTETC=${DESTETC}" \ "DESTRUN=${DESTRUN}" "DESTHELP=${DESTHELP}" \ "RANLIB=${RANLIB}" "AR=${AR}" "ARPREF=${ARPREF}" "ARSUFF=${ARSUFF}" \ - "INCL=../${INCL}" "PORTINCL=../${PORTINCL}" \ + "INCL=../${INCL}" "PORTINCL=../${PORTINCL}" "EXE=${EXE}" \ "LIBBIND=../${LIBBIND}" "LIBPORT=../${LIBPORT}" \ "INSTALL=${INSTALL}" "CPPFLAGS=${CPPFLAGS}" "TOP=../${TOP}" \ - "VER=${VER}" "STRIP=${STRIP}" "PS=${PS}" + "VER=${VER}" "STRIP=${STRIP}" "PS=${PS}" "INSTALL_LIB=${INSTALL_LIB}" \ + "INSTALL_EXEC=${INSTALL_EXEC}" "BOUNDS=${BOUNDS}" CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL} -SUBDIRS = addr nslookup dig dnsquery host named named-xfer ndc nsupdate +SUBDIRS = addr nslookup dig dnsquery host named named-xfer ndc nsupdate \ + mkservdb irpd dnskeygen named-bootconf all: ${SUBDIRS} diff --git a/contrib/bind/bin/addr/Makefile b/contrib/bind/bin/addr/Makefile index 0e8b2ec..18dd281 100644 --- a/contrib/bind/bin/addr/Makefile +++ b/contrib/bind/bin/addr/Makefile @@ -1,4 +1,4 @@ -## Copyright (c) 1996 by Internet Software Consortium +## 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 @@ -13,7 +13,7 @@ ## ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ## SOFTWARE. -# $Id: Makefile,v 8.19 1997/06/19 03:22:06 halley Exp $ +# $Id: Makefile,v 8.25 1999/08/08 17:51:00 vixie Exp $ DESTDIR= CC= cc @@ -29,15 +29,17 @@ PORTINCL = ${TOP}/port/${SYSTYPE}/include LIBBIND = ${TOP}/lib/libbind.a A=a O=o +EXE= LEX = lex -I SYSLIBS = -ll -lutil -PIDDIR = /var/run DESTBIN = /usr/local/bin DESTSBIN = /usr/local/sbin DESTEXEC = /usr/local/libexec DESTMAN = /usr/share/man DESTHELP= /usr/share/misc STRIP=-s +INSTALL_EXEC= +INSTALL_LIB=-o bin -g bin LDFLAGS= CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL} @@ -46,26 +48,29 @@ PROG= addr SRCS= ${PROG}.c OBJS= ${PROG}.${O} -all: ${PROG} +all: ${PROG}${EXE} -${PROG}: ${OBJS} ${LIBBIND} Makefile - ${CC} ${CDEBUG} ${LDFLAGS} -o ${PROG} ${OBJS} \ +${PROG}${EXE}: ${OBJS} ${LIBBIND} Makefile + ${CC} ${CDEBUG} ${LDFLAGS} ${BOUNDS} -o ${PROG}${EXE} ${OBJS} \ ${LIBBIND} ${SYSLIBS} +.c.${O}: + ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c + distclean: clean clean: FRC - rm -f ${PROG} ${OBJS} core .depend + rm -f ${PROG}${EXE} ${OBJS} core .depend rm -f *.BAK *.CKP *~ *.orig depend: ${SRCS} - mkdep -p ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS} + mkdep ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS} ${DESTDIR}${DESTBIN}: mkdir -p ${DESTDIR}${DESTBIN} -install: ${DESTDIR}${DESTBIN} ${PROG} - ${INSTALL} ${STRIP} -c -m 755 ${PROG} ${DESTDIR}${DESTBIN}/${PROG} +install: ${DESTDIR}${DESTBIN} ${PROG}${EXE} + ${INSTALL} ${STRIP} -c ${INSTALL_EXEC} -m 755 ${PROG}${EXE} ${DESTDIR}${DESTBIN}/${PROG}${EXE} links: FRC @set -e; ln -s SRC/*.[ch] . diff --git a/contrib/bind/bin/addr/addr.c b/contrib/bind/bin/addr/addr.c index 535033a..a693391 100644 --- a/contrib/bind/bin/addr/addr.c +++ b/contrib/bind/bin/addr/addr.c @@ -1,9 +1,9 @@ #if !defined(lint) && !defined(SABER) -static char rcsid[] = "$Id: addr.c,v 8.5 1997/04/25 00:00:29 vixie Exp $"; +static const char rcsid[] = "$Id: addr.c,v 8.8 1999/10/13 16:38:55 vixie Exp $"; #endif /* not lint */ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -129,11 +129,12 @@ main(argc, argv) char *argv[]; { u_char addr[BIGGEST_ADDRESS]; - int optchr, af, len; + int optchr, af, len, some; prog = argv[0]; af = AF_INET; len = INADDRSZ; + some = 0; while ((optchr = getopt(argc, argv, "46n:p:")) != -1) { switch (optchr) { case '4': @@ -152,6 +153,7 @@ main(argc, argv) /* NOTREACHED */ } display(optarg, af, addr, len); + some++; break; case 'p': if (inet_pton(af, optarg, addr) <= 0) { @@ -161,12 +163,15 @@ main(argc, argv) /* NOTREACHED */ } display(optarg, af, addr, len); + some++; break; default: usage(); /* NOTREACHED */ } } + if (!some) + usage(); exit(0); /* NOTREACHED */ } diff --git a/contrib/bind/bin/dig/Makefile b/contrib/bind/bin/dig/Makefile index dbbc00f..250df96 100644 --- a/contrib/bind/bin/dig/Makefile +++ b/contrib/bind/bin/dig/Makefile @@ -1,4 +1,4 @@ -## Copyright (c) 1996 by Internet Software Consortium +## 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 @@ -13,7 +13,7 @@ ## ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ## SOFTWARE. -# $Id: Makefile,v 8.19 1997/06/19 03:22:07 halley Exp $ +# $Id: Makefile,v 8.25 1999/08/08 17:51:01 vixie Exp $ DESTDIR= CC= cc @@ -29,15 +29,17 @@ PORTINCL = ${TOP}/port/${SYSTYPE}/include LIBBIND = ${TOP}/lib/libbind.a A=a O=o +EXE= LEX = lex -I SYSLIBS = -ll -lutil -PIDDIR = /var/run DESTBIN = /usr/local/bin DESTSBIN = /usr/local/sbin DESTEXEC = /usr/local/libexec DESTMAN = /usr/share/man DESTHELP= /usr/share/misc STRIP=-s +INSTALL_EXEC= +INSTALL_LIB=-o bin -g bin LDFLAGS= CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL} @@ -50,26 +52,29 @@ PROG= dig SRCS= ${PROG}.c OBJS= ${PROG}.${O} -all: ${PROG} +all: ${PROG}${EXE} -${PROG}: ${OBJS} ${NSLOOKUP_OBJS} ${LIBBIND} Makefile - ${CC} ${CDEBUG} ${LDFLAGS} -o ${PROG} ${OBJS} ${NSLOOKUP_OBJS} \ - ${LIBBIND} ${SYSLIBS} +${PROG}${EXE}: ${OBJS} ${NSLOOKUP_OBJS} ${LIBBIND} Makefile + ${CC} ${CDEBUG} ${LDFLAGS} ${BOUNDS} -o ${PROG}${EXE} ${OBJS} \ + ${NSLOOKUP_OBJS} ${LIBBIND} ${SYSLIBS} + +.c.${O}: + ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c distclean: clean clean: FRC - rm -f ${PROG} ${OBJS} core .depend + rm -f ${PROG}${EXE} ${OBJS} core .depend rm -f *.BAK *.CKP *~ *.orig depend: ${SRCS} - mkdep -p ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS} + mkdep ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS} ${DESTDIR}${DESTBIN}: mkdir -p ${DESTDIR}${DESTBIN} -install: ${DESTDIR}${DESTBIN} ${PROG} - ${INSTALL} ${STRIP} -c -m 755 ${PROG} ${DESTDIR}${DESTBIN}/${PROG} +install: ${DESTDIR}${DESTBIN} ${PROG}${EXE} + ${INSTALL} ${STRIP} -c ${INSTALL_EXEC} -m 755 ${PROG}${EXE} ${DESTDIR}${DESTBIN}/${PROG}${EXE} links: FRC @set -e; ln -s SRC/*.[ch] . diff --git a/contrib/bind/bin/dig/dig.c b/contrib/bind/bin/dig/dig.c index 7db8ba0..4e75c13 100644 --- a/contrib/bind/bin/dig/dig.c +++ b/contrib/bind/bin/dig/dig.c @@ -1,5 +1,5 @@ #ifndef lint -static char rcsid[] = "$Id: dig.c,v 8.19 1998/03/19 19:30:18 halley Exp $"; +static const char rcsid[] = "$Id: dig.c,v 8.36 1999/11/05 05:05:14 vixie Exp $"; #endif /* @@ -56,7 +56,7 @@ static char rcsid[] = "$Id: dig.c,v 8.19 1998/03/19 19:30:18 halley Exp $"; */ /* - * Copyright (c) 1996 by Internet Software Consortium + * 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 @@ -159,11 +159,14 @@ static char rcsid[] = "$Id: dig.c,v 8.19 1998/03/19 19:30:18 halley Exp $"; #include <sys/stat.h> #include <sys/socket.h> #include <sys/time.h> +#include <sys/wait.h> #include <netinet/in.h> #include <arpa/inet.h> #include <arpa/nameser.h> +#include <isc/dst.h> + #include <ctype.h> #include <errno.h> #include <fcntl.h> @@ -179,12 +182,10 @@ static char rcsid[] = "$Id: dig.c,v 8.19 1998/03/19 19:30:18 halley Exp $"; #include "../nslookup/res.h" -extern char *_res_resultcodes[]; /* res_debug.c */ - /* Global. */ -#define VERSION 81 -#define VSTRING "8.1" +#define VERSION 82 +#define VSTRING "8.2" #define PRF_DEF 0x2ff9 #define PRF_MIN 0xA930 @@ -194,20 +195,21 @@ extern char *_res_resultcodes[]; /* res_debug.c */ #define MAXHOSTNAMELEN 256 #endif -int eecode = 0; - -FILE *qfp; -int sockFD; - #define SAVEENV "DiG.env" #define DIG_MAXARGS 30 +static int eecode = 0; +static FILE * qfp; +static int sockFD; static char *defsrv, *srvmsg; static char defbuf[40] = "default -- "; static char srvbuf[60]; static char myhostname[MAXHOSTNAMELEN]; +static struct sockaddr_in myaddress; +static u_int32_t ixfr_serial; /* stuff for nslookup modules */ +struct __res_state res; FILE *filePtr; jmp_buf env; HostInfo *defaultPtr = NULL; @@ -228,7 +230,8 @@ static void Usage(void); static int SetOption(const char *); static void res_re_init(void); static int xstrtonum(char *); -static int printZone(const char *, const struct sockaddr_in *); +static int printZone(ns_type, const char *, + const struct sockaddr_in *, ns_tsig_key *); static int print_axfr(FILE *output, const u_char *msg, size_t msglen); static struct timeval difftv(struct timeval, struct timeval); @@ -246,15 +249,17 @@ main(int argc, char **argv) { HEADER header_; u_char packet_[PACKETSZ]; } packet_; -#define packet (packet_.packet_) - u_char answer[8*1024]; +#define header (packet_.header_) +#define packet (packet_.packet_) + u_char answer[64*1024]; int n; char doping[90]; char pingstr[50]; char *afile; char *addrc, *addrend, *addrbegin; - struct timeval exectime, tv1, tv2, start_time, end_time, query_time; + time_t exectime; + struct timeval tv1, tv2, start_time, end_time, query_time; char *srv; int anyflag = 0; @@ -262,7 +267,7 @@ main(int argc, char **argv) { int tmp; int qtypeSet; int addrflag = 0; - int zone = 0; + ns_type xfr = ns_t_invalid; int bytes_out, bytes_in; char cmd[256]; @@ -279,13 +284,22 @@ main(int argc, char **argv) { struct __res_state res_x, res_t; char *pp; - res_init(); - _res.pfcode = PRF_DEF; + ns_tsig_key key; + char *keyfile = NULL, *keyname = NULL; + + res_ninit(&res); + res.pfcode = PRF_DEF; qtypeSet = 0; memset(domain, 0, sizeof domain); gethostname(myhostname, (sizeof myhostname)); - defsrv = strcat(defbuf, inet_ntoa(_res.nsaddr.sin_addr)); - res_x = _res; +#ifdef HAVE_SA_LEN + myaddress.sin_len = sizeof(struct sockaddr_in); +#endif + myaddress.sin_family = AF_INET; + myaddress.sin_addr.s_addr = INADDR_ANY; + myaddress.sin_port = 0; /*INPORT_ANY*/; + defsrv = strcat(defbuf, inet_ntoa(res.nsaddr.sin_addr)); + res_x = res; /* * If LOCALDEF in environment, should point to file @@ -298,7 +312,7 @@ main(int argc, char **argv) { ((fp = open(SAVEENV, O_RDONLY)) > 0)) { read(fp, (char *)&res_x, (sizeof res_x)); close(fp); - _res = res_x; + res = res_x; } /* * Check for batch-mode DiG; also pre-scan for 'help'. @@ -332,7 +346,7 @@ main(int argc, char **argv) { vtmp++; } - _res.id = 1; + res.id = 1; gettimeofday(&tv1, NULL); /* @@ -352,7 +366,7 @@ main(int argc, char **argv) { */ if (sticky) { printf(";; (using sticky settings)\n"); - _res = res_x; + res = res_x; } /* @@ -363,7 +377,7 @@ main(int argc, char **argv) { /* defaults */ queryType = ns_t_ns; queryClass = ns_c_in; - zone = 0; + xfr = ns_t_invalid; *pingstr = 0; srv = NULL; @@ -387,7 +401,10 @@ main(int argc, char **argv) { SetOption(*argv+1); continue; } - + if (**argv == '=') { + ixfr_serial = strtoul(*argv+1, NULL, 0); + continue; + } if (strncmp(*argv, "-nost", 5) == 0) { sticky = 0; continue; @@ -460,15 +477,57 @@ main(int argc, char **argv) { strcat(domain, addrc); strcat(domain, ".in-addr.arpa."); break; - case 'p': port = htons(atoi(*++argv)); break; + case 'p': + if (argv[0][2] != '\0') + port = ntohs(atoi(argv[0]+2)); + else + port = htons(atoi(*++argv)); + break; case 'P': if (argv[0][2] != '\0') - strcpy(pingstr,&argv[0][2]); + strcpy(pingstr, argv[0]+2); else - strcpy(pingstr,"ping -s"); + strcpy(pingstr, "ping -s"); break; case 'n': - _res.ndots = atoi(&argv[0][2]); + if (argv[0][2] != '\0') + res.ndots = atoi(argv[0]+2); + else + res.ndots = atoi(*++argv); + break; + case 'b': { + char *a, *p; + + if (argv[0][2] != '\0') + a = argv[0]+2; + else + a = *++argv; + if ((p = strchr(a, ':')) != NULL) { + *p++ = '\0'; + myaddress.sin_port = + ntohs(atoi(p)); + } + if (!inet_aton(a,&myaddress.sin_addr)){ + fprintf(stderr, + ";; bad -b addr\n"); + exit(1); + } + } + case 'k': + /* -k keydir:keyname */ + + if (argv[0][2] != '\0') + keyfile = argv[0]+2; + else + keyfile = *++argv; + + keyname = strchr(keyfile, ':'); + if (keyname == NULL) { + fprintf(stderr, + "key option argument should be keydir:keyname\n"); + exit(1); + } + *keyname++='\0'; break; } /* switch - */ continue; @@ -479,9 +538,12 @@ main(int argc, char **argv) { queryClass = C_ANY; continue; } - if (T_AXFR == tmp) { - _res.pfcode = PRF_ZONE; - zone++; + if (ns_t_xfr_p(tmp) && + (tmp == ns_t_axfr || + (res.options & RES_USEVC) != 0) + ) { + res.pfcode = PRF_ZONE; + xfr = (ns_type)tmp; } else { queryType = tmp; qtypeSet++; @@ -495,16 +557,127 @@ main(int argc, char **argv) { } } /* while argv remains */ - if (_res.pfcode & 0x80000) + /* process key options */ + if (keyfile) { +#ifdef PARSE_KEYFILE + int i, n1; + char buf[BUFSIZ], *p; + FILE *fp = NULL; + int file_major, file_minor, alg; + + fp = fopen(keyfile, "r"); + if (fp == NULL) { + perror(keyfile); + exit(1); + } + /* Now read the header info from the file. */ + i = fread(buf, 1, BUFSIZ, fp); + if (i < 5) { + fclose(fp); + exit(1); + } + fclose(fp); + + p = buf; + + n=strlen(p); /* get length of strings */ + n1=strlen("Private-key-format: v"); + if (n1 > n || + strncmp(buf, "Private-key-format: v", n1)) { + fprintf(stderr, "Invalid key file format\n"); + exit(1); /* not a match */ + } + p+=n1; /* advance pointer */ + sscanf((char *)p, "%d.%d", &file_major, &file_minor); + /* should do some error checking with these someday */ + while (*p++!='\n'); /* skip to end of line */ + + n=strlen(p); /* get length of strings */ + n1=strlen("Algorithm: "); + if (n1 > n || strncmp(p, "Algorithm: ", n1)) { + fprintf(stderr, "Invalid key file format\n"); + exit(1); /* not a match */ + } + p+=n1; /* advance pointer */ + if (sscanf((char *)p, "%d", &alg)!=1) { + fprintf(stderr, "Invalid key file format\n"); + exit(1); + } + while (*p++!='\n'); /* skip to end of line */ + + n=strlen(p); /* get length of strings */ + n1=strlen("Key: "); + if (n1 > n || strncmp(p, "Key: ", n1)) { + fprintf(stderr, "Invalid key file format\n"); + exit(1); /* not a match */ + } + p+=n1; /* advance pointer */ + pp=p; + while (*pp++!='\n'); /* skip to end of line, + * terminate it */ + *--pp='\0'; + + key.data=malloc(1024*sizeof(char)); + key.len=b64_pton(p, key.data, 1024); + + strcpy(key.name, keyname); + strcpy(key.alg, "HMAC-MD5.SIG-ALG.REG.INT"); +#else + /* use the dst* routines to parse the key files + * + * This requires that both the .key and the .private + * files exist in your cwd, so the keyfile parmeter + * here is assumed to be a path in which the + * K*.{key,private} files exist. + */ + DST_KEY *dst_key; + char cwd[PATH_MAX+1]; + + if (getcwd(cwd, PATH_MAX)==NULL) { + perror("unable to get current directory"); + exit(1); + } + if (chdir(keyfile)<0) { + fprintf(stderr, + "unable to chdir to %s: %s\n", keyfile, + strerror(errno)); + exit(1); + } + + dst_init(); + dst_key = dst_read_key(keyname, + 0 /* not used for priv keys */, + KEY_HMAC_MD5, DST_PRIVATE); + if (!dst_key) { + fprintf(stderr, + "dst_read_key: error reading key\n"); + exit(1); + } + key.data=malloc(1024*sizeof(char)); + dst_key_to_buffer(dst_key, key.data, 1024); + key.len=dst_key->dk_key_size; + + strcpy(key.name, keyname); + strcpy(key.alg, "HMAC-MD5.SIG-ALG.REG.INT"); + + if (chdir(cwd)<0) { + fprintf(stderr, "unable to chdir to %s: %s\n", + cwd, strerror(errno)); + exit(1); + } +#endif + } + + if (res.pfcode & 0x80000) printf("; pfcode: %08lx, options: %08lx\n", - _res.pfcode, _res.options); + res.pfcode, res.options); /* * Current env. (after this parse) is to become the * new "working" environmnet. Used in conj. with sticky. */ if (envset) { - res_x = _res; + res_x = res; envset = 0; } @@ -523,13 +696,13 @@ main(int argc, char **argv) { ((fp = open(SAVEENV, O_WRONLY|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE)) > 0)) { - write(fp, (char *)&_res, (sizeof _res)); + write(fp, (char *)&res, (sizeof res)); close(fp); } envsave = 0; } - if (_res.pfcode & RES_PRF_CMD) + if (res.pfcode & RES_PRF_CMD) printf("%s\n", cmd); addrflag = anyflag = 0; @@ -549,16 +722,16 @@ main(int argc, char **argv) { struct in_addr addr; if (inet_aton(srv, &addr)) { - _res.nscount = 1; - _res.nsaddr.sin_addr = addr; + res.nscount = 1; + res.nsaddr.sin_addr = addr; srvmsg = strcat(srvbuf, srv); } else { - res_t = _res; - _res.pfcode = 0; - _res.options = RES_DEFAULT; - res_init(); + res_t = res; + res_ninit(&res); + res.pfcode = 0; + res.options = RES_DEFAULT; hp = gethostbyname(srv); - _res = res_t; + res = res_t; if (hp == NULL || hp->h_addr_list == NULL || *hp->h_addr_list == NULL) { @@ -572,54 +745,57 @@ main(int argc, char **argv) { } else { u_int32_t **addr; - _res.nscount = 0; + res.nscount = 0; for (addr = (u_int32_t**)hp->h_addr_list; - *addr && (_res.nscount < MAXNS); + *addr && (res.nscount < MAXNS); addr++) { - _res.nsaddr_list[ - _res.nscount++ + res.nsaddr_list[ + res.nscount++ ].sin_addr.s_addr = **addr; } srvmsg = strcat(srvbuf,srv); strcat(srvbuf, " "); strcat(srvmsg, - inet_ntoa(_res.nsaddr.sin_addr) - ); + inet_ntoa(res.nsaddr.sin_addr)); } } printf("; (%d server%s found)\n", - _res.nscount, (_res.nscount==1)?"":"s"); - _res.id += _res.retry; + res.nscount, (res.nscount==1)?"":"s"); + res.id += res.retry; } { int i; - for (i = 0; i < _res.nscount; i++) { - _res.nsaddr_list[i].sin_family = AF_INET; - _res.nsaddr_list[i].sin_port = port; + for (i = 0; i < res.nscount; i++) { + res.nsaddr_list[i].sin_family = AF_INET; + res.nsaddr_list[i].sin_port = port; } - _res.id += _res.retry; + res.id += res.retry; } - if (zone) { + if (ns_t_xfr_p(xfr)) { int i; - for (i = 0; i < _res.nscount; i++) { - int x = printZone(domain, - &_res.nsaddr_list[i]); - if (_res.pfcode & RES_PRF_STATS) { - struct timeval exectime; - time_t t; + for (i = 0; i < res.nscount; i++) { + int x; + if (keyfile) + x = printZone(xfr, domain, + &res.nsaddr_list[i], + &key); + else + x = printZone(xfr, domain, + &res.nsaddr_list[i], + NULL); + if (res.pfcode & RES_PRF_STATS) { + exectime = time(NULL); printf(";; FROM: %s to SERVER: %s\n", myhostname, - inet_ntoa(_res.nsaddr_list[i] + inet_ntoa(res.nsaddr_list[i] .sin_addr)); - gettimeofday(&exectime, NULL); - t = (time_t)exectime.tv_sec; - printf(";; WHEN: %s", ctime(&t)); + printf(";; WHEN: %s", ctime(&exectime)); } if (!x) break; /* success */ @@ -633,25 +809,54 @@ main(int argc, char **argv) { qtypeSet++; } - bytes_out = n = res_mkquery(QUERY, domain, - queryClass, queryType, - NULL, 0, NULL, - packet, sizeof packet); + bytes_out = n = res_nmkquery(&res, QUERY, domain, + queryClass, queryType, + NULL, 0, NULL, + packet, sizeof packet); if (n < 0) { fflush(stderr); - printf(";; res_mkquery: buffer too small\n\n"); + printf(";; res_nmkquery: buffer too small\n\n"); continue; } + if (queryType == T_IXFR) { + HEADER *hp = (HEADER *) packet; + u_char *cpp = packet + bytes_out; + + hp->nscount = htons(1+ntohs(hp->nscount)); + n = dn_comp(domain, cpp, + (sizeof packet) - (cpp - packet), + NULL, NULL); + cpp += n; + PUTSHORT(T_SOA, cpp); /* type */ + PUTSHORT(C_IN, cpp); /* class */ + PUTLONG(0, cpp); /* ttl */ + PUTSHORT(22, cpp); /* dlen */ + *cpp++ = 0; /* mname */ + *cpp++ = 0; /* rname */ + PUTLONG(ixfr_serial, cpp); + PUTLONG(0xDEAD, cpp); /* Refresh */ + PUTLONG(0xBEEF, cpp); /* Retry */ + PUTLONG(0xABCD, cpp); /* Expire */ + PUTLONG(0x1776, cpp); /* Min TTL */ + bytes_out = n = cpp - packet; + }; + eecode = 0; - if (_res.pfcode & RES_PRF_HEAD1) - __fp_resstat(NULL, stdout); + if (res.pfcode & RES_PRF_HEAD1) + fp_resstat(&res, stdout); (void) gettimeofday(&start_time, NULL); - if ((bytes_in = n = res_send(packet, n, - answer, sizeof answer)) < 0) { + if (keyfile) + n = res_nsendsigned(&res, packet, n, &key, answer, sizeof answer); + else + n = res_nsend(&res, packet, n, answer, sizeof answer); + if ((bytes_in = n) < 0) { fflush(stdout); n = 0 - n; msg[0]=0; - strcat(msg,";; res_send to server "); + if (keyfile) + strcat(msg,";; res_nsendsigned to server "); + else + strcat(msg,";; res_nsend to server "); strcat(msg,srvmsg); perror(msg); fflush(stderr); @@ -665,18 +870,17 @@ main(int argc, char **argv) { } (void) gettimeofday(&end_time, NULL); - if (_res.pfcode & RES_PRF_STATS) { + if (res.pfcode & RES_PRF_STATS) { time_t t; query_time = difftv(start_time, end_time); printf(";; Total query time: "); prnttime(query_time); putchar('\n'); + exectime = time(NULL); printf(";; FROM: %s to SERVER: %s\n", myhostname, srvmsg); - gettimeofday(&exectime,NULL); - t = (time_t)exectime.tv_sec; - printf(";; WHEN: %s", ctime(&t)); + printf(";; WHEN: %s", ctime(&exectime)); printf(";; MSG SIZE sent: %d rcvd: %d\n", bytes_out, bytes_in); } @@ -723,9 +927,11 @@ where: server,\n\ -f file (batch mode input file name)\n\ -T time (batch mode time delay, per query)\n\ -p port (nameserver is on this port) [53]\n\ - -Pping-string (see man page)\n\ + -b addr[:port] (bind to this tcp address) [*]\n\ + -P[ping-string] (see man page)\n\ -t query-type (synonym for q-type)\n\ -c query-class (synonym for q-class)\n\ + -k keydir:keyname (sign the query with this TSIG key)\n\ -envsav,-envset (see man page)\n\ -[no]stick (see man page)\n\ ", stderr); @@ -739,6 +945,8 @@ where: server,\n\ ", stderr); fputs("\ notes: defname and search don't work; use fully-qualified names.\n\ + this is DiG version " VSTRING "\n\ + $Id: dig.c,v 8.36 1999/11/05 05:05:14 vixie Exp $\n\ ", stderr); } @@ -747,128 +955,139 @@ SetOption(const char *string) { char option[NAME_LEN], type[NAME_LEN], *ptr; int i; - i = sscanf(string, " %s", option); - if (i != 1) { - fprintf(stderr, ";*** Invalid option: %s\n", option); - return (ERROR); + i = pickString(string, option, sizeof option); + if (i == 0) { + fprintf(stderr, ";*** Invalid option: %s\n", string); + + /* this is ugly, but fixing the caller to behave + properly with an error return value would require a major + cleanup. */ + exit(9); } if (strncmp(option, "aa", 2) == 0) { /* aaonly */ - _res.options |= RES_AAONLY; + res.options |= RES_AAONLY; } else if (strncmp(option, "noaa", 4) == 0) { - _res.options &= ~RES_AAONLY; + res.options &= ~RES_AAONLY; } else if (strncmp(option, "deb", 3) == 0) { /* debug */ - _res.options |= RES_DEBUG; + res.options |= RES_DEBUG; } else if (strncmp(option, "nodeb", 5) == 0) { - _res.options &= ~(RES_DEBUG | RES_DEBUG2); + res.options &= ~(RES_DEBUG | RES_DEBUG2); } else if (strncmp(option, "ko", 2) == 0) { /* keepopen */ - _res.options |= (RES_STAYOPEN | RES_USEVC); + res.options |= (RES_STAYOPEN | RES_USEVC); } else if (strncmp(option, "noko", 4) == 0) { - _res.options &= ~RES_STAYOPEN; + res.options &= ~RES_STAYOPEN; } else if (strncmp(option, "d2", 2) == 0) { /* d2 (more debug) */ - _res.options |= (RES_DEBUG | RES_DEBUG2); + res.options |= (RES_DEBUG | RES_DEBUG2); } else if (strncmp(option, "nod2", 4) == 0) { - _res.options &= ~RES_DEBUG2; + res.options &= ~RES_DEBUG2; } else if (strncmp(option, "def", 3) == 0) { /* defname */ - _res.options |= RES_DEFNAMES; + res.options |= RES_DEFNAMES; } else if (strncmp(option, "nodef", 5) == 0) { - _res.options &= ~RES_DEFNAMES; + res.options &= ~RES_DEFNAMES; } else if (strncmp(option, "sea", 3) == 0) { /* search list */ - _res.options |= RES_DNSRCH; + res.options |= RES_DNSRCH; } else if (strncmp(option, "nosea", 5) == 0) { - _res.options &= ~RES_DNSRCH; + res.options &= ~RES_DNSRCH; } else if (strncmp(option, "do", 2) == 0) { /* domain */ ptr = strchr(option, '='); - if (ptr != NULL) - sscanf(++ptr, "%s", _res.defdname); + if (ptr != NULL) { + i = pickString(++ptr, res.defdname, sizeof res.defdname); + if (i == 0) { /* value's too long or non-existant. This actually + shouldn't happen due to pickString() + above */ + fprintf(stderr, "*** Invalid domain: %s\n", ptr) ; + exit(9); /* see comment at previous call to exit()*/ + } + } } else if (strncmp(option, "ti", 2) == 0) { /* timeout */ ptr = strchr(option, '='); if (ptr != NULL) - sscanf(++ptr, "%d", &_res.retrans); + sscanf(++ptr, "%d", &res.retrans); } else if (strncmp(option, "ret", 3) == 0) { /* retry */ ptr = strchr(option, '='); if (ptr != NULL) - sscanf(++ptr, "%d", &_res.retry); + sscanf(++ptr, "%d", &res.retry); } else if (strncmp(option, "i", 1) == 0) { /* ignore */ - _res.options |= RES_IGNTC; + res.options |= RES_IGNTC; } else if (strncmp(option, "noi", 3) == 0) { - _res.options &= ~RES_IGNTC; + res.options &= ~RES_IGNTC; } else if (strncmp(option, "pr", 2) == 0) { /* primary */ - _res.options |= RES_PRIMARY; + res.options |= RES_PRIMARY; } else if (strncmp(option, "nop", 3) == 0) { - _res.options &= ~RES_PRIMARY; + res.options &= ~RES_PRIMARY; } else if (strncmp(option, "rec", 3) == 0) { /* recurse */ - _res.options |= RES_RECURSE; + res.options |= RES_RECURSE; } else if (strncmp(option, "norec", 5) == 0) { - _res.options &= ~RES_RECURSE; + res.options &= ~RES_RECURSE; } else if (strncmp(option, "v", 1) == 0) { /* vc */ - _res.options |= RES_USEVC; + res.options |= RES_USEVC; } else if (strncmp(option, "nov", 3) == 0) { - _res.options &= ~RES_USEVC; + res.options &= ~RES_USEVC; } else if (strncmp(option, "pfset", 5) == 0) { ptr = strchr(option, '='); if (ptr != NULL) - _res.pfcode = xstrtonum(++ptr); + res.pfcode = xstrtonum(++ptr); } else if (strncmp(option, "pfand", 5) == 0) { ptr = strchr(option, '='); if (ptr != NULL) - _res.pfcode = _res.pfcode & xstrtonum(++ptr); + res.pfcode = res.pfcode & xstrtonum(++ptr); } else if (strncmp(option, "pfor", 4) == 0) { ptr = strchr(option, '='); if (ptr != NULL) - _res.pfcode |= xstrtonum(++ptr); + res.pfcode |= xstrtonum(++ptr); } else if (strncmp(option, "pfmin", 5) == 0) { - _res.pfcode = PRF_MIN; + res.pfcode = PRF_MIN; } else if (strncmp(option, "pfdef", 5) == 0) { - _res.pfcode = PRF_DEF; + res.pfcode = PRF_DEF; } else if (strncmp(option, "an", 2) == 0) { /* answer section */ - _res.pfcode |= RES_PRF_ANS; + res.pfcode |= RES_PRF_ANS; } else if (strncmp(option, "noan", 4) == 0) { - _res.pfcode &= ~RES_PRF_ANS; + res.pfcode &= ~RES_PRF_ANS; } else if (strncmp(option, "qu", 2) == 0) { /* question section */ - _res.pfcode |= RES_PRF_QUES; + res.pfcode |= RES_PRF_QUES; } else if (strncmp(option, "noqu", 4) == 0) { - _res.pfcode &= ~RES_PRF_QUES; + res.pfcode &= ~RES_PRF_QUES; } else if (strncmp(option, "au", 2) == 0) { /* authority section */ - _res.pfcode |= RES_PRF_AUTH; + res.pfcode |= RES_PRF_AUTH; } else if (strncmp(option, "noau", 4) == 0) { - _res.pfcode &= ~RES_PRF_AUTH; + res.pfcode &= ~RES_PRF_AUTH; } else if (strncmp(option, "ad", 2) == 0) { /* addition section */ - _res.pfcode |= RES_PRF_ADD; + res.pfcode |= RES_PRF_ADD; } else if (strncmp(option, "noad", 4) == 0) { - _res.pfcode &= ~RES_PRF_ADD; + res.pfcode &= ~RES_PRF_ADD; } else if (strncmp(option, "tt", 2) == 0) { /* TTL & ID */ - _res.pfcode |= RES_PRF_TTLID; + res.pfcode |= RES_PRF_TTLID; } else if (strncmp(option, "nott", 4) == 0) { - _res.pfcode &= ~RES_PRF_TTLID; + res.pfcode &= ~RES_PRF_TTLID; } else if (strncmp(option, "he", 2) == 0) { /* head flags stats */ - _res.pfcode |= RES_PRF_HEAD2; + res.pfcode |= RES_PRF_HEAD2; } else if (strncmp(option, "nohe", 4) == 0) { - _res.pfcode &= ~RES_PRF_HEAD2; + res.pfcode &= ~RES_PRF_HEAD2; } else if (strncmp(option, "H", 1) == 0) { /* header all */ - _res.pfcode |= RES_PRF_HEADX; + res.pfcode |= RES_PRF_HEADX; } else if (strncmp(option, "noH", 3) == 0) { - _res.pfcode &= ~(RES_PRF_HEADX); + res.pfcode &= ~(RES_PRF_HEADX); } else if (strncmp(option, "qr", 2) == 0) { /* query */ - _res.pfcode |= RES_PRF_QUERY; + res.pfcode |= RES_PRF_QUERY; } else if (strncmp(option, "noqr", 4) == 0) { - _res.pfcode &= ~RES_PRF_QUERY; + res.pfcode &= ~RES_PRF_QUERY; } else if (strncmp(option, "rep", 3) == 0) { /* reply */ - _res.pfcode |= RES_PRF_REPLY; + res.pfcode |= RES_PRF_REPLY; } else if (strncmp(option, "norep", 5) == 0) { - _res.pfcode &= ~RES_PRF_REPLY; + res.pfcode &= ~RES_PRF_REPLY; } else if (strncmp(option, "cm", 2) == 0) { /* command line */ - _res.pfcode |= RES_PRF_CMD; + res.pfcode |= RES_PRF_CMD; } else if (strncmp(option, "nocm", 4) == 0) { - _res.pfcode &= ~RES_PRF_CMD; + res.pfcode &= ~RES_PRF_CMD; } else if (strncmp(option, "cl", 2) == 0) { /* class mnemonic */ - _res.pfcode |= RES_PRF_CLASS; + res.pfcode |= RES_PRF_CLASS; } else if (strncmp(option, "nocl", 4) == 0) { - _res.pfcode &= ~RES_PRF_CLASS; + res.pfcode &= ~RES_PRF_CLASS; } else if (strncmp(option, "st", 2) == 0) { /* stats*/ - _res.pfcode |= RES_PRF_STATS; + res.pfcode |= RES_PRF_STATS; } else if (strncmp(option, "nost", 4) == 0) { - _res.pfcode &= ~RES_PRF_STATS; + res.pfcode &= ~RES_PRF_STATS; } else { fprintf(stderr, "; *** Invalid option: %s\n", option); return (ERROR); @@ -881,22 +1100,22 @@ SetOption(const char *string) { * Force a reinitialization when the domain is changed. */ static void -res_re_init() -{ +res_re_init() { static char localdomain[] = "LOCALDOMAIN"; - long pfcode = _res.pfcode; - long ndots = _res.ndots; + u_long pfcode = res.pfcode, options = res.options; + unsigned ndots = res.ndots; char *buf; /* * This is ugly but putenv() is more portable than setenv(). */ - buf = malloc((sizeof localdomain) + strlen(_res.defdname) +10/*fuzz*/); - sprintf(buf, "%s=%s", localdomain, _res.defdname); + buf = malloc((sizeof localdomain) + strlen(res.defdname) +10/*fuzz*/); + sprintf(buf, "%s=%s", localdomain, res.defdname); putenv(buf); /* keeps the argument, so we won't free it */ - res_init(); - _res.pfcode = pfcode; - _res.ndots = ndots; + res_ninit(&res); + res.pfcode = pfcode; + res.options = options; + res.ndots = ndots; } /* @@ -947,7 +1166,9 @@ typedef union { } querybuf; static int -printZone(const char *zone, const struct sockaddr_in *sin) { +printZone(ns_type xfr, const char *zone, const struct sockaddr_in *sin, + ns_tsig_key *key) +{ static u_char *answer = NULL; static int answerLen = 0; @@ -960,19 +1181,91 @@ printZone(const char *zone, const struct sockaddr_in *sin) { char dname[2][NS_MAXDNAME], file[NAME_LEN]; enum { NO_ERRORS, ERR_READING_LEN, ERR_READING_MSG, ERR_PRINTING } error = NO_ERRORS; + pid_t zpid; + u_char *newmsg; + int newmsglen; + ns_tcp_tsig_state tsig_state; + int tsig_ret; + + switch (xfr) { + case ns_t_axfr: + case ns_t_zxfr: + break; + default: + fprintf(stderr, ";; %s - transfer type not supported\n", + p_type(xfr)); + return (ERROR); + } /* * Create a query packet for the requested zone name. */ - msglen = res_mkquery(ns_o_query, zone, queryClass, ns_t_axfr, NULL, - 0, 0, buf.qb2, sizeof buf); + msglen = res_nmkquery(&res, ns_o_query, zone, + queryClass, ns_t_axfr, NULL, + 0, 0, buf.qb2, sizeof buf); if (msglen < 0) { - if (_res.options & RES_DEBUG) - fprintf(stderr, ";; res_mkquery failed\n"); + if (res.options & RES_DEBUG) + fprintf(stderr, ";; res_nmkquery failed\n"); return (ERROR); } /* + * Sign the message if a key was sent + */ + if (key == NULL) { + newmsg = (u_char *)&buf; + newmsglen = msglen; + } else { + DST_KEY *dstkey; + int bufsize, siglen; + u_char sig[64]; + int ret; + + /* ns_sign() also calls dst_init(), but there is no harm + * doing it twice + */ + dst_init(); + + bufsize = msglen + 1024; + newmsg = (u_char *) malloc(bufsize); + if (newmsg == NULL) { + errno = ENOMEM; + return (-1); + } + memcpy(newmsg, (u_char *)&buf, msglen); + newmsglen = msglen; + + if (strcmp(key->alg, NS_TSIG_ALG_HMAC_MD5) != 0) + 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; + if (key) + free(newmsg); + return (-1); + } + + siglen = sizeof(sig); +/* newmsglen++; */ + ret = ns_sign(newmsg, &newmsglen, bufsize, NOERROR, dstkey, NULL, 0, + sig, &siglen, 0); + if (ret < 0) { + if (key) + free (newmsg); + if (ret == NS_TSIG_ERROR_NO_SPACE) + errno = EMSGSIZE; + else if (ret == -1) + errno = EINVAL; + return (ret); + } + ns_verify_tcp_init(dstkey, sig, siglen, &tsig_state); + } + + /* * Set up a virtual circuit to the server. */ if ((sockFD = socket(sin->sin_family, SOCK_STREAM, 0)) < 0) { @@ -981,29 +1274,86 @@ printZone(const char *zone, const struct sockaddr_in *sin) { perror(";; socket"); return (e); } + if (bind(sockFD, (struct sockaddr *)&myaddress, sizeof myaddress) < 0){ + int e = errno; + + fprintf(stderr, ";; bind(%s:%u): %s\n", + inet_ntoa(myaddress.sin_addr), + ntohs(myaddress.sin_port), + strerror(e)); + (void) close(sockFD); + sockFD = -1; + return (e); + } if (connect(sockFD, (struct sockaddr *)sin, sizeof *sin) < 0) { int e = errno; perror(";; connect"); (void) close(sockFD); sockFD = -1; - return e; + return (e); } /* * Send length & message for zone transfer */ - ns_put16(msglen, tmp); + ns_put16(newmsglen, tmp); if (write(sockFD, (char *)tmp, NS_INT16SZ) != NS_INT16SZ || - write(sockFD, (char *)&buf, msglen) != msglen) { + write(sockFD, (char *)newmsg, newmsglen) != newmsglen) { int e = errno; + if (key) + free (newmsg); perror(";; write"); (void) close(sockFD); sockFD = -1; return (e); } + /* + * If we're compressing, push a gzip into the pipeline. + */ + if (xfr == ns_t_zxfr) { + enum { rd = 0, wr = 1 }; + int z[2]; + + if (pipe(z) < 0) { + int e = errno; + if (key) + free (newmsg); + + perror(";; pipe"); + (void) close(sockFD); + sockFD = -1; + return (e); + } + zpid = vfork(); + if (zpid < 0) { + int e = errno; + if (key) + free (newmsg); + + perror(";; fork"); + (void) close(sockFD); + sockFD = -1; + return (e); + } else if (zpid == 0) { + /* Child. */ + (void) close(z[rd]); + (void) dup2(sockFD, STDIN_FILENO); + (void) close(sockFD); + (void) dup2(z[wr], STDOUT_FILENO); + (void) close(z[wr]); + execlp("gzip", "gzip", "-d", "-v", NULL); + perror(";; child: execlp(gunzip)"); + _exit(1); + } + /* Parent. */ + (void) close(z[wr]); + (void) dup2(z[rd], sockFD); + (void) close(z[rd]); + } + dname[0][0] = '\0'; for (done = 0; !done; (void)NULL) { /* @@ -1053,7 +1403,19 @@ printZone(const char *zone, const struct sockaddr_in *sin) { break; } - result = print_axfr(stdout, answer, cp - answer); + /* + * Verify the TSIG + */ + + if (key) { + tsig_ret = ns_verify_tcp(answer, &len, &tsig_state, 1); + if (tsig_ret == 0) + printf("; TSIG ok\n"); + else + printf("; TSIG invalid\n"); + } + + result = print_axfr(stdout, answer, len); if (result != 0) { error = ERR_PRINTING; break; @@ -1108,7 +1470,7 @@ printZone(const char *zone, const struct sockaddr_in *sin) { break; } if (type == T_SOA && soacnt++ && - !strcasecmp(dname[0], dname[1])) { + ns_samename(dname[0], dname[1]) == 1) { done++; break; } @@ -1122,6 +1484,35 @@ printZone(const char *zone, const struct sockaddr_in *sin) { (void) close(sockFD); sockFD = -1; + /* + * If we were uncompressing, reap the uncompressor. + */ + if (xfr == ns_t_zxfr) { + pid_t pid; + int status; + + pid = wait(&status); + if (pid < 0) { + int e = errno; + + perror(";; wait"); + return (e); + } + if (pid != zpid) { + fprintf(stderr, ";; wrong pid (%lu != %lu)\n", + (u_long)pid, (u_long)zpid); + return (ERROR); + } + printf(";; pid %lu: exit %d, signal %d, core %c\n", + pid, WEXITSTATUS(status), + WIFSIGNALED(status) ? WTERMSIG(status) : 0, + WCOREDUMP(status) ? 't' : 'f'); + } + + /* XXX This should probably happen sooner than here */ + if (key) + free (newmsg); + switch (error) { case NO_ERRORS: return (0); diff --git a/contrib/bind/bin/dnskeygen/Makefile b/contrib/bind/bin/dnskeygen/Makefile new file mode 100644 index 0000000..bea8511 --- /dev/null +++ b/contrib/bind/bin/dnskeygen/Makefile @@ -0,0 +1,85 @@ +## 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: Makefile,v 1.5 1999/08/08 17:51:01 vixie Exp $ + +DESTDIR= +CC= cc +SHELL= /bin/sh + +CDEBUG= -g + +#(net2 and its descendents) +SYSTYPE = bsdos +TOP = ../.. +INCL = ${TOP}/include +PORTINCL = ${TOP}/port/${SYSTYPE}/include +LIBBIND = ${TOP}/lib/libbind.a +A=a +O=o +LEX = lex -I +SYSLIBS = -ll -lutil +DESTBIN = /usr/local/bin +DESTSBIN = /usr/local/sbin +DESTEXEC = /usr/local/libexec +DESTMAN = /usr/share/man +DESTHELP= /usr/share/misc +AR= ar cru +INSTALL= install +STRIP=-s +INSTALL_EXEC= +INSTALL_LIB=-o bin -g bin + +PS=ps +LDFLAGS= +CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL} + +PROG= dnskeygen +SRCS= dnskeygen.c +OBJS= dnskeygen.${O} + +all: ${PROG}${EXE} + +${PROG}${EXE}: ${OBJS} ${LIBBIND} Makefile + ${CC} ${CDEBUG} ${LDFLAGS} ${BOUNDS} -o ${PROG}${EXE} ${OBJS} \ + ${LIBBIND} ${SYSLIBS} +.c.${O}: + ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c + +distclean: clean + +clean: FRC + rm -f ${PROG}${EXE} ${OBJS} core .depend + rm -f *.BAK *.CKP *~ *.orig + +depend: ${SRCS} + mkdep ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS} + +${DESTDIR}${DESTEXEC}: + mkdir -p ${DESTDIR}${DESTEXEC} + +install: ${DESTDIR}${DESTEXEC} ${PROG}${EXE} + ${INSTALL} ${STRIP} -c ${INSTALL_EXEC} -m 755 ${PROG}${EXE} ${DESTDIR}${DESTEXEC}/${PROG}${EXE} + +links: FRC + @set -e; ln -s SRC/*.[ch] . + +tags: FRC + ctags ${SRCS} *.h + +FRC: + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. diff --git a/contrib/bind/bin/dnskeygen/dnskeygen.c b/contrib/bind/bin/dnskeygen/dnskeygen.c new file mode 100644 index 0000000..c30eae7 --- /dev/null +++ b/contrib/bind/bin/dnskeygen/dnskeygen.c @@ -0,0 +1,318 @@ +#if !defined(lint) && !defined(SABER) +static const char rcsid[] = "$Id: dnskeygen.c,v 1.9 1999/10/13 16:38:59 vixie Exp $"; +#endif /* not lint */ + +/* + * Portions Copyright (c) 1995-1999 by TISLabs at 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. + */ + +#include "port_before.h" + +#include <stdio.h> +#include <ctype.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include "arpa/nameser.h" + +#include <isc/dst.h> + +#include "port_after.h" + +#define PRINT_SUPPORTED 2 + +static void usage(char *str, int full); + +static short dsa_sizes[] = {512, 576, 640, 704, 768, 832, 896, 960, 1024, 0}; +static char *prog; + +int +main(int argc, char **argv) { + DST_KEY *pubkey; + char *name=NULL; + int ch; + char str[128]; + int alg = 0; + int zone_key = 0, user_key = 0, end_key = 0, key_type = 0; + int size = -1, exp = 0; + int no_auth = 0, no_conf = 0; + int sign_val = 0, flags = 0, protocol = -1; + int i, err = 0, n; + extern char *optarg; + char array[1024]; + + dst_init(); + if ((prog = strrchr(argv[0],'/')) == NULL) + prog = strdup(argv[0]); + else + prog = strdup(++prog); + +/* process input arguments */ + while ((ch = getopt(argc, argv, "achiuzn:s:p:D:H:R:F"))!= -1) { + switch (ch) { + case 'a': + no_auth = NS_KEY_NO_AUTH; + break; + case 'c': + no_conf = NS_KEY_NO_CONF; + break; + case 'F': + exp=1; + break; + case 'n': + if (optarg) + name = strdup(optarg); + else + usage("-n not followed by name", 0); + i = strlen(name); + if (name[i-1] != '.') { + printf("** Adding dot to the name to make it" + " fully qualified domain name**\n"); + free(name); + name = malloc(i+2); + strcpy(name, optarg); + strcat(name, "."); + } + break; + case 'p': + if (optarg && isdigit(optarg[0])) + protocol = atoi(optarg); + else + usage("-p flag not followed by a number", 0); + break; + case 's': + /* Default: not signatory key */ + if (optarg && isdigit(optarg[0])) + sign_val = (int) atoi(optarg); + else + usage("-s flag requires a value",0); + break; + case 'h': + end_key = NS_KEY_NAME_ENTITY; + key_type++; + break; + case 'u' : + user_key = NS_KEY_NAME_USER; + key_type++; + break ; + case 'z': + zone_key = NS_KEY_NAME_ZONE; + key_type++; + break; + case 'H': + if (optarg && isdigit(optarg[0])) + size = (int) atoi(optarg); + else + usage("-H flag requires a size",0); + if (alg != 0) + usage("Only ONE alg can be specified", 1); + alg = KEY_HMAC_MD5; + if (!dst_check_algorithm(alg)) + usage("Algorithm HMAC-MD5 not available", + PRINT_SUPPORTED); + break; + case 'R': + if (optarg && isdigit(optarg[0])) + size = (int) atoi(optarg); + else + usage("-R flag requires a size",0); + if (alg != 0) + usage("Only ONE alg can be specified", 1); + alg = NS_ALG_MD5RSA; + if (!dst_check_algorithm(alg)) + usage("Algorithm RSA not available", + PRINT_SUPPORTED); + break; + case 'D': + if (optarg && isdigit(optarg[0])) + size = (int) atoi(optarg); + else + usage("-D flag requires a size", 0); + if (alg != 0) + usage("Only ONE alg can be specified", 1); + alg = NS_ALG_DSS; + if (dst_check_algorithm(alg) == 0) + usage("Algorithm DSS not available", + PRINT_SUPPORTED); + break; + default: + err++; + } /* switch */ + } /* while (getopt) */ + + /* + * Command line parsed make sure required parameters are present + */ + if (name == NULL) + usage("No key name specified -n <name>", 1); + + if (alg == 0) + usage("No algorithm specififed -{DHR}", 1); + + if (key_type == 0) + usage("Key type -{zhu} must be specified", 1); + else if (key_type > 1) + usage("Only one key type -{zhu} must be specified", 1); + + if (alg == NS_ALG_DSS) + no_conf = NS_KEY_NO_CONF; /* dss keys can not encrypt */ + + if (protocol == -1) { + if (zone_key || end_key) + protocol = NS_KEY_PROT_DNSSEC; + else + protocol = NS_KEY_PROT_EMAIL; + } + if (protocol < 0 || protocol > 255) + usage("Protocol value out of range [0..255]", 0); + + if (sign_val < 0 || sign_val > 15) { + sprintf(str, "%s: Signatory value %d out of range[0..15]\n", + prog, sign_val); + usage(str, 0); + } + /* if any of bits 321 is set bit 0 can not be set*/ + if (sign_val & 0xe) + sign_val &= 0xe; + + /* if a zone key make sure at least one of the signer flags is set */ + if ((protocol == NS_KEY_PROT_DNSSEC) && (sign_val == 0)) + sign_val = 0x01; + + if (no_auth && no_conf) { /* null key specified */ + if (sign_val > 0) + sign_val = 0x0; /* null key can not sign */ + if (size > 0) + size = 0; /* null key must have size 0 */ + } + + if (size > 0) { + if (alg == NS_ALG_MD5RSA){ + if (size < 512 || size > 4096) + usage("Size out of range", 1); + } + else if (exp) + usage("-F can only be specified with -R", 0); + if (alg == NS_ALG_DSS) { + for (i = 0; dsa_sizes[i]; i++) + if (size <= dsa_sizes[i]) + break; + if (size != dsa_sizes[i]) + usage("Invalid DSS key size", 1); + } + } + else if (size < 0) + usage("No size specified", 0); + + if (err) + usage("errors encountered/unknown flag", 1); + + flags = no_conf | no_auth | end_key | user_key | zone_key | sign_val; + +/* process defaults */ +#ifdef WARN_NONZONE_SIGNER + if (signer && (user_key | end_key)) + printf("Warning: User/End key is allowed to sign\n"); +#endif + + /* create a public/private key pair */ + if (alg == NS_ALG_MD5RSA) + printf("Generating %d bit RSA Key for %s\n\n",size, name); + else if (alg == NS_ALG_DSS) + printf("Generating %d bit DSS Key for %s\n\n",size, name); + else if (alg == KEY_HMAC_MD5) + printf("Generating %d bit HMAC-MD5 Key for %s\n\n", + size, name); + + /* Make the key + * dst_generate_key_pair will place result in files that it + * knows about K<name><foot>.public and K<name><foot>.private + */ + pubkey = dst_generate_key(name, size, exp, flags, protocol, alg); + + if (pubkey == NULL) { + printf("Failed generating key for %s\n", name); + exit(12); + } + + if (dst_write_key(pubkey, DST_PRIVATE) < 0) { + printf ("Failed to write private key for %s %d %d\n", + name, pubkey->dk_id, pubkey->dk_alg); + exit(12); + } + + if (dst_write_key(pubkey, DST_PUBLIC) <= 0) { + if (access(name, F_OK)) + printf("Not allowed to overwrite existing file\n"); + else + printf("Failed to write public key for %s %d %d\n", + name, pubkey->dk_id, pubkey->dk_alg); + exit(12); + } + + printf("Generated %d bit Key for %s id=%d alg=%d flags=%d\n\n", + size, name, pubkey->dk_id, pubkey->dk_alg, + pubkey->dk_flags); + exit(0); +} + +static void +usage(char *str, int flag){ + int i; + printf ("\nNo key generated\n"); + if (*str != '\0') + printf("Usage:%s: %s\n",prog, str); + printf("Usage:%s -{DHR} <size> [-F] -{zhu} [-ac] [-p <no>]" + " [-s <no>] -n name\n", prog); + if (flag == 0) + exit(2); + printf("\t-D generate DSA/DSS KEY: size must be one of following:\n"); + printf("\t\t"); + for(i = 0; dsa_sizes[i] > 0; i++) + printf(" %d,", dsa_sizes[i]); + printf("\n"); + printf("\t-H generate HMAC-MD5 KEY: size in the range [1..512]:\n"); + printf("\t-R generate RSA KEY: size in the range [512..4096]\n"); + printf("\t-F RSA KEYS only: use large exponent\n"); + + printf("\t-z Zone key \n"); + printf("\t-h Host/Entity key \n"); + printf("\t-u User key \n"); + + printf("\t-a Key CANNOT be used for authentication\n"); + printf("\t-c Key CANNOT be used for encryption\n"); + + printf("\t-p Set protocol field to <no>\n"); + printf("\t\t default: 2 (email) for Host keys, 3 (dnssec) for all others\n"); + printf("\t-s Strength value this key signs DNS records with\n"); + printf("\t\t default: 1 for Zone keys, 0 for all others\n"); + printf("\t-n name: the owner of the key\n"); + + if (flag == PRINT_SUPPORTED) { + printf("Available algorithms are:"); + if (dst_check_algorithm(NS_ALG_MD5RSA) == 1) + printf(" RSA"); + if (dst_check_algorithm(NS_ALG_DSS) == 1) + printf(" DSS"); + if (dst_check_algorithm(KEY_HMAC_MD5) == 1) + printf(" HMAC-MD5"); + printf("\n"); + } + + exit (-3); +} + + diff --git a/contrib/bind/bin/dnsquery/Makefile b/contrib/bind/bin/dnsquery/Makefile index 95d557d..a643702 100644 --- a/contrib/bind/bin/dnsquery/Makefile +++ b/contrib/bind/bin/dnsquery/Makefile @@ -1,4 +1,4 @@ -## Copyright (c) 1996 by Internet Software Consortium +## 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 @@ -13,7 +13,7 @@ ## ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ## SOFTWARE. -# $Id: Makefile,v 8.18 1997/06/19 03:22:08 halley Exp $ +# $Id: Makefile,v 8.24 1999/08/08 17:51:01 vixie Exp $ DESTDIR= CC= cc @@ -29,15 +29,17 @@ PORTINCL = ${TOP}/port/${SYSTYPE}/include LIBBIND = ${TOP}/lib/libbind.a A=a O=o +EXE= LEX = lex -I SYSLIBS = -ll -lutil -PIDDIR = /var/run DESTBIN = /usr/local/bin DESTSBIN = /usr/local/sbin DESTEXEC = /usr/local/libexec DESTMAN = /usr/share/man DESTHELP= /usr/share/misc STRIP=-s +INSTALL_EXEC= +INSTALL_LIB=-o bin -g bin LDFLAGS= CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL} @@ -46,26 +48,29 @@ PROG= dnsquery SRCS= ${PROG}.c OBJS= ${PROG}.${O} -all: ${PROG} +all: ${PROG}${EXE} -${PROG}: ${OBJS} ${LIBBIND} Makefile - ${CC} ${CDEBUG} ${LDFLAGS} -o ${PROG} ${OBJS} \ +${PROG}${EXE}: ${OBJS} ${LIBBIND} Makefile + ${CC} ${CDEBUG} ${LDFLAGS} ${BOUNDS} -o ${PROG}${EXE} ${OBJS} \ ${LIBBIND} ${SYSLIBS} +.c.${O}: + ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c + distclean: clean clean: FRC - rm -f ${PROG} ${OBJS} core .depend + rm -f ${PROG}${EXE} ${OBJS} core .depend rm -f *.BAK *.CKP *~ *.orig depend: ${SRCS} - mkdep -p ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS} + mkdep ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS} ${DESTDIR}${DESTBIN}: mkdir -p ${DESTDIR}${DESTBIN} -install: ${DESTDIR}${DESTBIN} ${PROG} - ${INSTALL} ${STRIP} -c -m 755 ${PROG} ${DESTDIR}${DESTBIN}/${PROG} +install: ${DESTDIR}${DESTBIN} ${PROG}${EXE} + ${INSTALL} ${STRIP} -c ${INSTALL_EXEC} -m 755 ${PROG}${EXE} ${DESTDIR}${DESTBIN}/${PROG}${EXE} links: FRC @set -e; ln -s SRC/*.[ch] . diff --git a/contrib/bind/bin/dnsquery/dnsquery.c b/contrib/bind/bin/dnsquery/dnsquery.c index 790e0cc..218c8a8 100644 --- a/contrib/bind/bin/dnsquery/dnsquery.c +++ b/contrib/bind/bin/dnsquery/dnsquery.c @@ -1,9 +1,9 @@ #if !defined(lint) && !defined(SABER) -static char rcsid[] = "$Id: dnsquery.c,v 8.7 1997/05/21 19:51:22 halley Exp $"; +static const char rcsid[] = "$Id: dnsquery.c,v 8.13 1999/10/13 16:38:59 vixie Exp $"; #endif /* not lint */ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -33,6 +33,7 @@ static char rcsid[] = "$Id: dnsquery.c,v 8.7 1997/05/21 19:51:22 halley Exp $"; #include <resolv.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <unistd.h> #include "port_after.h" @@ -41,6 +42,8 @@ extern int errno; extern int h_errno; extern char *h_errlist[]; +struct __res_state res; + int main(int argc, char *argv[]) { char name[MAXDNAME]; @@ -68,13 +71,13 @@ main(int argc, char *argv[]) { } /* handle args */ - while ((c = getopt(argc, argv, "c:dh:n:p:r:st:u:v")) != EOF) { + while ((c = getopt(argc, argv, "c:dh:n:p:r:st:u:v")) != -1) { switch (c) { - case 'r' : _res.retry = atoi(optarg); + case 'r' : res.retry = atoi(optarg); break; - case 'p' : _res.retrans = atoi(optarg); + case 'p' : res.retrans = atoi(optarg); break; case 'h' : strcpy(name, optarg); @@ -123,10 +126,11 @@ main(int argc, char *argv[]) { * So, we must init the resolver before any * of this. */ - if (!(_res.options & RES_INIT)) - if (res_init() == -1) { + if (!(res.options & RES_INIT)) + if (res_ninit(&res) == -1) { fprintf(stderr, - "res_init() failed\n"); + "res_ninit() failed\n" + ); exit(-1); } if (nameservers >= MAXNS) break; @@ -158,29 +162,28 @@ main(int argc, char *argv[]) { len = sizeof(answer); + if (!(res.options & RES_INIT)) + if (res_ninit(&res) == -1) { + fprintf(stderr, "res_ninit() failed\n"); + exit(-1); + } + /* * set these here so they aren't set for a possible call to * gethostbyname above */ - if (debug || stream) { - if (!(_res.options & RES_INIT)) - if (res_init() == -1) { - fprintf(stderr, "res_init() failed\n"); - exit(-1); - } - if (debug) - _res.options |= RES_DEBUG; - if (stream) - _res.options |= RES_USEVC; - } + if (debug) + res.options |= RES_DEBUG; + if (stream) + res.options |= RES_USEVC; /* if the -n flag was used, add them to the resolver's list */ if (nameservers != 0) { - _res.nscount = nameservers; + res.nscount = nameservers; for (i = nameservers - 1; i >= 0; i--) { - _res.nsaddr_list[i].sin_addr.s_addr = q_nsaddr[i].s_addr; - _res.nsaddr_list[i].sin_family = AF_INET; - _res.nsaddr_list[i].sin_port = htons(NAMESERVER_PORT); + res.nsaddr_list[i].sin_addr.s_addr = q_nsaddr[i].s_addr; + res.nsaddr_list[i].sin_family = AF_INET; + res.nsaddr_list[i].sin_port = htons(NAMESERVER_PORT); } } @@ -190,17 +193,18 @@ main(int argc, char *argv[]) { * which will strip the trailing dot */ if (name[strlen(name) - 1] == '.') { - n = res_query(name, class, type, answer, len); + n = res_nquery(&res, name, class, type, answer, len); if (n < 0) { fprintf(stderr, "Query failed (h_errno = %d) : %s\n", h_errno, h_errlist[h_errno]); exit(-1); } - } else if ((n = res_search(name, class, type, answer, len)) < 0) { + } else if ((n = res_nsearch(&res, name, class, type, + answer, len)) < 0) { fprintf(stderr, "Query failed (h_errno = %d) : %s\n", h_errno, h_errlist[h_errno]); exit(-1); } - fp_nquery(answer, n, stdout); + res_pquery(&res, answer, n, stdout); exit(0); } diff --git a/contrib/bind/bin/host/Makefile b/contrib/bind/bin/host/Makefile index c1090d4..f121ab7 100644 --- a/contrib/bind/bin/host/Makefile +++ b/contrib/bind/bin/host/Makefile @@ -1,4 +1,4 @@ -## Copyright (c) 1996 by Internet Software Consortium +## 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 @@ -13,7 +13,7 @@ ## ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ## SOFTWARE. -# $Id: Makefile,v 8.18 1997/06/19 03:22:08 halley Exp $ +# $Id: Makefile,v 8.24 1999/08/08 17:51:01 vixie Exp $ DESTDIR= CC= cc @@ -29,15 +29,17 @@ PORTINCL = ${TOP}/port/${SYSTYPE}/include LIBBIND = ${TOP}/lib/libbind.a A=a O=o +EXE= LEX = lex -I SYSLIBS = -ll -lutil -PIDDIR = /var/run DESTBIN = /usr/local/bin DESTSBIN = /usr/local/sbin DESTEXEC = /usr/local/libexec DESTMAN = /usr/share/man DESTHELP= /usr/share/misc STRIP=-s +INSTALL_EXEC= +INSTALL_LIB=-o bin -g bin LDFLAGS= CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL} @@ -46,26 +48,29 @@ PROG= host SRCS= ${PROG}.c OBJS= ${PROG}.${O} -all: ${PROG} +all: ${PROG}${EXE} -${PROG}: ${OBJS} ${LIBBIND} Makefile - ${CC} ${CDEBUG} ${LDFLAGS} -o ${PROG} ${OBJS} \ +${PROG}${EXE}: ${OBJS} ${LIBBIND} Makefile + ${CC} ${CDEBUG} ${LDFLAGS} ${BOUNDS} -o ${PROG}${EXE} ${OBJS} \ ${LIBBIND} ${SYSLIBS} +.c.${O}: + ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c + distclean: clean clean: FRC - rm -f ${PROG} ${OBJS} core .depend + rm -f ${PROG}${EXE} ${OBJS} core .depend rm -f *.BAK *.CKP *~ *.orig depend: ${SRCS} - mkdep -p ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS} + mkdep ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS} ${DESTDIR}${DESTBIN}: mkdir -p ${DESTDIR}${DESTBIN} -install: ${DESTDIR}${DESTBIN} ${PROG} - ${INSTALL} ${STRIP} -c -m 755 ${PROG} ${DESTDIR}${DESTBIN}/${PROG} +install: ${DESTDIR}${DESTBIN} ${PROG}${EXE} + ${INSTALL} ${STRIP} -c ${INSTALL_EXEC} -m 755 ${PROG}${EXE} ${DESTDIR}${DESTBIN}/${PROG}${EXE} links: FRC @set -e; ln -s SRC/*.[ch] . diff --git a/contrib/bind/bin/host/host.c b/contrib/bind/bin/host/host.c index 78eb48b..bcfbe02 100644 --- a/contrib/bind/bin/host/host.c +++ b/contrib/bind/bin/host/host.c @@ -1,5 +1,5 @@ #ifndef lint -static char rcsid[] = "$Id: host.c,v 8.21 1998/03/19 19:31:25 halley Exp $"; +static const char rcsid[] = "$Id: host.c,v 8.34 1999/11/11 19:39:10 cyarnell Exp $"; #endif /* not lint */ /* @@ -56,7 +56,7 @@ static char rcsid[] = "$Id: host.c,v 8.21 1998/03/19 19:31:25 halley Exp $"; */ /* - * Portions Copyright (c) 1996 by Internet Software Consortium + * 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 @@ -76,7 +76,7 @@ static char rcsid[] = "$Id: host.c,v 8.21 1998/03/19 19:31:25 halley Exp $"; static const char copyright[] = "@(#) Copyright (c) 1986 Regents of the University of California.\n\ Portions Copyright (c) 1993 Digital Equipment Corporation.\n\ - Portions Copyright (c) 1996 Internet Software Consortium.\n\ + Portions Copyright (c) 1996-1999 Internet Software Consortium.\n\ All rights reserved.\n"; #endif /* not lint */ @@ -106,16 +106,22 @@ static const char copyright[] = #include <string.h> #include <unistd.h> -#include "port_after.h" +#include <memory.h> +#include <errno.h> +#include <sys/stat.h> +#include <isc/dst.h> -extern int h_errno; -extern char *_res_resultcodes[]; +#include "port_after.h" /* Global. */ +#define SIG_RDATA_BY_NAME 18 +#define NS_HEADERDATA_SIZE 10 + #define NUMNS 8 #define NUMNSADDR 16 #define NUMMX 50 +#define NUMRR 127 /* max rr's per node to verify signatures for */ #define SUCCESS 0 #define TIME_OUT -1 @@ -123,22 +129,50 @@ extern char *_res_resultcodes[]; #define ERROR -3 #define NONAUTH -4 +#define MY_PACKETSZ 64*1024 /* need this to hold tcp answers */ + typedef union { HEADER qb1; - u_char qb2[NS_PACKETSZ]; + u_char qb2[MY_PACKETSZ]; } querybuf; +#define SD_RR 1 +#define SD_SIG 2 +#define SD_BADSIG 4 + +typedef struct { + u_char data[MY_PACKETSZ]; + size_t len; +} rrstruct; + +static char chase_domain[NS_MAXDNAME]; +static int chase_class; +static int chase_type; +static char chase_sigorigttl[NS_INT32SZ]; +static rrstruct chase_rr[NUMRR]; +static int chase_rr_num; +static char chase_lastgoodkey[NS_MAXDNAME]; +static char chase_signer[NS_MAXDNAME]; +static u_char chase_sigrdata[MY_PACKETSZ]; +static size_t chase_sigrdata_len; +static u_char chase_signature[MY_PACKETSZ]; +static size_t chase_signature_len; +static int chase_step; +static int sigchase; + static char cnamebuf[NS_MAXDNAME]; static u_char hostbuf[NS_MAXDNAME]; static int sockFD; static FILE *filePtr; -static struct __res_state orig; +static struct __res_state res, orig; static char *cname = NULL; +static const char *progname = "amnesia"; static int getclass = ns_c_in, verbose = 0, list = 0; static int server_specified = 0; static int gettype; +static char getdomain[NS_MAXDNAME]; /* Forward. */ @@ -146,7 +180,7 @@ static int parsetype(const char *s); static int parseclass(const char *s); static void printanswer(const struct hostent *hp); static void hperror(int errnum); -static int getaddrinfo(struct in_addr addr); +static int addrinfo(struct in_addr addr); static int gethostinfo(char *name); static int getdomaininfo(const char *name, const char *domain); static int getinfo(const char *name, const char *domain, @@ -162,74 +196,97 @@ static const u_char * pr_cdname(const u_char *cp, const u_char *msg, static int ListHosts(char *namePtr, int queryType); static const char * DecodeError(int result); +static void +usage(const char *msg) { + fprintf(stderr, "%s: usage error (%s)\n", progname, msg); + fprintf(stderr, "\ +Usage: %s [-adlrwv] [-t querytype] [-c class] host [server]\n\ +\t-a is equivalent to '-v -t *'\n\ +\t-c class to look for non-Internet data\n\ +\t-d to turn on debugging output\n\ +\t-l to turn on 'list mode'\n\ +\t-r to disable recursive processing\n\ +\t-s recursively chase signature found in answers\n\ +\t-t querytype to look for a specific type of information\n\ +\t-v for verbose output\n\ +\t-w to wait forever until reply\n\ +", progname); + exit(1); +} + /* Public. */ int -main(int c, char **v) { +main(int argc, char **argv) { struct in_addr addr; struct hostent *hp; - char *s, *oldcname; + char *s; int inverse = 0, waitmode = 0; - int ncnames; + int ncnames, ch; + int nkeychains, i; - res_init(); - _res.retrans = 5; + dst_init(); - if (c < 2) { - fprintf(stderr, "Usage: host [-w] [-v] [-r] [-d] [-t querytype] [-c class] [-a] host [server]\n -w to wait forever until reply\n -v for verbose output\n -r to disable recursive processing\n -d to turn on debugging output\n -t querytype to look for a specific type of information\n -c class to look for non-Internet data\n -a is equivalent to '-v -t *'\n"); - exit(1); - } - while (c > 2 && v[1][0] == '-') { - if (strcmp (v[1], "-w") == 0) { - _res.retry = 1; - _res.retrans = 15; - waitmode = 1; - v++; - c--; - } - else if (strcmp (v[1], "-r") == 0) { - _res.options &= ~RES_RECURSE; - v++; - c--; - } - else if (strcmp (v[1], "-d") == 0) { - _res.options |= RES_DEBUG; - v++; - c--; - } - else if (strcmp (v[1], "-v") == 0) { + if ((progname = strrchr(argv[0], '/')) == NULL) + progname = argv[0]; + else + progname++; + res_ninit(&res); + res.retrans = 5; + while ((ch = getopt(argc, argv, "ac:dlrst:vw")) != -1) { + switch (ch) { + case 'a': verbose = 1; - v++; - c--; - } - else if (strcmp (v[1], "-l") == 0) { + gettype = ns_t_any; + break; + case 'c': + getclass = parseclass(optarg); + break; + case 'd': + res.options |= RES_DEBUG; + break; + case 'l': list = 1; - v++; - c--; - } - else if (strncmp (v[1], "-t", 2) == 0) { - v++; - c--; - gettype = parsetype(v[1]); - v++; - c--; - } - else if (strncmp (v[1], "-c", 2) == 0) { - v++; - c--; - getclass = parseclass(v[1]); - v++; - c--; - } - else if (strcmp (v[1], "-a") == 0) { + break; + case 'r': + res.options &= ~RES_RECURSE; + break; + case 's': + sigchase = 1; + break; + case 't': + gettype = parsetype(optarg); + break; + case 'v': verbose = 1; - gettype = ns_t_any; - v++; - c--; - } - } - if (c > 2) { - s = v[2]; + break; + case 'w': + res.retry = 1; + res.retrans = 15; + waitmode = 1; + break; + default: + usage("unrecogized switch"); + /*NOTREACHED*/ + } + } + if (gettype == 0) { + if (verbose) + printf ("Forcing `-t a' for signature trace.\n"); + gettype = ns_t_a; + } + argc -= optind; + argv += optind; + if (argc < 1) + usage("missing host argument"); + strncpy(getdomain, *argv++, NS_MAXDNAME); + getdomain[NS_MAXDNAME-1] = 0; + argc--; + if (argc > 1) + usage("extra undefined arguments"); + if (argc == 1) { + s = *argv++; + argc--; server_specified++; if (!inet_aton(s, &addr)) { @@ -237,55 +294,85 @@ main(int c, char **v) { if (hp == NULL) { fprintf(stderr, "Error in looking up server name:\n"); - hperror(h_errno); + hperror(res.res_h_errno); exit(1); } - memcpy(&_res.nsaddr.sin_addr, hp->h_addr, NS_INADDRSZ); + memcpy(&res.nsaddr.sin_addr, hp->h_addr, NS_INADDRSZ); printf("Using domain server:\n"); printanswer(hp); } else { - _res.nsaddr.sin_family = AF_INET; - _res.nsaddr.sin_addr = addr; - _res.nsaddr.sin_port = htons(NAMESERVER_PORT); + res.nsaddr.sin_family = AF_INET; + res.nsaddr.sin_addr = addr; + res.nsaddr.sin_port = htons(NAMESERVER_PORT); printf("Using domain server %s:\n", - inet_ntoa(_res.nsaddr.sin_addr)); + inet_ntoa(res.nsaddr.sin_addr)); } - _res.nscount = 1; - _res.retry = 2; + res.nscount = 1; + res.retry = 2; } - if (strcmp(v[1], ".") == 0 || !inet_aton(v[1], &addr)) + if (strcmp(getdomain, ".") == 0 || !inet_aton(getdomain, &addr)) addr.s_addr = INADDR_NONE; hp = NULL; - h_errno = TRY_AGAIN; + res.res_h_errno = TRY_AGAIN; /* * We handle default domains ourselves, thank you. */ - _res.options &= ~RES_DEFNAMES; + res.options &= ~RES_DEFNAMES; if (list) - exit(ListHosts(v[1], gettype ? gettype : ns_t_a)); - oldcname = NULL; - ncnames = 5; - while (hp == NULL && h_errno == TRY_AGAIN) { + exit(ListHosts(getdomain, gettype ? gettype : ns_t_a)); + ncnames = 5; nkeychains = 18; + while (hp == NULL && res.res_h_errno == TRY_AGAIN) { if (addr.s_addr == INADDR_NONE) { cname = NULL; - if (oldcname == NULL) - hp = (struct hostent *)gethostinfo(v[1]); - else - hp = (struct hostent *)gethostinfo(oldcname); - if (cname) { + hp = (struct hostent *)gethostinfo(getdomain); + getdomain[0] = 0; /* clear this query */ + if (sigchase && (chase_step & SD_RR)) { + if (nkeychains-- == 0) { + printf("Too many sig/key chains. Loop?\n"); + exit(1); + } + if (chase_step & SD_SIG) { + /* start new query, for KEY */ + strcpy (getdomain, chase_signer); + strcat (getdomain, "."); + gettype = ns_t_key; + } else if (!(chase_step & SD_BADSIG)) { + /* start new query, for SIG */ + strcpy (getdomain, chase_domain); + strcat (getdomain, "."); + gettype = ns_t_sig; + } else if (hp && !(chase_step & SD_SIG) && + (chase_step & SD_BADSIG)) { + printf ("%s for %s not found, last verified key %s\n", + chase_step & SD_SIG ? "Key" : "Signature", + chase_step & SD_SIG ? chase_signer : chase_domain, + chase_domain, + chase_lastgoodkey ? chase_lastgoodkey : "None"); + } + } + if (!getdomain[0] && cname) { if (ncnames-- == 0) { printf("Too many cnames. Loop?\n"); exit(1); } - strcat(cname, "."); - oldcname = cname; + strcpy(getdomain, cname); + strcat(getdomain, "."); + } + if (getdomain[0]) { + if (chase_step & SD_SIG) { + printf ("Locating key for %s\n", getdomain); + } else if (chase_step & SD_SIG) { + printf ("Locating signature for %s record(s) on %s\n", + sym_ntos(__p_type_syms, chase_type, NULL), + getdomain); + } hp = NULL; - h_errno = TRY_AGAIN; + res.res_h_errno = TRY_AGAIN; continue; } } else { - if (getaddrinfo(addr) == 0) + if (addrinfo(addr) == 0) hp = NULL; else hp = (struct hostent *)1; /* XXX */ @@ -295,7 +382,7 @@ main(int c, char **v) { } if (hp == NULL) { - hperror(h_errno); + hperror(res.res_h_errno); exit(1); } @@ -317,6 +404,7 @@ parsetype(const char *s) { return (atoi(s)); fprintf(stderr, "Invalid query type: %s\n", s); exit(2); + /*NOTREACHED*/ } static int @@ -330,6 +418,7 @@ parseclass(const char *s) { return (atoi(s)); fprintf(stderr, "Invalid query class: %s\n", s); exit(2); + /*NOTREACHED*/ } static void @@ -430,7 +519,7 @@ hperror(int errnum) { } static int -getaddrinfo(struct in_addr addr) { +addrinfo(struct in_addr addr) { u_int32_t ha = ntohl(addr.s_addr); char name[NS_MAXDNAME]; @@ -445,6 +534,7 @@ getaddrinfo(struct in_addr addr) { static int gethostinfo(char *name) { char *cp, **domain; + char tmp[NS_MAXDNAME]; const char *tp; int hp, nDomain; int asis = 0; @@ -463,13 +553,13 @@ gethostinfo(char *name) { cp[-1] = '.'; return (hp); } - if (n == 0 && (tp = hostalias(name))) { + if (n == 0 && (tp = res_hostalias(&res, name, tmp, sizeof tmp))) { if (verbose) printf("Aliased to \"%s\"\n", tp); - _res.options |= RES_DEFNAMES; + res.options |= RES_DEFNAMES; return (getdomaininfo(tp, (char *)NULL)); } - if (n >= _res.ndots) { + if (n >= res.ndots) { asis = 1; if (verbose) printf("Trying null domain\n"); @@ -477,14 +567,14 @@ gethostinfo(char *name) { if (hp) return (hp); } - for (domain = _res.dnsrch; *domain; domain++) { + for (domain = res.dnsrch; *domain; domain++) { if (verbose) printf("Trying domain \"%s\"\n", *domain); hp = getdomaininfo(name, *domain); if (hp) return (hp); } - if (h_errno != HOST_NOT_FOUND || (_res.options & RES_DNSRCH) == 0) + if (res.res_h_errno != HOST_NOT_FOUND || (res.options & RES_DNSRCH) == 0) return (0); if (!asis) return (0); @@ -500,10 +590,10 @@ getdomaininfo(const char *name, const char *domain) { if (gettype) return (getinfo(name, domain, gettype)); else { - val1 = getinfo(name, domain, ns_t_a); + val1 = getinfo(name, domain, gettype=ns_t_a); if (cname || verbose) return (val1); - val2 = getinfo(name, domain, ns_t_mx); + val2 = getinfo(name, domain, gettype=ns_t_mx); return (val1 || val2); } } @@ -523,19 +613,19 @@ getinfo(const char *name, const char *domain, int type) { sprintf(host, "%.*s.%.*s", NS_MAXDNAME, name, NS_MAXDNAME, domain); - n = res_mkquery(QUERY, host, getclass, type, NULL, 0, NULL, - buf.qb2, sizeof buf); + n = res_nmkquery(&res, QUERY, host, getclass, type, NULL, 0, NULL, + buf.qb2, sizeof buf); if (n < 0) { - if (_res.options & RES_DEBUG) - printf("res_mkquery failed\n"); - h_errno = NO_RECOVERY; + if (res.options & RES_DEBUG) + printf("res_nmkquery failed\n"); + res.res_h_errno = NO_RECOVERY; return (0); } - n = res_send(buf.qb2, n, answer.qb2, sizeof answer); + n = res_nsend(&res, buf.qb2, n, answer.qb2, sizeof answer); if (n < 0) { - if (_res.options & RES_DEBUG) - printf("res_send failed\n"); - h_errno = TRY_AGAIN; + if (res.options & RES_DEBUG) + printf("res_nsend failed\n"); + res.res_h_errno = TRY_AGAIN; return (0); } eom = answer.qb2 + n; @@ -544,7 +634,7 @@ getinfo(const char *name, const char *domain, int type) { static int printinfo(const querybuf *answer, const u_char *eom, int filter, int isls) { - int n, n1, i, j, nmx, ancount, nscount, arcount, qdcount, buflen; + int n, n1, i, j, nmx, ancount, nscount, arcount, qdcount, buflen, savesigchase; u_short pref, class; const u_char *bp, *cp; const HEADER *hp; @@ -557,24 +647,24 @@ printinfo(const querybuf *answer, const u_char *eom, int filter, int isls) { qdcount = ntohs(hp->qdcount); nscount = ntohs(hp->nscount); arcount = ntohs(hp->arcount); - if (_res.options & RES_DEBUG || (verbose && isls == 0)) + if (res.options & RES_DEBUG || (verbose && isls == 0)) printf("rcode = %d (%s), ancount=%d\n", hp->rcode, DecodeError(hp->rcode), ancount); if (hp->rcode != NOERROR || (ancount+nscount+arcount) == 0) { switch (hp->rcode) { case NXDOMAIN: - h_errno = HOST_NOT_FOUND; + res.res_h_errno = HOST_NOT_FOUND; return (0); case SERVFAIL: - h_errno = TRY_AGAIN; + res.res_h_errno = TRY_AGAIN; return (0); case NOERROR: - h_errno = NO_DATA; + res.res_h_errno = NO_DATA; return (0); case FORMERR: case NOTIMP: case REFUSED: - h_errno = NO_RECOVERY; + res.res_h_errno = NO_RECOVERY; return (0); } return (0); @@ -603,21 +693,20 @@ printinfo(const querybuf *answer, const u_char *eom, int filter, int isls) { printf( "The following answer is not authoritative:\n" ); - while (--ancount >= 0 && cp && cp < eom) { + if (!hp->ad) + if (verbose && isls == 0) + printf("The following answer is not verified as authentic by the server:\n"); + while (--ancount >= 0 && cp && cp < eom) cp = pr_rr(cp, answer->qb2, stdout, filter); - /* - * When we ask for address and there is a CNAME, it - * seems to return both the CNAME and the address. - * Since we trace down the CNAME chain ourselves, we - * don't really want to print the address at this - * point. - */ - if (cname && ! verbose) - return (1); - } } if (!verbose) return (1); + + /* don't chase signatures for non-answer stuff */ + + savesigchase = sigchase; + sigchase = 0; + if (nscount) { printf("For authoritative answers, see:\n"); while (--nscount >= 0 && cp && cp < eom) @@ -628,9 +717,80 @@ printinfo(const querybuf *answer, const u_char *eom, int filter, int isls) { while (--arcount >= 0 && cp && cp < eom) cp = (u_char *)pr_rr(cp, answer->qb2, stdout, filter); } + + /* restore sigchase value */ + + sigchase = savesigchase; + return (1); } +void print_hex_field (u_int8_t field[], int length, int width, char *pref) +{ + /* Prints an arbitrary bit field, from one address for some number of + bytes. Output is formatted via the width, and includes the raw + hex value and (if printable) the printed value underneath. "pref" + is a string used to start each line, e.g., " " to indent. + + This is very useful in gdb to see what's in a memory field. + */ + int i, start, stop; + + start=0; + do + { + stop=(start+width)<length?(start+width):length; + printf (pref); + for (i = start; i < stop; i++) + printf ("%02x ", (u_char) field[i]); + printf ("\n"); + + printf (pref); + for (i = start; i < stop; i++) + if (isprint(field[i])) + printf (" %c ", (u_char) field[i]); + else + printf (" "); + printf ("\n"); + + start = stop; + } while (start < length); +} + +void memswap (void *s1, void *s2, size_t n) +{ + void *tmp; + + tmp = malloc(n); + if (!tmp) { + printf ("Out of memory\n"); + exit (1); + } + + memcpy(tmp, s1, n); + memcpy(s1, s2, n); + memcpy(s2, tmp, n); + + free (tmp); +} + +void print_hex (u_int8_t field[], int length) +{ + /* Prints the hex values of a field...not as pretty as the print_hex_field. + */ + int i, start, stop; + + start=0; + do + { + stop=length; + for (i = start; i < stop; i++) + printf ("%02x ", (u_char) field[i]); + start = stop; + if (start < length) printf ("\n"); + } while (start < length); +} + /* * Print resource record fields in human readable form. */ @@ -639,16 +799,21 @@ pr_rr(const u_char *cp, const u_char *msg, FILE *file, int filter) { int type, class, dlen, n, c, proto, ttl; struct in_addr inaddr; u_char in6addr[NS_IN6ADDRSZ]; + const u_char *savecp = cp; const u_char *cp1; struct protoent *protop; struct servent *servp; char punc = ' '; int doprint; char name[NS_MAXDNAME]; + char thisdomain[NS_MAXDNAME]; char tmpbuf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"]; + u_char canonrr[MY_PACKETSZ]; + size_t canonrr_len = 0; if ((cp = (u_char *)pr_cdname(cp, msg, name, sizeof(name))) == NULL) return (NULL); /* compression error */ + strcpy(thisdomain, name); type = ns_get16(cp); cp += INT16SZ; @@ -711,10 +876,31 @@ pr_rr(const u_char *cp, const u_char *msg, FILE *file, int filter) { case ns_t_mr: case ns_t_ns: case ns_t_ptr: - cp = (u_char *)pr_cdname(cp, msg, name, sizeof(name)); + { + const u_char *startrdata = cp; + u_char cdname[NS_MAXCDNAME]; + + cp = (u_char *)pr_cdname(cp, msg, name, sizeof name); if (doprint) - fprintf(file,"%c%s",punc, name); + fprintf(file, "%c%s", punc, name); + + /* Extract DNSSEC canonical RR. */ + + n = ns_name_unpack(msg, msg+MY_PACKETSZ, startrdata, + cdname, sizeof cdname); + if (n >= 0) + n = ns_name_ntol(cdname, cdname, sizeof cdname); + if (n >= 0) { + /* Copy header. */ + memcpy(canonrr, cp1 - NS_HEADERDATA_SIZE, NS_HEADERDATA_SIZE); + /* Overwrite length field. */ + ns_put16(n, canonrr + NS_HEADERDATA_SIZE - NS_INT16SZ); + /* Copy unpacked name. */ + memcpy(canonrr + NS_HEADERDATA_SIZE, cdname, n); + canonrr_len = NS_HEADERDATA_SIZE + n; + } break; + } case ns_t_hinfo: case ns_t_isdn: @@ -739,12 +925,47 @@ pr_rr(const u_char *cp, const u_char *msg, FILE *file, int filter) { break; case ns_t_soa: - cp = (u_char *)pr_cdname(cp, msg, name, sizeof(name)); + { + const u_char *startname = cp; + u_char cdname[NS_MAXCDNAME]; + + cp = (u_char *)pr_cdname(cp, msg, name, sizeof name); if (doprint) fprintf(file, "\t%s", name); - cp = (u_char *)pr_cdname(cp, msg, name, sizeof(name)); + + n = ns_name_unpack(msg, msg + 512, startname, + cdname, sizeof cdname); + if (n >= 0) + n = ns_name_ntol(cdname, cdname, sizeof cdname); + if (n >= 0) { + /* Copy header. */ + memcpy(canonrr, cp1 - NS_HEADERDATA_SIZE, NS_HEADERDATA_SIZE); + /* Copy expanded name. */ + memcpy(canonrr + NS_HEADERDATA_SIZE, cdname, n); + canonrr_len = NS_HEADERDATA_SIZE + n; + } + + startname = cp; + cp = (u_char *)pr_cdname(cp, msg, name, sizeof name); if (doprint) fprintf(file, " %s", name); + + n = ns_name_unpack(msg, msg + 512, startname, + cdname, sizeof cdname); + if (n >= 0) + n = ns_name_ntol(cdname, cdname, sizeof cdname); + if (n >= 0) { + /* Copy expanded name. */ + memcpy(canonrr + canonrr_len, cdname, n); + canonrr_len += n; + /* Copy rest of SOA. */ + memcpy(canonrr + canonrr_len, cp, 5 * INT32SZ); + canonrr_len += 5 * INT32SZ; + /* Overwrite length field. */ + ns_put16(canonrr_len - NS_HEADERDATA_SIZE, + canonrr + NS_HEADERDATA_SIZE - NS_INT16SZ); + } + if (doprint) fprintf(file, "(\n\t\t\t%ld\t;serial (version)", ns_get32(cp)); @@ -767,10 +988,14 @@ pr_rr(const u_char *cp, const u_char *msg, FILE *file, int filter) { ns_get32(cp)); cp += INT32SZ; break; - + } case ns_t_mx: case ns_t_afsdb: case ns_t_rt: + { + const u_char *startrdata = cp; + u_char cdname[NS_MAXCDNAME]; + if (doprint) { if (type == ns_t_mx && !verbose) fprintf(file," (pri=%d) by ", ns_get16(cp)); @@ -783,7 +1008,28 @@ pr_rr(const u_char *cp, const u_char *msg, FILE *file, int filter) { cp = (u_char *)pr_cdname(cp, msg, name, sizeof(name)); if (doprint) fprintf(file, "%s", name); + + n = ns_name_unpack(msg, msg+512, startrdata + sizeof(u_short), + cdname, sizeof cdname); + if (n >= 0) + n = ns_name_ntol(cdname, cdname, sizeof cdname); + if (n >= 0) { + /* Copy header. */ + memcpy(canonrr, cp1 - NS_HEADERDATA_SIZE, + NS_HEADERDATA_SIZE); + /* Overwrite length field. */ + ns_put16(sizeof(u_short) + n, + canonrr + NS_HEADERDATA_SIZE - NS_INT16SZ); + /* Copy u_short. */ + memcpy(canonrr + NS_HEADERDATA_SIZE, startrdata, + sizeof(u_short)); + /* Copy expanded name. */ + memcpy(canonrr + NS_HEADERDATA_SIZE + sizeof(u_short), + cdname, n); + canonrr_len = NS_HEADERDATA_SIZE + sizeof(u_short) + n; + } break; + } case ns_t_srv: if (doprint) @@ -934,6 +1180,260 @@ pr_rr(const u_char *cp, const u_char *msg, FILE *file, int filter) { } while (++n & 07); } break; + case ns_t_nxt: + { + const u_char *startrdata = cp; + u_char cdname[NS_MAXCDNAME]; + size_t bitmaplen; + + cp = (u_char *) pr_cdname(cp, msg, name, sizeof name); + if (doprint) + fprintf(file, "%c%s", punc, name); + bitmaplen = dlen - (cp - startrdata); + + /* extract dnssec canonical rr */ + + n = ns_name_unpack(msg, msg+MY_PACKETSZ, startrdata, + cdname, sizeof cdname); + if (n >= 0) + n = ns_name_ntol(cdname, cdname, sizeof cdname); + if (n >= 0) { + /* Copy header. */ + memcpy(canonrr, cp1 - NS_HEADERDATA_SIZE, + NS_HEADERDATA_SIZE); + /* Overwrite length field. */ + ns_put16(n + bitmaplen, + canonrr + NS_HEADERDATA_SIZE - NS_INT16SZ); + /* Copy expanded name. */ + memcpy(canonrr + NS_HEADERDATA_SIZE, cdname, n); + /* Copy type bit map. */ + memcpy(canonrr + NS_HEADERDATA_SIZE + n, cp, + bitmaplen); + canonrr_len = NS_HEADERDATA_SIZE + n + bitmaplen; + } + cp += bitmaplen; + break; + } + case ns_t_sig: + { + int tc; + const u_char *origttl; + + /* type covered */ + tc = ns_get16(cp); + if (doprint && verbose) + fprintf(file, "%c%s", punc, sym_ntos(__p_type_syms, tc, NULL)); + cp += sizeof(u_short); + /* algorithm */ + if (doprint && verbose) + fprintf(file, " %d", *cp); + cp++; + /* labels */ + if (doprint && verbose) + fprintf(file, " %d", *cp); + cp++; + /* original ttl */ + origttl = cp; + if (doprint && verbose) + fprintf(file, " %d", ns_get32(cp)); + cp += INT32SZ; + /* signature expiration */ + if (doprint && verbose) + fprintf(file, " %d", ns_get32(cp)); + cp += INT32SZ; + /* time signed */ + if (doprint && verbose) + fprintf(file, " %d", ns_get32(cp)); + cp += INT32SZ; + /* key footprint */ + if (doprint && verbose) + fprintf(file, " %d", ns_get16(cp)); + cp += sizeof(u_short); + /* signer's name */ + cp = (u_char *)pr_cdname(cp, msg, name, sizeof(name)); + if (doprint && verbose) + fprintf(file, " %s", name); + else if (doprint && !verbose) + fprintf (file, " %s for type %s", name, + sym_ntos(__p_type_syms, tc, NULL)); + /* signature */ + { + char str[MY_PACKETSZ]; + size_t len = cp1-cp+dlen; + + b64_ntop (cp, len, str, MY_PACKETSZ-1); + + if (sigchase && !(chase_step & SD_SIG) && + strcmp (chase_domain, thisdomain) == 0 && + chase_class == class & chase_type == tc) + { + u_char cdname[NS_MAXCDNAME]; + + if (doprint && !verbose) + fprintf(file, " (chasing key)"); + + strcpy(chase_signer, name); + + memcpy(&chase_sigorigttl[0], origttl, + NS_INT32SZ); + + n = ns_name_ntol(cp1 + SIG_RDATA_BY_NAME, + cdname, sizeof cdname); + if (n >= 0) { + memcpy(chase_sigrdata, cp1, + SIG_RDATA_BY_NAME); + memcpy(chase_sigrdata + SIG_RDATA_BY_NAME, + cdname, n); + chase_sigrdata_len += SIG_RDATA_BY_NAME + n; + memcpy(chase_signature, cp, len); + chase_signature_len = len; + + chase_step |= SD_SIG; + } + } else if (sigchase) { + chase_step |= SD_BADSIG; + } + + cp += len; + if (doprint && verbose) + fprintf (file, " %s", str); + } + break; + } + case ns_t_key: + /* flags */ + if (doprint && verbose) + fprintf(file, "%c%d", punc, ns_get16(cp)); + cp += sizeof(u_short); + /* protocol */ + if (doprint && verbose) + fprintf(file, " %d", *cp); + cp++; + /* algorithm */ + n = *cp; + if (doprint && verbose) + fprintf(file, " %d", *cp); + cp++; + switch (n) { + case 1: /* MD5/RSA */ + { + char str[MY_PACKETSZ]; + size_t len = cp1-cp+dlen; + + b64_ntop (cp, len, str, MY_PACKETSZ-1); + cp += len; + + if (doprint && verbose) + fprintf (file, " %s", str); + break; + } + + default: + fprintf (stderr, "Unknown algorithm %d\n", n); + cp = cp1 + dlen; + break; + } + + if (sigchase && (chase_step & (SD_SIG|SD_RR)) && + strcmp (getdomain, name) == 0 && + getclass == class & gettype == type) + { + DST_KEY *dstkey; + int rc, len, i, j; + + /* convert dnskey to dstkey */ + + dstkey = dst_dnskey_to_key (name, cp1, dlen); + + /* fix ttl in rr */ + + for (i = 0; i < NUMRR && chase_rr[i].len; i++) + { + len = dn_skipname(chase_rr[i].data, + chase_rr[i].data + + chase_rr[i].len); + if (len>=0) + memcpy(chase_rr[i].data + len + NS_INT16SZ + + NS_INT16SZ, + &chase_sigorigttl, INT32SZ); + } + + /* sort rr's (qsort() is too slow) */ + + for (i = 0; i < NUMRR && chase_rr[i].len; i++) + for (j = i + 1; i < NUMRR && chase_rr[j].len; j++) + if (memcmp(chase_rr[i].data, chase_rr[j].data, MY_PACKETSZ) > 0) + memswap(&chase_rr[i], &chase_rr[j], sizeof(rrstruct)); + + /* append rr's to sigrdata */ + + for (i = 0; i < NUMRR && chase_rr[i].len; i++) + { + memcpy (chase_sigrdata + chase_sigrdata_len, + chase_rr[i].data, chase_rr[i].len); + chase_sigrdata_len += chase_rr[i].len; + } + + /* print rr-data and signature */ + + if (verbose) { + print_hex_field(chase_sigrdata, + chase_sigrdata_len, + 21,"DATA: "); + print_hex_field(chase_signature, + chase_signature_len, + 21,"SIG: "); + } + + /* do the works */ + + if (dstkey) + rc = dst_verify_data(SIG_MODE_ALL, dstkey, NULL, + chase_sigrdata, + chase_sigrdata_len, + chase_signature, + chase_signature_len); + else + rc = 1; + + dst_free_key(dstkey); + + if (verbose) + { + fprintf(file, "\nVerification %s", rc == 0 ? + "was SUCCESSFULL" : + "FAILED"); + } + else + { + fprintf (file, + " that %s verify our %s " + "record(s) on %s", + rc == 0 ? "successfully" : + "DOES NOT", + sym_ntos(__p_type_syms, chase_type, + NULL), + chase_domain); + } + + if (rc == 0) + { + strcpy (chase_lastgoodkey, name); + } + else + { + /* don't trace further after a failure */ + sigchase = 0; + } + + chase_step = 0; + chase_signature_len = 0; + chase_sigrdata_len = 0; + memset(chase_sigorigttl, 0, NS_INT32SZ); + memset(chase_rr, 0, sizeof(chase_rr)); + chase_rr_num = 0; + } + break; default: if (doprint) @@ -944,8 +1444,42 @@ pr_rr(const u_char *cp, const u_char *msg, FILE *file, int filter) { if (cp != cp1 + dlen) fprintf(file, "packet size error (%p != %p)\n", cp, cp1 + dlen); + + if (sigchase && !(chase_step & SD_SIG) && + strcmp (getdomain, thisdomain) == 0 && getclass == class && + gettype == type && type != ns_t_sig) + { + u_char cdname[NS_MAXCDNAME]; + + if (doprint && !verbose) + fprintf (file, " (chasing signature)", sigchase-1); + + /* unpack rr */ + + n = ns_name_unpack(msg, msg + MY_PACKETSZ, savecp, + cdname, sizeof cdname); + if (n >= 0) + n = ns_name_ntol(cdname, cdname, sizeof cdname); + if (n >= 0) { + memcpy(chase_rr[chase_rr_num].data, cdname, n); + memcpy(chase_rr[chase_rr_num].data + n, + canonrr_len ? canonrr : cp1 - NS_HEADERDATA_SIZE, + canonrr_len ? canonrr_len : dlen + NS_HEADERDATA_SIZE); + chase_rr[chase_rr_num].len = + n + (canonrr_len != 0 ? canonrr_len : + dlen + NS_HEADERDATA_SIZE); + + strcpy(chase_domain, getdomain); + chase_class = class; + chase_type = type; + chase_step |= SD_RR; + chase_rr_num++; + } + } + if (doprint) fprintf(file, "\n"); + return (cp); } @@ -965,6 +1499,12 @@ pr_type(int type) { return ("mail is handled"); case ns_t_txt: return ("descriptive text"); + case ns_t_sig: + return ("has a signature signed by"); + case ns_t_key: + return ("has a key"); + case ns_t_nxt: + return ("next valid name"); case ns_t_afsdb: return ("DCE or AFS service from"); } @@ -995,7 +1535,7 @@ pr_class(int class) { static const u_char * pr_cdname(const u_char *cp, const u_char *msg, char *name, int namelen) { - int n = dn_expand(msg, msg + 512, cp, name, namelen - 2); + int n = dn_expand(msg, msg + MY_PACKETSZ, cp, name, namelen - 2); if (n < 0) return (NULL); @@ -1036,7 +1576,7 @@ ListHosts(char *namePtr, int queryType) { namePtr[i-1] = 0; if (server_specified) { - memcpy(&nsipaddr[0], &_res.nsaddr.sin_addr, NS_INADDRSZ); + memcpy(&nsipaddr[0], &res.nsaddr.sin_addr, NS_INADDRSZ); numnsaddr = 1; } else { /* @@ -1044,19 +1584,22 @@ ListHosts(char *namePtr, int queryType) { * query, possibly followed by looking up addresses for some * of the names. */ - msglen = res_mkquery(ns_o_query, namePtr, ns_c_in, ns_t_ns, - NULL, 0, NULL, buf.qb2, sizeof buf); + msglen = res_nmkquery(&res, ns_o_query, namePtr, + ns_c_in, ns_t_ns, + NULL, 0, NULL, + buf.qb2, sizeof buf); if (msglen < 0) { - printf("res_mkquery failed\n"); + printf("res_nmkquery failed\n"); return (ERROR); } - msglen = res_send(buf.qb2, msglen, answer.qb2, sizeof answer); + msglen = res_nsend(&res, buf.qb2, msglen, + answer.qb2, sizeof answer); if (msglen < 0) { printf("Cannot find nameserver -- try again later\n"); return (ERROR); } - if (_res.options & RES_DEBUG || verbose) + if (res.options & RES_DEBUG || verbose) printf("rcode = %d (%s), ancount=%d\n", answer.qb1.rcode, DecodeError(answer.qb1.rcode), ntohs(answer.qb1.ancount)); @@ -1134,13 +1677,13 @@ ListHosts(char *namePtr, int queryType) { if (dn_expand(answer.qb2, eom, cp, name, sizeof(name)) >= 0) { if (numns < NUMNS && - strcasecmp((char *)domain, - namePtr) == 0) { + ns_samename((char *)domain, + namePtr) == 1) { for (i = 0; i < numns; i++) - if (strcasecmp( + if (ns_samename( nsname[i], (char *)name - ) == 0) + ) == 1) /* duplicate */ break; if (i >= numns) { @@ -1155,9 +1698,9 @@ ListHosts(char *namePtr, int queryType) { } else if (type == ns_t_a) { if (numnsaddr < NUMNSADDR) for (i = 0; i < numns; i++) { - if (strcasecmp(nsname[i], + if (ns_samename(nsname[i], (char *)domain) - == 0) { + == 1) { nshaveaddr[i]++; memcpy( &nsipaddr[numnsaddr], @@ -1195,11 +1738,11 @@ ListHosts(char *namePtr, int queryType) { numaddrs++; } } - if (_res.options & RES_DEBUG || verbose) + if (res.options & RES_DEBUG || verbose) printf( "Found %d addresses for %s by extra query\n", numaddrs, nsname[i]); - } else if (_res.options & RES_DEBUG || verbose) + } else if (res.options & RES_DEBUG || verbose) printf("Found %d addresses for %s\n", nshaveaddr[i], nsname[i]); } @@ -1218,10 +1761,10 @@ ListHosts(char *namePtr, int queryType) { /* * Create a query packet for the requested domain name. */ - msglen = res_mkquery(QUERY, namePtr, getclass, ns_t_axfr, NULL, - 0, NULL, buf.qb2, sizeof buf); + msglen = res_nmkquery(&res, QUERY, namePtr, getclass, ns_t_axfr, NULL, + 0, NULL, buf.qb2, sizeof buf); if (msglen < 0) { - if (_res.options & RES_DEBUG) + if (res.options & RES_DEBUG) fprintf(stderr, "ListHosts: Res_mkquery failed\n"); return (ERROR); } @@ -1240,7 +1783,7 @@ ListHosts(char *namePtr, int queryType) { return (ERROR); } memcpy(&sin.sin_addr, &nsipaddr[thisns], NS_INADDRSZ); - if (_res.options & RES_DEBUG || verbose) + if (res.options & RES_DEBUG || verbose) printf("Trying %s\n", inet_ntoa(sin.sin_addr)); if (connect(sockFD, (struct sockaddr *)&sin, sizeof(sin)) >= 0) break; @@ -1310,7 +1853,7 @@ ListHosts(char *namePtr, int queryType) { if (i != NOERROR || ntohs(buf.qb1.ancount) == 0) { if (thisns + 1 < numnsaddr && (i == SERVFAIL || i == NOTIMP || i == REFUSED)) { - if (_res.options & RES_DEBUG || verbose) + if (res.options & RES_DEBUG || verbose) printf( "Server failed, trying next server: %s\n", i != NOERROR @@ -1356,7 +1899,7 @@ ListHosts(char *namePtr, int queryType) { (void) dn_expand(buf.qb2, buf.qb2 + len, nmp, dname[soacnt], sizeof dname[0]); if (soacnt) { - if (strcmp(dname[0], dname[1]) == 0) + if (ns_samename(dname[0], dname[1]) == 1) break; } else soacnt++; @@ -1383,7 +1926,7 @@ ListHosts(char *namePtr, int queryType) { fprintf(stderr,"ListHosts: error receiving zone transfer:\n"); fprintf(stderr, " result: %s, answers = %d, authority = %d, additional = %d\n", - _res_resultcodes[headerPtr->rcode], + p_rcode(headerPtr->rcode), ntohs(headerPtr->ancount), ntohs(headerPtr->nscount), ntohs(headerPtr->arcount)); return (ERROR); @@ -1395,16 +1938,16 @@ ListHosts(char *namePtr, int queryType) { static const char * DecodeError(int result) { switch(result) { - case NOERROR: return ("Success"); break; - case FORMERR: return ("Format error"); break; - case SERVFAIL: return ("Server failed"); break; - case NXDOMAIN: return ("Non-existent domain"); break; - case NOTIMP: return ("Not implemented"); break; - case REFUSED: return ("Query refused"); break; - case NO_INFO: return ("No information"); break; - case ERROR: return ("Unspecified error"); break; - case TIME_OUT: return ("Timed out"); break; - case NONAUTH: return ("Non-authoritative answer"); break; + case NOERROR: return ("Success"); + case FORMERR: return ("Format error"); + case SERVFAIL: return ("Server failed"); + case NXDOMAIN: return ("Non-existent domain"); + case NOTIMP: return ("Not implemented"); + case REFUSED: return ("Query refused"); + case NO_INFO: return ("No information"); + case ERROR: return ("Unspecified error"); + case TIME_OUT: return ("Timed out"); + case NONAUTH: return ("Non-authoritative answer"); default: return ("BAD ERROR VALUE"); } /* NOTREACHED */ diff --git a/contrib/bind/bin/irpd/Makefile b/contrib/bind/bin/irpd/Makefile new file mode 100644 index 0000000..6f94d63 --- /dev/null +++ b/contrib/bind/bin/irpd/Makefile @@ -0,0 +1,98 @@ +## Copyright (c) 1996, 1997 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: Makefile,v 1.3 1999/02/22 02:47:55 vixie Exp $ + +DESTDIR= +CC= cc +SHELL= /bin/sh + +CDEBUG= -g + +#(net2 and its descendents) +SYSTYPE = bsdos +TOP = ../.. +INCL = ${TOP}/include +PORTINCL = ${TOP}/port/${SYSTYPE}/include +LIBBIND = ${TOP}/lib/libbind.a +A=a +O=o +EXE= +LEX = lex -I +YACC = yacc -d +SYSLIBS = -ll -lutil +DESTBIN = /usr/local/bin +DESTSBIN = /usr/local/sbin +DESTEXEC = /usr/local/libexec +DESTMAN = /usr/share/man +DESTHELP= /usr/share/misc +DESTETC= /etc +DESTRUN= /var/run +AR= ar cru +INSTALL= install +STRIP=-s + +PS=ps +LDFLAGS= +CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL} -I${TOP}/lib/irs ${DEFS} + +VER= LOCAL-`date +%y%m%d.%H%M%S` +HOSTNAMECMD= hostname || uname -n + +PROG= irpd +HDRS= +SRCS= irpd.c +OBJS= irpd.${O} + +all: ${PROG}${EXE} + +${PROG}${EXE}: irpd.${O} tmp_version.${O} ${LIBBIND} + ${CC} ${CDEBUG} ${LDFLAGS} -o ${PROG}${EXE} ${OBJS} tmp_version.${O} \ + ${LIBBIND} ${SYSLIBS} + +tmp_version.${O}: tmp_version.c + +tmp_version.c: version.c Makefile ../Makefile ${SRCS} ${HDRS} + (u=$${USER-root} d=`pwd` h=`${HOSTNAMECMD}` t=`date`; \ + sed -e "s|%WHEN%|$${t}|" -e "s|%VERSION%|"${VER}"|" \ + -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \ + < version.c > tmp_version.c) + +distclean: clean + +clean: FRC + rm -f ${PROG}${EXE} ${OBJS} core .depend + rm -f *.BAK *.CKP *~ *.orig + rm -f tmp_version.c tmp_version.${O} + +depend: ${SRCS} + mkdep ${CPPFLAGS} -I${INCL} -I${PORTINCL} -I${TOP}/lib/irs ${DEFS} ${SRCS} + +${DESTDIR}${DESTSBIN}: + mkdir -p ${DESTDIR}${DESTSBIN} + +install: ${DESTDIR}${DESTSBIN} ${PROG}${EXE} + ${INSTALL} ${STRIP} -c -m 755 ${PROG}${EXE} ${DESTDIR}${DESTSBIN}/${PROG}${EXE} + +links: FRC + @ln -s SRC/*.[chy] SRC/test .; rm -f ns_parser.[ch] + +tags: FRC + ctags ${SRCS} *.h + +FRC: + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. diff --git a/contrib/bind/bin/irpd/irpd.c b/contrib/bind/bin/irpd/irpd.c new file mode 100644 index 0000000..a2b13cb --- /dev/null +++ b/contrib/bind/bin/irpd/irpd.c @@ -0,0 +1,2252 @@ +/* + * 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. + */ + +/* Notes. */ + +#if 0 + +I have to use an AF_INET. Ctl_server should probably take a AF arugment. + +The server has no way to issue any other greeting than HELLO. E.g., would +like to be able to drop connection on greeting if client is not comming +from 127.0.0.1. + +Need to fix client to handle response with body. + +should add iovec with body to the struct ctl_sess? + +should we close connections on some errors (like marshalling errors)? + +getnetbyname falls back to /etc/networks when named not running. Does not +seem to be so for getnetbyaddr + +#endif + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: irpd.c,v 1.7 1999/10/13 16:26:23 vixie Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* Imports. */ + +#include "port_before.h" + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> + +#include <assert.h> +#include <ctype.h> +#include <ctype.h> +#include <errno.h> +#include <grp.h> +#include <netdb.h> +#include <pwd.h> +#include <pwd.h> +#include <resolv.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <unistd.h> +#include <utmp.h> + +#ifdef EMPTY +/* Digital UNIX utmp.h defines this. */ +#undef EMPTY +#endif + +#include <isc/ctl.h> +#include <isc/assertions.h> +#include <isc/list.h> +#include <isc/memcluster.h> +#include <isc/logging.h> + +#include <irs.h> +#include <irp.h> +#include <isc/irpmarshall.h> +#include <irs_data.h> + +#include "port_after.h" + +/* Macros. */ + +#define ALLDIGITS(s) (strspn((s), "0123456789") == strlen((s))) + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 256 +#endif + +#define MAXNETNAMELEN 256 + +#if !defined(SUN_LEN) +#define SUN_LEN(su) \ + (sizeof (*(su)) - sizeof ((su)->sun_path) + strlen((su)->sun_path)) +#endif + +/* + * This macro is used to initialize a specified field of a net_data struct. + * If the initialization fails then an error response code is sent with a + * description of which field failed to be initialized. + * + * This is only meant for use at the start of the various verb functions. + */ + +#define ND_INIT(nd, field, sess, respcode) \ + do{ if ((nd)->field == 0) { \ + (nd)->field = (*(nd)->irs->field ## _map)(nd->irs); \ + if ((nd)->field == 0) { \ + char *msg = "net_data " #field " initialization failed"; \ + ctl_response(sess, respcode, msg, CTL_EXIT, NULL, \ + NULL, NULL, NULL, 0); \ + return; \ + } \ + } \ + } while (0) + +/* Data structures. */ + +struct arg_s { + struct iovec * iov; + int iovlen; +}; + +struct response_buff { + char * buff; + size_t bufflen; +}; + +struct client_ctx { + struct net_data * net_data; +}; + +/* Forwards. */ + +static struct response_buff *newbuffer(u_int length); +static void release_buffer(struct response_buff *b); +static struct arg_s *split_string(const char *string); +static void free_args(struct arg_s *args); +static int is_all_digits(char *p); +static struct client_ctx *make_cli_ctx(void); +static struct net_data *get_net_data(struct ctl_sess *sess); + +static void irpd_gethostbyname(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_gethostbyname2(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_gethostbyaddr(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_gethostent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_sethostent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_getpwnam(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_getpwuid(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_getpwent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_setpwent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_getnetbyname(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_getnetbyaddr(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_getnetent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_setnetent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_getgrnam(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_getgrgid(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_getgrent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_setgrent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_getservbyname(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_getservbyport(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_getservent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_setservent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_getprotobyname(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_getprotobynumber(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_getprotoent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_setprotoent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_getnetgrent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_innetgr(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_setnetgrent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_endnetgrent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_quit(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_help(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_accept(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); +static void irpd_abort(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx); + +static void irpd_done(struct ctl_sctx *ctx, struct ctl_sess *sess, + void *param); +static void response_done(struct ctl_sctx *ctx, struct ctl_sess *sess, + void *uap); +static void logger(enum ctl_severity, const char *fmt, ...); + +/* Constants. */ + +static const u_int hello_code = IRPD_WELCOME_CODE; +static const char hello_msg[] = "Welcome to IRPD (v 1)"; +static const u_int unkncode = 500; +static const u_int timeoutcode = 501; +static const u_int irpd_quit_ok = 201; +static const u_int timeout = IRPD_TIMEOUT; + +/* Globals. */ + +static int main_needs_exit = 0; +static evContext ev; + +struct ctl_verb verbs [] = { + { "gethostbyname", irpd_gethostbyname }, + { "gethostbyname2", irpd_gethostbyname2 }, + { "gethostbyaddr", irpd_gethostbyaddr }, + { "gethostent", irpd_gethostent }, + { "sethostent", irpd_sethostent }, +#ifdef WANT_IRS_PW + { "getpwnam", irpd_getpwnam }, + { "getpwuid", irpd_getpwuid }, + { "getpwent", irpd_getpwent }, + { "setpwent", irpd_setpwent }, +#endif + { "getnetbyname", irpd_getnetbyname }, + { "getnetbyaddr", irpd_getnetbyaddr }, + { "getnetent", irpd_getnetent }, + { "setnetent", irpd_setnetent }, +#ifdef WANT_IRS_GR + { "getgrnam", irpd_getgrnam }, + { "getgrgid", irpd_getgrgid }, + { "getgrent", irpd_getgrent }, + { "setgrent", irpd_setgrent }, +#endif + { "getservbyname", irpd_getservbyname }, + { "getservbyport", irpd_getservbyport }, + { "getservent", irpd_getservent }, + { "setservent", irpd_setservent }, + + { "getprotobyname", irpd_getprotobyname }, + { "getprotobynumber", irpd_getprotobynumber }, + { "getprotoent", irpd_getprotoent }, + { "setprotoent", irpd_setprotoent }, + + { "getnetgrent", irpd_getnetgrent }, + { "innetgr", irpd_innetgr }, + { "setnetgrent", irpd_setnetgrent }, + { "endnetgrent", irpd_endnetgrent }, + { "quit", irpd_quit }, + { "help", irpd_help }, + + { "", irpd_accept }, /* For connection setups. */ + + /* abort is a verb expected by the ctl library. Is called when the + * client drops the connection unexpectedly. + */ + { "abort", irpd_abort }, + + { NULL, NULL } +}; + +/* + * An empty string causes the library to use the compiled in + * defaults and to ignore any external files. + */ +char *conffile = ""; + +/* Public. */ + +int +main(int argc, char **argv) { + struct ctl_sctx *ctx; + struct sockaddr *addr; + struct sockaddr_un uaddr; + struct sockaddr_in iaddr; + log_channel chan; + short port = IRPD_PORT; + char *prog = argv[0]; + char *sockname = IRPD_PATH; + char *p; + int ch; + size_t socksize; + + addr = (struct sockaddr *)&iaddr; + socksize = sizeof iaddr; + + openlog("iprd", LOG_CONS|LOG_PID, LOG_DAEMON); + while ((ch = getopt(argc, argv, "u:p:c:")) != -1) { + switch(ch) { + case 'c': + conffile = optarg; + break; + + case 'p': + port = strtol(optarg, &p, 10); + if (*p != '\0') { + /* junk in argument */ + syslog(LOG_ERR, "port option not a number"); + exit(1); + } + break; + + case 'u': + sockname = optarg; + addr = (struct sockaddr *)&uaddr; + socksize = sizeof uaddr; + break; + + case 'h': + case '?': + default: + fprintf(stderr, "%s [ -c config-file ]\n", prog); + exit(1); + } + } + argc -= optind; + argv += optind; + + memset(&uaddr, 0, sizeof uaddr); + memset(&iaddr, 0, sizeof iaddr); + +#ifdef HAVE_SA_LEN + iaddr.sin_len = sizeof iaddr; +#endif + iaddr.sin_family = AF_INET; + iaddr.sin_port = htons(IRPD_PORT); + iaddr.sin_addr.s_addr = htonl(INADDR_ANY); + + uaddr.sun_family = AF_UNIX; + strncpy(uaddr.sun_path, sockname, sizeof uaddr.sun_path); +#ifdef HAVE_SA_LEN + uaddr.sun_len = SUN_LEN(&uaddr); +#endif + + if (addr == (struct sockaddr *)&uaddr) + socksize = SUN_LEN(&uaddr); + + /* XXX what if this file is not currently a socket? */ + unlink(sockname); + + evCreate(&ev); + + ctx = ctl_server(ev, addr, socksize, verbs, + unkncode, timeoutcode, /* IRPD_TIMEOUT */ 30, 5, + IRPD_MAXSESS, logger, NULL); + + INSIST(ctx != NULL); + + while (!main_needs_exit) { + evEvent event; + + INSIST_ERR(evGetNext(ev, &event, EV_WAIT) != -1); + INSIST_ERR(evDispatch(ev, event) != -1); + } + + return (0); +} + + +/* + * static void + * simple_response(struct ctl_sess *sess, u_int code, char *msg); + * Send back a simple, one-line response to the client. + */ +static void +simple_response(struct ctl_sess *sess, u_int code, char *msg) { + struct response_buff *b = newbuffer(strlen(msg) + 1); + + if (b == 0) + return; + strcpy(b->buff, msg); + ctl_response(sess, code, b->buff, 0, 0, response_done, b, NULL, 0); +} + +/* + * static void + * send_hostent(struct ctl_sess *sess, struct hostent *ho); + * Send a hostent struct over the wire. If HO is NULL, then + * a "No such host" is sent instead. + */ +static void +send_hostent(struct ctl_sess *sess, struct hostent *ho) { + if (ho == NULL) + simple_response(sess, IRPD_GETHOST_NONE, "No such host"); + else { + size_t need; + struct response_buff *b = newbuffer(0); + + if (irp_marshall_ho(ho, &b->buff, &b->bufflen) != 0) { + simple_response(sess, IRPD_GETHOST_ERROR, + "Internal error"); + logger(ctl_warning, + "Cannot marshall host data for %s\n", + ho->h_name); + release_buffer(b); + } else { + strcat(b->buff, "\r\n"); + + ctl_response(sess, IRPD_GETHOST_OK, "Host found", + 0, 0, response_done, + b, b->buff, strlen(b->buff)); + } + } +} + +/* + * static void + * do_gethostbyname2(struct ctl_sess *sess, struct net_data *nd, + * const char *hostname, int af); + * Look up the given HOSTNAME by Address-Family + * and then send the results to the client connected to + * SESS. + */ +static void +do_gethostbyname2(struct ctl_sess *sess, struct net_data *nd, + const char *hostname, int af) +{ + struct hostent *ho; + + ho = gethostbyname2_p(hostname, af, nd); + send_hostent(sess, ho); +} + +/* + * static void + * irpd_gethostbyname(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Implementation of the GETHOSTBYNAME verb. + */ +static void +irpd_gethostbyname(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + char hname[MAXHOSTNAMELEN]; + struct arg_s *args; + int i; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, ho, sess, IRPD_GETHOST_ERROR); + + args = split_string(rest); + if (args->iovlen != 2) { /* len includes NULL at end */ + simple_response(sess, IRPD_GETHOST_ERROR, + "Incorrect usage: GETHOSTBYNAME hostname"); + } else { + if (args->iov[0].iov_len >= sizeof hname) { + simple_response(sess, IRPD_GETHOST_ERROR, + "GETHOSTBYNAME: name too long"); + } else { + strncpy(hname, args->iov[0].iov_base, + args->iov[0].iov_len); + hname[args->iov[0].iov_len] = '\0'; + do_gethostbyname2(sess, netdata, hname, AF_INET); + } + } + free_args(args); +} + +/* + * static void + * irpd_gethostbyname2(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Implementation of the GETHOSTBYNAME2 verb. + */ +static void +irpd_gethostbyname2(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + char hname[MAXHOSTNAMELEN]; + struct arg_s *args; + int i; + int af; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, ho, sess, IRPD_GETHOST_ERROR); + + args = split_string(rest); + if (args->iovlen != 3) { /* len includes NULL at end */ + simple_response(sess, IRPD_GETHOST_ERROR, + "Incorrect usage: GETHOSTBYNAME2 hostname AF"); + } else if (args->iov[0].iov_len >= sizeof hname) { + simple_response(sess, IRPD_GETHOST_ERROR, + "GETHOSTBYNAME2: name too long"); + } else { + if (strncasecmp(args->iov[1].iov_base, "af_inet6", 8) == 0) + af = AF_INET6; + else if (strncasecmp(args->iov[1].iov_base, "af_inet", 7) == 0) + af = AF_INET; + else { + simple_response(sess, IRPD_GETHOST_ERROR, + "Unknown address family"); + goto untimely; + } + + strncpy(hname, args->iov[0].iov_base, + args->iov[0].iov_len); + hname[args->iov[0].iov_len] = '\0'; + do_gethostbyname2(sess, netdata, hname, af); + } + + untimely: + free_args(args); +} + +/* + * static void + * irpd_gethostbyaddr(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Implementation of the GETHOSTBYADDR verb. + */ +static void +irpd_gethostbyaddr(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct hostent *ho; + char haddr[MAXHOSTNAMELEN]; + char tmpaddr[NS_IN6ADDRSZ]; + struct arg_s *args; + int i; + int af; + int addrlen; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, ho, sess, IRPD_GETHOST_ERROR); + + args = split_string(rest); + if (args->iovlen != 3) { + simple_response(sess, IRPD_GETHOST_ERROR, + "GETHOSTBYADDR addr afamily"); + } else { + if (args->iov[0].iov_len >= sizeof haddr) { + simple_response(sess, IRPD_GETHOST_ERROR, + "Address too long"); + } else { + strncpy(haddr, args->iov[1].iov_base, + args->iov[1].iov_len); + haddr[args->iov[1].iov_len] = '\0'; + if (strcasecmp(haddr, "af_inet") == 0) { + af = AF_INET; + addrlen = NS_INADDRSZ; + } else if (strcasecmp(haddr, "af_inet6") == 0) { + af = AF_INET6; + addrlen = NS_IN6ADDRSZ; + } else { + simple_response(sess, IRPD_GETHOST_ERROR, + "Unknown address family"); + goto untimely; + } + + strncpy(haddr, args->iov[0].iov_base, + args->iov[0].iov_len); + haddr[args->iov[0].iov_len] = '\0'; + + if (inet_pton(af, haddr, tmpaddr) != 1) { + simple_response(sess, IRPD_GETHOST_ERROR, + "Invalid address"); + goto untimely; + } + + ho = gethostbyaddr_p(tmpaddr, addrlen, af, netdata); + send_hostent(sess, ho); + } + } + + untimely: + free_args(args); +} + + +/* + * static void + * irpd_gethostent(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Implementation of the GETHOSTENT verb + */ +static void +irpd_gethostent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct hostent *ho; + size_t need; + size_t need_total = 0; + struct response_buff *b; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, ho, sess, IRPD_GETHOST_ERROR); + + ho = gethostent_p(netdata); + + send_hostent(sess, ho); +} + +/* + * static void + * irpd_sethostent(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Implementation of the SETHOSTENT verb + */ +static void +irpd_sethostent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct hostent *ho; + size_t need; + size_t need_total = 0; + struct response_buff *b; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, ho, sess, IRPD_GETHOST_ERROR); + + sethostent_p(1, netdata); /* always stayopen */ + simple_response(sess, IRPD_GETHOST_SETOK, "ok"); +} + +#ifdef WANT_IRS_PW +/* + * static void + * send_pwent(struct ctl_sess *sess, struct passwd *pw); + * Send PW over the wire, or, if PW is NULL, a "No such + * user" response. + */ +static void +send_pwent(struct ctl_sess *sess, struct passwd *pw) { + if (pw == NULL) { + simple_response(sess, IRPD_GETUSER_NONE, + "No such user"); + } else { + struct response_buff *b = newbuffer(0); + + if (irp_marshall_pw(pw, &b->buff, + &b->bufflen) != 0) { + simple_response(sess, IRPD_GETUSER_ERROR, + "Internal error"); + logger(ctl_warning, "Cant marshall pw\n"); + return; + } + + strcat(b->buff, "\r\n"); + + ctl_response(sess, IRPD_GETUSER_OK, "User found", 0, 0, + response_done, b, b->buff, strlen(b->buff)); + } +} + +/* + * static void + * irpd_getpwnam(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Implementation of the GETPWNAM verb + */ +static void +irpd_getpwnam(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct arg_s *args; + struct passwd *pw; + char username[64]; + struct response_buff *b; + size_t need; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, pw, sess, IRPD_GETUSER_ERROR); + + args = split_string(rest); + if (args->iovlen != 2) { /* len includes NULL at end */ + simple_response(sess, IRPD_GETUSER_ERROR, + "GETPWNAM username"); + } else { + if (args->iov[0].iov_len >= sizeof username) { + simple_response(sess, IRPD_GETUSER_ERROR, + "Name too long"); + } else { + strncpy(username, args->iov[0].iov_base, + args->iov[0].iov_len); + username[args->iov[0].iov_len] = '\0'; + + pw = getpwnam_p(username, netdata); + send_pwent(sess, pw); + } + } + + free_args(args); +} + +/* + * static void + * irpd_getpwuid(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Implementation of the GETPWUID verb. + */ +static void +irpd_getpwuid(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct arg_s *args; + struct passwd *pw; + char userid[64]; + struct response_buff *b; + size_t need; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, pw, sess, IRPD_GETUSER_ERROR); + + args = split_string(rest); + if (args->iovlen != 2) { /* len includes NULL at end */ + simple_response(sess, IRPD_GETUSER_ERROR, + "GETPWUID uid"); + } else { + if (args->iov[0].iov_len >= sizeof userid) { + simple_response(sess, IRPD_GETUSER_ERROR, + "Name too long"); + } else { + strncpy(userid, args->iov[0].iov_base, + args->iov[0].iov_len); + userid[args->iov[0].iov_len] = '\0'; + + if (!ALLDIGITS(userid)) { + simple_response(sess, IRPD_GETUSER_ERROR, + "Not a uid"); + } else { + uid_t uid; + long lval; + + lval = strtol(userid, 0, 10); + uid = (uid_t)lval; + if ((long)uid != lval) { + /* value was too big */ + simple_response(sess, + IRPD_GETUSER_ERROR, + "Not a valid uid"); + goto untimely; + } + + pw = getpwuid_p(uid, netdata); + send_pwent(sess, pw); + } + } + } + + untimely: + free_args(args); +} + +/* + * static void + * irpd_getpwent(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Implemtnation of the GETPWENT verb. + */ +static void +irpd_getpwent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct passwd *pw; + size_t need; + size_t need_total = 0; + struct response_buff *b; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, pw, sess, IRPD_GETUSER_ERROR); + + pw = getpwent_p(netdata); + send_pwent(sess, pw); +} + +/* + * static void + * irpd_setpwent(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Implemtnation of the SETPWENT verb. + */ +static void +irpd_setpwent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct passwd *pw; + size_t need; + size_t need_total = 0; + struct response_buff *b; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, pw, sess, IRPD_GETUSER_ERROR); + + setpwent_p(netdata); + simple_response(sess, IRPD_GETUSER_SETOK, "ok"); +} +#endif /* WANT_IRS_PW */ + +/* + * static void + * send_nwent(struct ctl_sess *sess, struct nwent *ne); + * Sends a nwent structure over the wire, or "No such + * network" if NE is NULL. + */ +static void +send_nwent(struct ctl_sess *sess, struct nwent *nw) { + if (nw == NULL) { + simple_response(sess, IRPD_GETNET_NONE, "No such net"); + } else { + struct response_buff *b = newbuffer(0); + + if (irp_marshall_nw(nw, &b->buff, + &b->bufflen) != 0) { + simple_response(sess, IRPD_GETNET_ERROR, + "Internal error"); + logger(ctl_warning, "Cant marshall nw\n"); + return; + } + + strcat(b->buff, "\r\n"); + + ctl_response(sess, IRPD_GETNET_OK, "Network found", 0, 0, + response_done, b, b->buff, strlen(b->buff)); + } +} + +/* + * static void + * send_netent(struct ctl_sess *sess, struct netent *ne); + * Sends a NETENT structure over the wire, or "No such + * Network" error if NE is NULL. + */ +static void +send_netent(struct ctl_sess *sess, struct netent *ne) { + if (ne == NULL) { + simple_response(sess, IRPD_GETNET_NONE, "No such net"); + } else { + struct response_buff *b = newbuffer(0); + + if (irp_marshall_ne(ne, &b->buff, + &b->bufflen) != 0) { + simple_response(sess, IRPD_GETNET_ERROR, + "Internal error"); + logger(ctl_warning, "Cant marshall ne\n"); + return; + } + + strcat(b->buff, "\r\n"); + + ctl_response(sess, IRPD_GETNET_OK, "Network found", 0, 0, + response_done, b, b->buff, strlen(b->buff)); + } +} + +/* + * static void + * irpd_getnetbyname(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Implementation of GETNETBYNAME verb. + */ +static void +irpd_getnetbyname(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct arg_s *args; + struct netent *ne; + struct nwent *nw; + char netname[MAXNETNAMELEN]; + struct response_buff *b; + size_t need; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, nw, sess, IRPD_GETNET_ERROR); + + args = split_string(rest); + if (args->iovlen != 2) { /* len includes NULL at end */ + simple_response(sess, IRPD_GETNET_ERROR, + "GETNETBYNAME name"); + } else { + if (args->iov[0].iov_len >= sizeof netname) { + simple_response(sess, IRPD_GETNET_ERROR, + "Name too long"); + } else { + strncpy(netname, args->iov[0].iov_base, + args->iov[0].iov_len); + netname[args->iov[0].iov_len] = '\0'; + + ne = getnetbyname_p(netname, netdata); + + /* The public interface only gives us a struct + netent, and we need a struct nwent that irs uses + internally, so we go dig it out ourselves. Yuk + */ + nw = NULL; + if (ne != NULL) { + /* Puke. */ + INSIST(netdata->nw_last == ne); + nw = netdata->nww_last; + } + + send_nwent(sess, nw); + } + } + free_args(args); +} + +/* + * static void + * irpd_getnetbyaddr(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + */ +static void +irpd_getnetbyaddr(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct netent *ne; + struct nwent *nw; + char haddr[MAXHOSTNAMELEN]; + long tmpaddr; + struct arg_s *args; + int i; + int af; + int addrlen; + int bits; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, nw, sess, IRPD_GETUSER_ERROR); + + args = split_string(rest); + if (args->iovlen != 3) { + simple_response(sess, IRPD_GETNET_ERROR, + "GETNETBYADDR addr afamily"); + } else { + if (args->iov[0].iov_len >= sizeof haddr) { + simple_response(sess, IRPD_GETNET_ERROR, + "Address too long"); + } else { + strncpy(haddr, args->iov[1].iov_base, + args->iov[1].iov_len); + haddr[args->iov[1].iov_len] = '\0'; + if (strcasecmp(haddr, "af_inet") == 0) { + af = AF_INET; + addrlen = NS_INADDRSZ; + } else if (strcasecmp(haddr, "af_inet6") == 0) { + af = AF_INET6; + addrlen = NS_IN6ADDRSZ; + + /* XXX the interface we use(getnetbyaddr) + * can't handle AF_INET6, so for now we + * bail. + */ + simple_response(sess, IRPD_GETNET_ERROR, + "AF_INET6 unsupported"); + goto untimely; + } else { + simple_response(sess, IRPD_GETNET_ERROR, + "Unknown address family"); + goto untimely; + } + + strncpy(haddr, args->iov[0].iov_base, + args->iov[0].iov_len); + haddr[args->iov[0].iov_len] = '\0'; + + bits = inet_net_pton(af, haddr, + &tmpaddr, sizeof tmpaddr); + if (bits < 0) { + simple_response(sess, IRPD_GETNET_ERROR, + "Invalid address"); + goto untimely; + } + + ne = getnetbyaddr_p(tmpaddr, af, netdata); + + /* The public interface only gives us a struct + netent, and we need a struct nwent that irs uses + internally, so we go dig it out ourselves. Yuk + */ + nw = NULL; + if (ne != NULL) { + /* Puke puke */ + INSIST(netdata->nw_last == ne); + nw = netdata->nww_last; + } + + send_nwent(sess, nw); + } + } + + untimely: + free_args(args); +} + + +/* + * static void + * irpd_getnetent(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Implementation of the GETNETENT verb. + */ +static void +irpd_getnetent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct netent *ne; + struct nwent *nw; + size_t need; + size_t need_total = 0; + struct response_buff *b; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, nw, sess, IRPD_GETNET_ERROR); + + ne = getnetent_p(netdata); + nw = NULL; + if (ne != NULL) { + /* triple puke */ + INSIST(netdata->nw_last == ne); + nw = netdata->nww_last; + } + send_nwent(sess, nw); +} + +/* + * static void + * irpd_setnetent(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Implementation of the SETNETENT verb. + */ +static void +irpd_setnetent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct netent *ne; + struct nwent *nw; + size_t need; + size_t need_total = 0; + struct response_buff *b; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, nw, sess, IRPD_GETNET_ERROR); + + setnetent_p(1, netdata); /* always stayopen */ + simple_response(sess, IRPD_GETNET_SETOK, "ok"); +} + +#ifdef WANT_IRS_GR +/* + * static void + * send_grent(struct ctl_sess *sess, struct group *gr); + * Marshall GR and send as body of response. If GR is NULL + * then a "No such group" response is sent instead. + */ +static void +send_grent(struct ctl_sess *sess, struct group *gr) { + if (gr == NULL) { + simple_response(sess, IRPD_GETGROUP_NONE, + "No such user"); + } else { + struct response_buff *b = newbuffer(0); + + if (irp_marshall_gr(gr, &b->buff, &b->bufflen) != 0) { + simple_response(sess, IRPD_GETGROUP_ERROR, + "Internal error"); + logger(ctl_warning, "Cant marshall gr\n"); + return; + } + + strcat(b->buff, "\r\n"); + + ctl_response(sess, IRPD_GETGROUP_OK, "Group found", 0, 0, + response_done, b, b->buff, strlen(b->buff)); + } +} + +/* + * static void + * irpd_getgrnam(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Implementation of the GETGRNAM verb. + */ +static void +irpd_getgrnam(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct arg_s *args; + struct group *gr; + char groupname[64]; + struct response_buff *b; + size_t need; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, gr, sess, IRPD_GETGROUP_ERROR); + + args = split_string(rest); + if (args->iovlen != 2) { /* len includes NULL at end */ + simple_response(sess, IRPD_GETGROUP_ERROR, + "GETGRNAM groupname"); + } else { + if (args->iov[0].iov_len >= sizeof groupname) { + simple_response(sess, IRPD_GETGROUP_ERROR, + "Name too long"); + } else { + strncpy(groupname, args->iov[0].iov_base, + args->iov[0].iov_len); + groupname[args->iov[0].iov_len] = '\0'; + + gr = getgrnam_p(groupname, netdata); + send_grent(sess, gr); + } + } + + free_args(args); +} + +/* + * static void + * irpd_getgrgid(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Implentation of the GETGRGID verb. + */ +static void +irpd_getgrgid(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct arg_s *args; + struct group *gr; + char groupid[64]; + struct response_buff *b; + size_t need; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, gr, sess, IRPD_GETGROUP_ERROR); + + args = split_string(rest); + if (args->iovlen != 2) { /* len includes NULL at end */ + simple_response(sess, IRPD_GETGROUP_ERROR, + "GETGRUID gid"); + } else { + if (args->iov[0].iov_len >= sizeof groupid) { + simple_response(sess, IRPD_GETGROUP_ERROR, + "Name too long"); + } else { + strncpy(groupid, args->iov[0].iov_base, + args->iov[0].iov_len); + groupid[args->iov[0].iov_len] = '\0'; + + if (!ALLDIGITS(groupid)) { + simple_response(sess, IRPD_GETGROUP_ERROR, + "Not a gid"); + } else { + gid_t gid; + long lval; + + lval = strtol(groupid, 0, 10); + gid = (gid_t)lval; + if ((long)gid != lval) { + /* value was too big */ + simple_response(sess, + IRPD_GETGROUP_ERROR, + "Not a valid gid"); + goto untimely; + } + + gr = getgrgid_p(gid, netdata); + send_grent(sess, gr); + } + } + } + + untimely: + free_args(args); +} + +/* + * static void + * irpd_getgrent(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Implementation of the GETGRENT verb. + */ +static void +irpd_getgrent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct group *gr; + size_t need; + size_t need_total = 0; + struct response_buff *b; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, gr, sess, IRPD_GETGROUP_ERROR); + + gr = getgrent_p(netdata); + send_grent(sess, gr); +} + +/* + * static void + * irpd_setgrent(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Implementation of the SETGRENT verb. + */ +static void +irpd_setgrent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct group *gr; + size_t need; + size_t need_total = 0; + struct response_buff *b; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, gr, sess, IRPD_GETGROUP_ERROR); + + setgrent_p(netdata); + simple_response(sess, IRPD_GETGROUP_SETOK, "ok"); +} +#endif /* WANT_IRS_GR */ + +static void +send_servent(struct ctl_sess *sess, struct servent *serv) { + if (serv == NULL) { + simple_response(sess, IRPD_GETSERVICE_NONE, + "No such service"); + } else { + struct response_buff *b = newbuffer(0); + + if (irp_marshall_sv(serv, &b->buff, + &b->bufflen) != 0) { + simple_response(sess, IRPD_GETSERVICE_ERROR, + "Internal error"); + logger(ctl_warning, "Cant marshall servent\n"); + return; + } + + strcat(b->buff, "\r\n"); + + ctl_response(sess, IRPD_GETSERVICE_OK, "Service found", 0, 0, + response_done, b, b->buff, strlen(b->buff)); + } +} + +static void +irpd_getservbyname(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct arg_s *args; + struct servent *serv; + char servicename[64]; + char protoname[10]; + struct response_buff *b; + size_t need; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, sv, sess, IRPD_GETSERVICE_ERROR); + + args = split_string(rest); + if (args->iovlen != 3) { /* len includes NULL at end */ + simple_response(sess, IRPD_GETSERVICE_ERROR, + "GETSERVNAM servicename protocol"); + } else { + if (args->iov[0].iov_len >= sizeof servicename) { + simple_response(sess, IRPD_GETSERVICE_ERROR, + "Invalid service name"); + } else if (args->iov[1].iov_len >= sizeof protoname) { + simple_response(sess, IRPD_GETSERVICE_ERROR, + "Invalid protocol name"); + } else { + strncpy(servicename, args->iov[0].iov_base, + args->iov[0].iov_len); + servicename[args->iov[0].iov_len] = '\0'; + + strncpy(protoname, args->iov[1].iov_base, + args->iov[1].iov_len); + protoname[args->iov[1].iov_len] = '\0'; + + serv = getservbyname_p(servicename, protoname, + netdata); + send_servent(sess, serv); + } + } + + free_args(args); +} + +/* + * static void + * irpd_getservbyport(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Handle the GETSERVBYPORT verb. + */ +static void +irpd_getservbyport(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct arg_s *args; + struct servent *sv; + char portnum[64]; + char protoname[10]; + struct response_buff *b; + size_t need; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, sv, sess, IRPD_GETSERVICE_ERROR); + + args = split_string(rest); + if (args->iovlen != 3) { /* len includes NULL at end */ + simple_response(sess, IRPD_GETSERVICE_ERROR, + "GETSERVBYPORT port protocol"); + } else { + if (args->iov[0].iov_len >= sizeof portnum) { + simple_response(sess, IRPD_GETSERVICE_ERROR, + "Invalid port"); + } else if (args->iov[1].iov_len > sizeof protoname - 1) { + simple_response(sess, IRPD_GETSERVICE_ERROR, + "Invalid protocol"); + } else { + strncpy(portnum, args->iov[0].iov_base, + args->iov[0].iov_len); + portnum[args->iov[0].iov_len] = '\0'; + + strncpy(protoname, args->iov[1].iov_base, + args->iov[1].iov_len); + protoname[args->iov[1].iov_len] = '\0'; + + if (!ALLDIGITS(portnum)) { + simple_response(sess, IRPD_GETSERVICE_ERROR, + "Not a port number"); + } else { + short port; + long lval; + + lval = strtol(portnum, 0, 10); + port = (short)lval; + if ((long)port != lval) { + /* value was too big */ + simple_response(sess, + IRPD_GETSERVICE_ERROR, + "Not a valid port"); + goto untimely; + } + port = htons(port); + + sv = getservbyport_p(port, protoname, netdata); + send_servent(sess, sv); + } + } + } + + untimely: + free_args(args); +} + +/* + * static void + * irpd_getservent(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Handle the GETSERVENT verb. + */ +static void +irpd_getservent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct servent *sv; + size_t need; + size_t need_total = 0; + struct response_buff *b; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, sv, sess, IRPD_GETSERVICE_ERROR); + + sv = getservent_p(netdata); + send_servent(sess, sv); +} + +/* + * static void + * irpd_setservent(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Handle the SETSERVENT verb. + */ +static void +irpd_setservent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct servent *sv; + size_t need; + size_t need_total = 0; + struct response_buff *b; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, sv, sess, IRPD_GETSERVICE_ERROR); + + setservent_p(1, netdata); /* always stay open */ + simple_response(sess, IRPD_GETSERVICE_SETOK, "ok"); +} + +/* + * static void + * send_prent(struct ctl_sess *sess, struct protoent *pr); + * Send the PR structure over the wire. If PR is NULL, then + * the response "No such protocol" is sent instead. + */ +static void +send_prent(struct ctl_sess *sess, struct protoent *pr) { + if (pr == NULL) { + simple_response(sess, IRPD_GETPROTO_NONE, + "No such protocol"); + } else { + struct response_buff *b = newbuffer(0); + + if (irp_marshall_pr(pr, &b->buff, + &b->bufflen) != 0) { + simple_response(sess, IRPD_GETPROTO_ERROR, + "Internal error"); + logger(ctl_warning, "Cant marshall pr\n"); + return; + } + + strcat(b->buff, "\r\n"); + + ctl_response(sess, IRPD_GETPROTO_OK, "Protocol found", 0, 0, + response_done, b, b->buff, strlen(b->buff)); + } +} + +/* + * static void + * irpd_getprotobyname(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Handle the GETPROTOBYNAME verb. + */ +static void +irpd_getprotobyname(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct arg_s *args; + struct protoent *pr; + char protoname[64]; + struct response_buff *b; + size_t need; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, pr, sess, IRPD_GETPROTO_ERROR); + + args = split_string(rest); + if (args->iovlen != 2) { /* len includes NULL at end */ + simple_response(sess, IRPD_GETPROTO_ERROR, + "GETPROTOBYNAME protocol"); + } else { + if (args->iov[0].iov_len >= sizeof protoname) { + simple_response(sess, IRPD_GETPROTO_ERROR, + "Name too long"); + } else { + strncpy(protoname, args->iov[0].iov_base, + args->iov[0].iov_len); + protoname[args->iov[0].iov_len] = '\0'; + + pr = getprotobyname_p(protoname, netdata); + send_prent(sess, pr); + } + } + free_args(args); +} + +/* + * static void + * irpd_getprotobynumber(struct ctl_sctx *ctx, + * struct ctl_sess *sess, const struct ctl_verb *verb, + * const char *rest, u_int respflags, void *respctx, + * void *uctx); + * Handle the GETPROTOBYNUMBER verb. + */ +static void +irpd_getprotobynumber(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct arg_s *args; + struct protoent *pr; + char protonum[64]; + struct response_buff *b; + size_t need; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, pr, sess, IRPD_GETPROTO_ERROR); + + args = split_string(rest); + if (args->iovlen != 2) { /* len includes NULL at end */ + simple_response(sess, IRPD_GETPROTO_ERROR, + "GETPROTOBYNUMBER protocol"); + } else { + if (args->iov[0].iov_len >= sizeof protonum) { + simple_response(sess, IRPD_GETGROUP_ERROR, + "Name too long"); + } else { + strncpy(protonum, args->iov[0].iov_base, + args->iov[0].iov_len); + protonum[args->iov[0].iov_len] = '\0'; + + if (!ALLDIGITS(protonum)) { + simple_response(sess, IRPD_GETPROTO_ERROR, + "Not a protocol number"); + } else { + int proto; + long lval; + + lval = strtol(protonum, 0, 10); + proto = (int)lval; + if ((long)proto != lval) { + /* value was too big */ + simple_response(sess, + IRPD_GETPROTO_ERROR, + "Not a valid proto"); + goto untimely; + } + + pr = getprotobynumber_p(proto, netdata); + send_prent(sess, pr); + } + } + } + + untimely: + free_args(args); +} + +/* + * static void + * irpd_getprotoent(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Handle the GETPROTOENT verb. + */ +static void +irpd_getprotoent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct protoent *pr; + size_t need; + size_t need_total = 0; + struct response_buff *b; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, pr, sess, IRPD_GETPROTO_ERROR); + + pr = getprotoent_p(netdata); + send_prent(sess, pr); +} + +/* + * static void + * irpd_setprotoent(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Handle the SETPROTOENT verb. + */ +static void +irpd_setprotoent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct protoent *pr; + size_t need; + size_t need_total = 0; + struct response_buff *b; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, pr, sess, IRPD_GETPROTO_ERROR); + + setprotoent_p(1, netdata); /* always stay open */ + simple_response(sess, IRPD_GETPROTO_SETOK, "ok"); +} + +/* + * static void + * send_pwent(struct ctl_sess *sess, struct passwd *pw); + * Send PW over the wire, or, if PW is NULL, a "No such + * user" response. + */ +static void +send_ngent(struct ctl_sess *sess, char *host, char *user, char *domain) { + struct response_buff *b = newbuffer(0); + + if (irp_marshall_ng(host, user, domain, &b->buff, + &b->bufflen) != 0) { + simple_response(sess, IRPD_GETNETGR_ERROR, + "Internal error"); + logger(ctl_warning, "Cant marshall ng\n"); + return; + } + + strcat(b->buff, "\r\n"); + + ctl_response(sess, IRPD_GETNETGR_OK, "Netgroup entry", 0, 0, + response_done, b, b->buff, strlen(b->buff)); +} + +/* + * static void + * irpd_getnetgrent(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Handle the GETNETGRENT verb. + */ +static void +irpd_getnetgrent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + char netgroupname[64]; + struct response_buff *b = NULL; + size_t need; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, ng, sess, IRPD_GETNETGR_ERROR); + + if (rest != NULL && strlen(rest) > 0) { + simple_response(sess, IRPD_GETNETGR_ERROR, + "GETNETGRENT"); + } else { + char *host, *user, *domain; + + if (getnetgrent_p(&host, &user, &domain, netdata) == 1) { + send_ngent(sess, host, user, domain); + } else { + simple_response(sess, IRPD_GETNETGR_NOMORE, + "No more"); + } + } +} + +/* + * static void + * irpd_innetgr(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Handle the INNETGR verb. + */ +static void +irpd_innetgr(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct arg_s *args; + struct response_buff *b; + size_t need; + struct net_data *netdata = get_net_data(sess); + char *host; + char *user; + char *domain; + + INSIST(netdata != NULL); + + ND_INIT(netdata, ng, sess, IRPD_GETNETGR_ERROR); + + args = split_string(rest); + if (args->iovlen != 3) { /* len includes NULL at end */ + simple_response(sess, IRPD_GETNETGR_ERROR, + "INNETGR netgroup ngentry"); + } else { + char *grptmp = memget(args->iov[0].iov_len + 1); + char *ngtmp = memget(args->iov[1].iov_len + 1); + + strncpy(grptmp, args->iov[0].iov_base, args->iov[0].iov_len); + strncpy(ngtmp, args->iov[1].iov_base, args->iov[1].iov_len); + + grptmp[args->iov[0].iov_len] = '\0'; + ngtmp[args->iov[1].iov_len] = '\0'; + + if (irp_unmarshall_ng(&host, &user, &domain, ngtmp) != 0) { + simple_response(sess, IRPD_GETNETGR_ERROR, + "ngentry must be (host,user,domain)"); + } else { + if (innetgr_p(grptmp, host, user, domain, + netdata) == 1) { + simple_response(sess, IRPD_GETNETGR_MATCHES, + "INNETGR matches"); + } else { + simple_response(sess, IRPD_GETNETGR_NOMATCH, + "INNETGR does not match"); + } + } + + memput(grptmp, args->iov[0].iov_len + 1); + memput(ngtmp, args->iov[1].iov_len + 1); + } + + untimely: + free_args(args); +} + +/* + * static void + * irpd_setnetgrent(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Handle the SETNETGRENT verb. + */ +static void +irpd_setnetgrent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct arg_s *args; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, ng, sess, IRPD_GETNETGR_ERROR); + + args = split_string(rest); + if (args->iovlen != 2) { /* len includes NULL at end */ + simple_response(sess, IRPD_GETNETGR_ERROR, + "setnetgrent netgroup"); + } else { + setnetgrent_p(rest, netdata); + simple_response(sess, IRPD_GETNETGR_SETOK, + "setnetgrent ok"); + } + + untimely: + free_args(args); +} + +/* + * static void + * irpd_endnetgrent(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Handle the ENDNETGRENT verb. + */ +static void +irpd_endnetgrent(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct arg_s *args; + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + ND_INIT(netdata, ng, sess, IRPD_GETNETGR_ERROR); + + if (rest != NULL && strlen (rest) > 0) { + simple_response(sess, IRPD_GETNETGR_ERROR, + "endnetgrent netgroup"); + } else { + endnetgrent_p(netdata); + simple_response(sess, IRPD_GETNETGR_SETOK, + "endnetgrent ok"); + } +} + +/* + * static void + * irpd_done(struct ctl_sctx *ctx, struct ctl_sess *sess, void *param) + * Callback for when QUIT respnse is sent out. + */ +static void +irpd_done(struct ctl_sctx *ctx, struct ctl_sess *sess, void *param) { + struct net_data *netdata = get_net_data(sess); + + INSIST(netdata != NULL); + + net_data_destroy(netdata); +} + +/* + * static void + * irpd_quit(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Handle the QUIT verb. + */ +static void +irpd_quit(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + ctl_response(sess, irpd_quit_ok, "See ya!", CTL_EXIT, NULL, + 0 , NULL, NULL, 0); +} + +/* + * static void + * irpd_help(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Handle the HELP verb. + */ +static void +irpd_help(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + /* XXX should make this do something better (like include required + * arguments. + */ + ctl_sendhelp(sess, 231); +} + +/* + * static void + * irpd_accept(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Handle a new connection. + */ +static void +irpd_accept(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct sockaddr *sa = respctx; + char raddr[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"]; + int reject = 1; + int response; + char *respmsg = NULL; + + if (sa->sa_family == AF_UNIX) { + syslog (LOG_INFO, "New AF_UNIX connection"); + reject = 0; + } else if (sa->sa_family == AF_INET) { + struct sockaddr_in *sin = respctx; + static long localhost; + static long zero; + + if (localhost == 0) { + /* yes, this could be done with simple arithmetic... */ + inet_pton(AF_INET, "127.0.0.1", &localhost); + } + + inet_ntop(AF_INET, &sin->sin_addr, raddr, sizeof raddr); + + /* we reject INET connections that are not from the local + * machine. + */ + if (sin->sin_addr.s_addr == zero || + sin->sin_addr.s_addr == localhost) { + reject = 0; + syslog(LOG_INFO, "New connection from %s", raddr); + } else { + syslog(LOG_INFO, "New connection from %s (reject)", + raddr); + respmsg = "Connections from off host not permitted"; + } + } else if (sa->sa_family == AF_INET6) { + /* XXX should do something intelligent here. */ + respmsg = "IPv6 connections not implemented yet."; + syslog(LOG_ERR, "Cannot handle AF_INET6 connections yet"); + } else { + syslog (LOG_ERR, "Unknown peer type: %d", sa->sa_family); + respmsg = "What are you???"; + } + + if (reject) { + response = IRPD_NOT_WELCOME_CODE; + if (respmsg == NULL) { + respmsg = "Go away!"; + } + /* XXX can we be sure that stacked up commands will not be + * processed before the control connection is closed??? + */ + } else { + void *ctx = make_cli_ctx(); + + if (ctx == NULL) { + response = IRPD_NOT_WELCOME_CODE; + respmsg = "Internal error (client context)"; + } else { + response = IRPD_WELCOME_CODE; + if (respmsg == NULL) { + respmsg = "Welcome to IRPD (v 1)"; + } + ctl_setcsctx(sess, ctx); + } + } + ctl_response(sess, response, respmsg, (reject ? CTL_EXIT : 0), NULL, + 0, NULL, NULL, 0); +} + +/* + * static void + * irpd_abort(struct ctl_sctx *ctx, struct ctl_sess *sess, + * const struct ctl_verb *verb, const char *rest, + * u_int respflags, void *respctx, void *uctx); + * Handle a dropped connection. + */ +static void +irpd_abort(struct ctl_sctx *ctx, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct net_data *netdata = get_net_data(sess); + + if (netdata != NULL) + net_data_destroy(netdata); +} + +/* + * void + * response_done(struct ctl_sctx *ctx, struct ctl_sess *sess, void *uap) + * UAP is the response_buffer passed through to + * ctl_response. + */ +static void +response_done(struct ctl_sctx *ctx, struct ctl_sess *sess, void *uap) { + release_buffer(uap); +} + +/* + * static void + * logger(enum ctl_severity sev, const char *fmt, ...); + * Logging routine called by the ctl_* functions. For now we + * just spit everything to stderr. + */ + +static void +logger(enum ctl_severity sev, const char *fmt, ...) { + char buffer[1024]; + va_list ap; + int level; + + if (sev == ctl_debug) + return; + + if (sev == ctl_warning) + level = LOG_WARNING; + else if (sev == ctl_error) + level = LOG_ERR; + else { + syslog(LOG_CRIT, "Invalid severity: %d", (int)sev); + exit(1); + } + + va_start(ap, fmt); + +#if 0 + fprintf(stderr, "irpd: "); + vfprintf(stderr, fmt, ap); +#else + if (vsprintf(buffer, fmt, ap) > (sizeof (buffer) - 1)) { + syslog(LOG_CRIT, "Buffer overrun in logger"); + abort(); + } + syslog(level, "%s", buffer); +#endif + va_end(ap); +} + +/* + * static struct response_buff * + * newbuffer(u_int length); + * Create a structure to hold an allocated buffer. We do + * this so we can get the size to deallocate later. + * Returns: + * Pointer to the structure + */ +static struct response_buff * +newbuffer(u_int length) { + struct response_buff *h; + + h = memget(sizeof *h); + if (h == NULL) { + errno = ENOMEM; + return (NULL); + } + + h->buff = NULL; + h->bufflen = length; + + if (length > 0) { + h->buff = memget(h->bufflen); + if (h->buff == NULL) { + memput(h, sizeof *h); + errno = ENOMEM; + return (NULL); + } + memset(h->buff, 0, h->bufflen); + } + + return (h); +} + +/* + * static void + * release_buffer(struct response_buff *b); + * Free up a buffer allocated with newbuffer. + */ +static void +release_buffer(struct response_buff *b) { + memset(b->buff, 0, b->bufflen); + memput(b->buff, b->bufflen); + + memset(b, 0, sizeof *b); + memput(b, sizeof *b); +} + +/* + * static struct arg_s * + * split_string(const char *string); + * Create an array of iovecs(last one having NULL fields) + * pointing into STRING at the non-whitespace sections. The + * iovecs are stashed inside a structure so we can get the + * size back later at deallocation time. Iovecs are used to avoid + * modifying the argument with added nulls. + * Returns: + * Pointer to the wrapper structure. Must be given to free_args() + * when done + */ +static struct arg_s * +split_string(const char *string) { + struct iovec *iovs; + const char *p; + int i, c, iswh; + struct arg_s *a; + + /* count + 1 of the number of runs of non-whitespace. */ + for (iswh = 1, i = 1, p = string ; p != NULL && *p ; p++) { + if (iswh && !isspace(*p)) { + iswh = 0; + i++; + } else if (!iswh && isspace(*p)) { + iswh = 1; + } + } + + iovs = memget(sizeof (struct iovec) * i); + if (iovs == NULL) { + errno = ENOMEM; + return (NULL); + } + + a = memget(sizeof *a); + if (a == NULL) { + errno = ENOMEM; + memput(iovs, sizeof (struct iovec) * i); + return (NULL); + } + a->iov = iovs; + a->iovlen = i; + + for (c = 0, p = string ; p != NULL && *p ; c++) { + while (isspace(*p)) { + p++; + } + + if (*p == '\0') + break; + + iovs[c].iov_base = (void *)p; + + while (*p && !isspace(*p)) { + p++; + } + iovs[c].iov_len = p - (char *)iovs[c].iov_base; + } + INSIST(c == i - 1); + iovs[c].iov_base = NULL; + iovs[c].iov_len = 0; + + return (a); +} + +/* + * static void + * free_args(struct arg_s *args); + * Free up the argument structure created with + * split_string(). + */ + +static void +free_args(struct arg_s *args) { + memput(args->iov, sizeof (struct iovec) * args->iovlen); + memput(args, sizeof *args); +} + +static struct client_ctx * +make_cli_ctx(void) { + struct client_ctx *p = memget (sizeof *p); + + if (p == NULL) + return (NULL); + + p->net_data = net_data_create(conffile); + + return (p); +} + +static void +release_cli_ctx(struct client_ctx *ctx) { + INSIST(ctx != NULL); + INSIST(ctx->net_data != NULL); + + net_data_destroy(ctx->net_data); + memput(ctx, sizeof *ctx); +} + +static struct net_data * +get_net_data(struct ctl_sess *sess) { + struct client_ctx *ctx = ctl_getcsctx(sess); + + INSIST(ctx != NULL); + INSIST(ctx->net_data != NULL); + + return (ctx->net_data); +} diff --git a/contrib/bind/bin/irpd/irs-irpd.conf b/contrib/bind/bin/irpd/irs-irpd.conf new file mode 100644 index 0000000..07385d3 --- /dev/null +++ b/contrib/bind/bin/irpd/irs-irpd.conf @@ -0,0 +1,11 @@ +# Private irs config file for irpd so that it doesn't get configured to +# talk to itself. +passwd local +group local +services local +protocols local +hosts dns continue +hosts local +networks dns continue +networks local +netgroup local diff --git a/contrib/bind/bin/irpd/version.c b/contrib/bind/bin/irpd/version.c new file mode 100644 index 0000000..cc42c0b --- /dev/null +++ b/contrib/bind/bin/irpd/version.c @@ -0,0 +1,25 @@ +/* + * 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. + */ + +#ifndef lint +char sccsid[] = "@(#)named %VERSION% %WHEN% %WHOANDWHERE%"; +char rcsid[] = "$Id: version.c,v 1.1 1999/01/18 07:47:17 vixie Exp $"; +#endif /* not lint */ + +char Version[] = "named %VERSION% %WHEN%\n\t%WHOANDWHERE%"; +char ShortVersion[] = "%VERSION%"; + diff --git a/contrib/bind/bin/mkservdb/Makefile b/contrib/bind/bin/mkservdb/Makefile new file mode 100644 index 0000000..47af236 --- /dev/null +++ b/contrib/bind/bin/mkservdb/Makefile @@ -0,0 +1,83 @@ +## 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: Makefile,v 1.6 1999/08/08 17:51:01 vixie Exp $ + +DESTDIR= +CC= cc +SHELL= /bin/sh + +CDEBUG= -g + +#(net2 and its descendents) +SYSTYPE = bsdos +TOP = ../.. +INCL = ${TOP}/include +PORTINCL = ${TOP}/port/${SYSTYPE}/include +LIBBIND = ${TOP}/lib/libbind.a +A=a +O=o +LEX = lex -I +SYSLIBS = -ll -lutil +DESTBIN = /usr/local/bin +DESTSBIN = /usr/local/sbin +DESTEXEC = /usr/local/libexec +DESTMAN = /usr/share/man +DESTHELP= /usr/share/misc +STRIP=-s +INSTALL_EXEC= +INSTALL_LIB=-o bin -g bin + +LDFLAGS= +CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL} + +PROG= mkservdb +SRCS= ${PROG}.c +OBJS= ${PROG}.${O} + +all: ${PROG}${EXE} + +${PROG}${EXE}: ${OBJS} ${LIBBIND} Makefile + ${CC} ${CDEBUG} ${LDFLAGS} ${BOUNDS} -o ${PROG}${EXE} ${OBJS} \ + ${LIBBIND} ${SYSLIBS} + +.c.${O}: + ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c + +distclean: clean + +clean: FRC + rm -f ${PROG}${EXE} ${OBJS} core .depend + rm -f *.BAK *.CKP *~ *.orig + +depend: ${SRCS} + mkdep ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS} + +${DESTDIR}${DESTBIN}: + mkdir -p ${DESTDIR}${DESTBIN} + +install: ${DESTDIR}${DESTBIN} ${PROG}${EXE} + ${INSTALL} ${STRIP} -c ${INSTALL_EXEC} -m 755 ${PROG}${EXE} ${DESTDIR}${DESTBIN}/${PROG}${EXE} + +links: FRC + @set -e; ln -s SRC/*.[ch] . + +tags: FRC + ctags *.[ch] + +FRC: + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. diff --git a/contrib/bind/bin/mkservdb/mkservdb.c b/contrib/bind/bin/mkservdb/mkservdb.c new file mode 100644 index 0000000..5647ec7 --- /dev/null +++ b/contrib/bind/bin/mkservdb/mkservdb.c @@ -0,0 +1,169 @@ +#if !defined(lint) && !defined(SABER) +static const char rcsid[] = "$Id: mkservdb.c,v 1.6 1999/10/13 16:39:00 vixie 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. + */ + +#include "port_before.h" + +#include <sys/types.h> +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <resolv.h> + +#include <ctype.h> +#ifdef IRS_LCL_SV_DB +#include <db.h> +#endif +#include <fcntl.h> +#include <limits.h> +#include <netdb.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "../../include/irs.h" +#include "../../lib/irs/irs_p.h" + +#include "port_after.h" + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) ((size_t)sprintf x) +#endif + +#ifndef IRS_LCL_SV_DB +main(int argc, char **argv) { + fprintf(stderr, "%s: not supported on this architecture\n", argv[0]); + exit(1); +} + +#else + +#define _PATH_SERVICES_DB_TMP _PATH_SERVICES_DB ".new" + +struct servent *getnextent(FILE *); + +main(int argc, char **argv) { + DB *db; + DBT key; + DBT data; + char *filename = _PATH_SERVICES; + char *tmpdatabase = _PATH_SERVICES_DB_TMP; + char *database = _PATH_SERVICES_DB; + char dbuf[1024]; + char kbuf[512]; + u_short *ports; + struct lcl_sv lcl_sv; + struct servent *sv; + int n, r; + char *p; + + unlink(tmpdatabase); + + if (argc > 1) + filename = argv[1]; + + lcl_sv.fp = fopen(filename, "r"); + if (lcl_sv.fp == NULL) + err(1, "%s", filename); + + db = dbopen(tmpdatabase, O_CREAT|O_RDWR, 0444, DB_BTREE, NULL); + if (db == NULL) + err(1, "%s", tmpdatabase); + + while ((sv = irs_lclsv_fnxt(&lcl_sv)) != NULL) { + if (sv->s_proto == NULL) + continue; + + key.data = kbuf; + data.data = dbuf; + + /* Note that (sizeof "/") == 2. */ + if (strlen(sv->s_name) + sizeof "/" + strlen(sv->s_proto) + > sizeof kbuf) + continue; + key.size = SPRINTF((kbuf, "%s/%s", sv->s_name, sv->s_proto))+1; + + ((u_short *)dbuf)[0] = sv->s_port; + p = dbuf; + p += sizeof(u_short); + if (sv->s_aliases) + for (n = 0; sv->s_aliases[n]; ++n) { + strcpy(p, sv->s_aliases[n]); + p += strlen(p) + 1; + } + data.size = p - dbuf; + + if ((r = db->put(db, &key, &data, R_NOOVERWRITE))) + if (r < 0) + errx(1, "failed to write %s", key.data); + else + warnx("will not overwrite %s", key.data); + for (n = 0; sv->s_aliases[n]; ++n) { + if (strlen(sv->s_aliases[n]) + sizeof "/" + + strlen(sv->s_proto) > sizeof kbuf) + continue; + key.size = SPRINTF((kbuf, "%s/%s", + sv->s_aliases[n], sv->s_proto))+1; + if ((r = db->put(db, &key, &data, R_NOOVERWRITE))) + if (r < 0) + errx(1, "failed to write %s", + key.data); + else + warnx("will not overwrite %s", + key.data); + } + + ports = (u_short *)kbuf; + ports[0] = 0; + ports[1] = sv->s_port; + strcpy((char *)(ports+2), sv->s_proto); + key.size = sizeof(u_short) * 2 + strlen((char *)(ports+2)) + 1; + + if (strlen(sv->s_name) + sizeof "/" + strlen(sv->s_proto) + > sizeof dbuf) + continue; + p = dbuf; + p += SPRINTF((p, "%s/%s", sv->s_name, sv->s_proto)) + 1; + if (sv->s_aliases != NULL) + for (n = 0; sv->s_aliases[n] != NULL; n++) + if ((p + strlen(sv->s_aliases[n]) + 1) - dbuf + <= sizeof dbuf) { + strcpy(p, sv->s_aliases[n]); + p += strlen(p) + 1; + } + data.size = p - dbuf; + + if ((r = db->put(db, &key, &data, R_NOOVERWRITE))) + if (r < 0) + errx(1, "failed to write %d/%s", + ntohs(sv->s_port), sv->s_proto); + else + warnx("will not overwrite %d/%s", + ntohs(sv->s_port), sv->s_proto); + } + db->close(db); + if (rename(tmpdatabase, database)) + err(1, "rename %s -> %s", tmpdatabase, database); + exit(0); +} + +#endif diff --git a/contrib/bind/bin/named-bootconf/Grot/named-bootconf.pl b/contrib/bind/bin/named-bootconf/Grot/named-bootconf.pl new file mode 100644 index 0000000..ce1b368 --- /dev/null +++ b/contrib/bind/bin/named-bootconf/Grot/named-bootconf.pl @@ -0,0 +1,324 @@ +#!/usr/bin/perl + +## 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: named-bootconf.pl,v 1.2 1999/01/08 19:27:35 vixie Exp $ + +# This is a filter. Input is a named.boot. Output is a named.conf. + +$new_config = ""; + +$have_options = 0; +%options = (); +%options_comments = (); +@topology = (); +@topology_comments = (); +@bogus = (); +@bogus_comments = (); +@transfer_acl = (); +@transfer_comments = (); +$logging = ""; + +while(<>) { + next if /^$/; + + # skip comment-only lines + if (/^\s*;+\s*(.*)$/) { + $new_config .= "// $1\n"; + next; + } + + # handle continued lines + while (/\\$/) { + s/\\$/ /; + $_ .= <>; + } + + chop; + + # deal with lines ending in a coment + if (s/\s*;+\s*(.*)$//) { + $comment = "// $1"; + } else { + $comment = ""; + } + + ($directive, @rest) = split; + + $class = ""; + if ($directive =~ /^(.*)\/(.*)$/) { + $directive = $1; + $class = $2; + } + + if ($directive eq "primary") { + $zname = shift(@rest); + &maybe_print_comment("","\n"); + $new_config .= "zone \"$zname\" "; + if ($class ne "") { + $new_config .= "$class "; + } + $new_config .= "{\n"; + $new_config .= "\ttype master;\n"; + $filename = shift(@rest); + $new_config .= "\tfile \"$filename\";\n"; + $new_config .= "};\n\n"; + } elsif ($directive eq "secondary" || $directive eq "stub") { + if ($directive eq "secondary") { + $type = "slave"; + } else { + $type = "stub"; + } + $zname = shift(@rest); + &maybe_print_comment("","\n"); + $new_config .= "zone \"$zname\" "; + if ($class ne "") { + $new_config .= "$class "; + } + $new_config .= "{\n"; + $new_config .= "\ttype $type;\n"; + $filename = pop(@rest); + if ($filename =~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/) { + push(@rest, $filename); + $filename = ""; + } else { + $new_config .= "\tfile \"$filename\";\n"; + } + $new_config .= "\tmasters {\n"; + foreach $master (@rest) { + $new_config .= "\t\t$master;\n"; + } + $new_config .= "\t};\n"; + $new_config .= "};\n\n"; + } elsif ($directive eq "cache") { + $zname = shift(@rest); + &maybe_print_comment("","\n"); + $new_config .= "zone \"$zname\" {\n"; + $new_config .= "\ttype hint;\n"; + $filename = shift(@rest); + $new_config .= "\tfile \"$filename\";\n"; + $new_config .= "};\n\n"; + } elsif ($directive eq "directory") { + $options{"directory"} = "\"$rest[0]\""; + $options_comments{"directory"} = $comment; + $have_options = 1; + } elsif ($directive eq "check-names") { + $type = shift(@rest); + if ($type eq "primary") { + $type = "master"; + } elsif ($type eq "secondary") { + $type = "slave"; + } + $action = shift(@rest); + $options{"check-names $type"} = $action; + $options_comments{"check-names $type"} = $comment; + $have_options = 1; + } elsif ($directive eq "forwarders") { + $options{"forwarders"}="{\n"; + foreach $forwarder (@rest) { + $options{"forwarders"} .= "\t\t$forwarder;\n"; + } + $options{"forwarders"} .= "\t}"; + $options_comments{"forwarders"} = $comment; + $have_options = 1; + } elsif ($directive eq "slave") { + &handle_options("forward-only"); + } elsif ($directive eq "options") { + &handle_options(@rest); + } elsif ($directive eq "limit") { + &handle_limit(@rest); + } elsif ($directive eq "include") { + $new_config .= + "// make sure your include is still in the right place\n"; + $comment = "\t" . $comment; + $new_config .= "include \"$rest[0]\";$comment\n\n"; + } elsif ($directive eq "xfrnets" || $directive eq "tcplist") { + if ($comment ne "") { + $comment = "\t$comment"; + } + foreach $elt (@rest) { + push(@transfer_acl, $elt); + push(@transfer_comments, $comment); + } + $have_options = 1; + } elsif ($directive eq "sortlist") { + if ($comment ne "") { + $comment = "\t$comment"; + } + foreach $elt (@rest) { + push(@topology, $elt); + push(@topology_comments, $comment); + } + } elsif ($directive eq "bogusns") { + if ($comment ne "") { + $comment = "\t$comment"; + } + foreach $elt (@rest) { + push(@bogus, $elt); + push(@bogus_comments, $comment); + } + } elsif ($directive eq "max-fetch") { + $options{"transfers-in"}=$rest[0]; + $options_comments{"transfers-in"}=$comment; + $have_options = 1; + } else { + $new_config .= "// NOTE: unconverted directive '$directive @rest'\n\n"; + } +} + +print "// generated by named-bootconf.pl\n\n"; +if ($have_options) { + print "options {\n"; + foreach $option (sort(keys(%options))) { + print "\t$option $options{$option};"; + if ($options_comments{$option} ne "") { + print "\t$options_comments{$option}"; + } + print "\n"; + } + if (@transfer_acl > 0) { + print "\tallow-transfer {\n"; + for ($i = 0; $i <= $#transfer_acl; $i++) { + &print_maybe_masked("\t\t", $transfer_acl[$i], + $transfer_comments[$i]); + } + print "\t};\n"; + } + print "\t/* +\t * If there is a firewall between you and nameservers you want +\t * to talk to, you might need to uncomment the query-source +\t * directive below. Previous versions of BIND always asked +\t * questions using port 53, but BIND 8.1 uses an unprivileged +\t * port by default. +\t */ +\t// query-source address * port 53; +"; + + print "};\n\n"; +} +if ($logging ne "") { + print "logging {\n$logging};\n\n"; +} +if (@topology > 0) { + print "// Note: the following will be supported in a future release.\n"; + print "/*\n"; + print "host { any; } {\n\ttopology {\n"; + for ($i = 0; $i <= $#topology; $i++) { + &print_maybe_masked("\t\t", $topology[$i], + $topology_comments[$i]); + } + print "\t};\n};\n"; + print "*/\n"; + print "\n"; +} +if (@bogus > 0) { + for ($i = 0; $i <= $#bogus; $i++) { + print "server $bogus[$i] { bogus yes; };$bogus_comments[$i]\n"; + } + print "\n"; +} +print $new_config; + +exit 0; + +sub maybe_print_comment { + $prefix = shift; + $suffix = shift; + if ($comment ne "") { + $new_config .= sprintf("%s%s%s", $prefix, $comment, $suffix); + } +} + +sub handle_options { + foreach $option (@_) { + if ($option eq "forward-only") { + $options{"forward"}="only"; + $options_comments{"forward"}=$comment; + $have_options = 1; + } elsif ($option eq "no-recursion") { + $options{"recursion"}="no"; + $options_comments{"recursion"}=$comment; + $have_options = 1; + } elsif ($option eq "no-fetch-glue") { + $options{"fetch-glue"}="no"; + $options_comments{"fetch-glue"}=$comment; + $have_options = 1; + } elsif ($option eq "fake-iquery") { + $options{"fake-iquery"}="yes"; + $options_comments{"fake-iquery"}=$comment; + $have_options = 1; + } elsif ($option eq "query-log") { + if ($comment ne "") { + $logging .= "\t$comment\n"; + } + $logging .= "\tcategory queries { default_syslog; };\n"; + } else { + $options{"// NOTE: unconverted option '$option'"}=""; + $options_comments{"// NOTE: unconverted option '$option'"}= + $comment; + $have_options = 1; + } + } +} + +sub handle_limit { + $limit = shift; + if ($limit eq "datasize" || $limit eq "transfers-in" + || $limit eq "transfers-per-ns" || $limit eq "files") { + $options{$limit}=$_[0]; + $options_comments{$limit}=$comment; + $have_options = 1; + } else { + $options{"// NOTE: unconverted limit '$limit @_'"}=""; + $options_comments{"// NOTE: unconverted limit '$limit @_'"}=$comment; + $have_options = 1; + } +} + +sub print_maybe_masked { + # this assumes a contiguous netmask starting at the MSB + $prefix = shift; + $elt = shift; + $elt_comment = shift; + if ($elt =~ /^(.*)&(.*)$/) { + $address = $1; + $mask = $2; + ($m1,$m2,$m3,$m4) = split(/\./, $mask); + $mask_val = ($m1 << 24) + ($m2 << 16) +($m3 << 8) + $m4; + $zero_bits = 0; + while (($mask_val % 2) == 0) { + $mask_val /= 2; + $zero_bits++; + } + $mask_bits = 32 - $zero_bits; + } else { + $address = $elt; + ($a1,$a2,$a3,$a4) = split(/\./, $address); + if ($a1 < 128) { + $mask_bits = 8; + } elsif ($a1 < 192) { + $mask_bits = 16; + } else { + $mask_bits = 24; + } + } + + print "$prefix$address"; + if ($mask_bits != 32) { + print "/$mask_bits"; + } + print ";$elt_comment\n"; +} diff --git a/contrib/bind/bin/named-bootconf/Makefile b/contrib/bind/bin/named-bootconf/Makefile new file mode 100644 index 0000000..4c1a0df --- /dev/null +++ b/contrib/bind/bin/named-bootconf/Makefile @@ -0,0 +1,76 @@ +## 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: Makefile,v 1.1 1999/01/07 02:09:37 vixie Exp $ + +DESTDIR= +CC= cc +SHELL= /bin/sh + +CDEBUG= -g + +#(net2 and its descendents) +SYSTYPE = bsdos +TOP = ../.. +INCL = ${TOP}/include +PORTINCL = ${TOP}/port/${SYSTYPE}/include +LIBBIND = ${TOP}/lib/libbind.a +A=a +O=o +LEX = lex -I +SYSLIBS = -ll -lutil +DESTBIN = /usr/local/bin +DESTSBIN = /usr/local/sbin +DESTEXEC = /usr/local/libexec +DESTMAN = /usr/share/man +DESTHELP= /usr/share/misc +STRIP=-s +INSTALL_EXEC= +INSTALL_LIB=-o bin -g bin + +LDFLAGS= +CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL} + +PROG= named-bootconf + +all: ${PROG} + +${PROG}: ${PROG}.sh Makefile + cp ${PROG}.sh ${PROG} + chmod +x ${PROG} + +distclean: clean + +clean: FRC + rm -f ${PROG} + rm -f *.BAK *.CKP *~ *.orig + +depend: + +${DESTDIR}${DESTSBIN}: + mkdir -p ${DESTDIR}${DESTSBIN} + +install: ${DESTDIR}${DESTSBIN} ${PROG} + ${INSTALL} -c -m 755 ${PROG} ${DESTDIR}${DESTSBIN}/${PROG} + +links: FRC + @set -e; ln -s SRC/*.sh . + +tags: + +FRC: + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. diff --git a/contrib/bind/bin/named-bootconf/named-bootconf.sh b/contrib/bind/bin/named-bootconf/named-bootconf.sh new file mode 100644 index 0000000..c1dfaad --- /dev/null +++ b/contrib/bind/bin/named-bootconf/named-bootconf.sh @@ -0,0 +1,306 @@ +#!/bin/sh +# +# $NetBSD: named-bootconf.sh,v 1.5 1998/12/15 01:00:53 tron Exp $ +# +# Copyright (c) 1995, 1998 The NetBSD Foundation, Inc. +# All rights reserved. +# +# This code is derived from software contributed to The NetBSD Foundation +# by Matthias Scheler. +# +# 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 NetBSD +# Foundation, Inc. and its contributors. +# 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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) 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 [ ${OPTIONFILE-X} = X ]; then + OPTIONFILE=/tmp/.options.`date +%s`.$$ + ZONEFILE=/tmp/.zones.`date +%s`.$$ + COMMENTFILE=/tmp/.comments.`date +%s`.$$ + export OPTIONFILE ZONEFILE COMMENTFILE + touch $OPTIONFILE $ZONEFILE $COMMENTFILE + DUMP=1 +else + DUMP=0 +fi + +while read CMD ARGS; do + class= + CMD=`echo "${CMD}" | tr '[A-Z]' '[a-z]'` + case $CMD in + \; ) + echo \# $ARGS >>$COMMENTFILE + ;; + cache ) + set - X $ARGS + shift + if [ $# -eq 2 ]; then + (echo "" + cat $COMMENTFILE + echo "zone \"$1\" {" + echo " type hint;" + echo " file \"$2\";" + echo "};") >>$ZONEFILE + rm -f $COMMENTFILE + touch $COMMENTFILE + fi + ;; + directory ) + set - X $ARGS + shift + if [ $# -eq 1 ]; then + (cat $COMMENTFILE + echo " directory \"$1\";") >>$OPTIONFILE + rm -f $COMMENTFILE + touch $COMMENTFILE + + DIRECTORY=$1 + export DIRECTORY + fi + ;; + forwarders ) + (cat $COMMENTFILE + echo " forwarders {" + for ARG in $ARGS; do + echo " $ARG;" + done + echo " };") >>$OPTIONFILE + rm -f $COMMENTFILE + touch $COMMENTFILE + ;; + include ) + if [ "$ARGS" != "" ]; then + (cd ${DIRECTORY-.}; cat $ARGS) | $0 + fi + ;; + limit ) + ARGS=`echo "${ARGS}" | tr '[A-Z]' '[a-z]'` + set - X $ARGS + shift + if [ $# -eq 2 ]; then + cat $COMMENTFILE >>$OPTIONFILE + case $1 in + datasize | files | transfers-in | transfers-per-ns ) + echo " $1 $2;" >>$OPTIONFILE + ;; + esac + rm -f $COMMENTFILE + touch $COMMENTFILE + fi + ;; + options ) + ARGS=`echo "${ARGS}" | tr '[A-Z]' '[a-z]'` + cat $COMMENTFILE >>$OPTIONFILE + for ARG in $ARGS; do + case $ARG in + fake-iquery ) + echo " fake-iquery yes;" >>$OPTIONFILE + ;; + forward-only ) + echo " forward only;" >>$OPTIONFILE + ;; + no-fetch-glue ) + echo " fetch-glue no;" >>$OPTIONFILE + ;; + no-recursion ) + echo " recursion no;" >>$OPTIONFILE + ;; + esac + done + rm -f $COMMENTFILE + touch $COMMENTFILE + ;; + primary|primary/* ) + case $CMD in + primary/chaos ) + class="chaos " + ;; + primary/hs ) + class="hesiod " + ;; + esac + set - X $ARGS + shift + if [ $# -eq 2 ]; then + (echo "" + cat $COMMENTFILE + echo "zone \"$1\" ${class}{" + echo " type master;" + echo " file \"$2\";" + echo "};") >>$ZONEFILE + rm -f $COMMENTFILE + touch $COMMENTFILE + fi + ;; + secondary|secondary/* ) + case $CMD in + secondary/chaos ) + class="chaos " + ;; + secondary/hs ) + class="hesiod " + ;; + esac + set - X $ARGS + shift + if [ $# -gt 2 ]; then + ZONE=$1 + shift + PRIMARIES=$1 + while [ $# -gt 2 ]; do + shift + PRIMARIES="$PRIMARIES $1" + done + (echo "" + cat $COMMENTFILE + echo "zone \"$ZONE\" ${class}{" + echo " type slave;" + echo " file \"$2\";" + echo " masters {" + for PRIMARY in $PRIMARIES; do + echo " $PRIMARY;" + done + echo " };" + echo "};") >>$ZONEFILE + rm -f $COMMENTFILE + touch $COMMENTFILE + fi + ;; + stub|stub/* ) + case $CMD in + stub/chaos ) + class="chaos " + ;; + stub/hs ) + class="hesiod " + ;; + esac + set - X $ARGS + shift + if [ $# -gt 2 ]; then + ZONE=$1 + shift + PRIMARIES=$1 + while [ $# -gt 2 ]; do + shift + PRIMARIES="$PRIMARIES $1" + done + (echo "" + cat $COMMENTFILE + echo "zone \"$ZONE\" ${class}{" + echo " type stub;" + echo " file \"$2\";" + echo " masters {" + for PRIMARY in $PRIMARIES; do + echo " $PRIMARY;" + done + echo " };" + echo "};") >>$ZONEFILE + rm -f $COMMENTFILE + touch $COMMENTFILE + fi + ;; + slave ) + cat $COMMENTFILE >>$OPTIONFILE + echo " forward only;" >>$OPTIONFILE + rm -f $COMMENTFILE + touch $COMMENTFILE + ;; + sortlist ) + (cat $COMMENTFILE + echo " topology {" + for ARG in $ARGS; do + case $ARG in + *.0.0.0 ) + echo " $ARG/8;" + ;; + *.0.0 ) + echo " $ARG/16;" + ;; + *.0 ) + echo " $ARG/24;" + ;; + * ) + echo " $ARG;" + ;; + esac + done + echo " };") >>$OPTIONFILE + rm -f $COMMENTFILE + touch $COMMENTFILE + ;; + tcplist | xfrnets ) + (cat $COMMENTFILE + echo " allow-transfer {" + for ARG in $ARGS; do + case $ARG in + *.0.0.0 ) + echo " $ARG/8;" + ;; + *.0.0 ) + echo " $ARG/16;" + ;; + *.0 ) + echo " $ARG/24;" + ;; + * ) + echo " $ARG;" + ;; + esac + done + echo " };") >>$OPTIONFILE + rm -f $COMMENTFILE + touch $COMMENTFILE + ;; + esac +done + +if [ $DUMP -eq 1 ]; then + echo "" + echo "options {" + cat $OPTIONFILE + echo "};" + cat $ZONEFILE $COMMENTFILE + + rm -f $OPTIONFILE $ZONEFILE $COMMENTFILE +fi + +exit 0 diff --git a/contrib/bind/bin/named-xfer/Makefile b/contrib/bind/bin/named-xfer/Makefile index 8db8b6e..76d9684 100644 --- a/contrib/bind/bin/named-xfer/Makefile +++ b/contrib/bind/bin/named-xfer/Makefile @@ -1,4 +1,4 @@ -## Copyright (c) 1996 by Internet Software Consortium +## 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 @@ -13,7 +13,7 @@ ## ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ## SOFTWARE. -# $Id: Makefile,v 8.21 1998/04/14 00:39:03 halley Exp $ +# $Id: Makefile,v 8.29 1999/08/08 17:51:02 vixie Exp $ DESTDIR= CC= cc @@ -29,17 +29,19 @@ PORTINCL = ${TOP}/port/${SYSTYPE}/include LIBBIND = ${TOP}/lib/libbind.a A=a O=o +EXE= LEX = lex -I SYSLIBS = -ll -lutil -PIDDIR = /var/run DESTBIN = /usr/local/bin DESTSBIN = /usr/local/sbin DESTEXEC = /usr/local/libexec DESTMAN = /usr/share/man DESTHELP= /usr/share/misc -AR= ar cruv +AR= ar cru INSTALL= install STRIP=-s +INSTALL_EXEC= +INSTALL_LIB=-o bin -g bin PS=ps LDFLAGS= @@ -52,26 +54,28 @@ PROG= named-xfer SRCS= ${PROG}.c OBJS= ${PROG}.${O} -all: ${PROG} +all: ${PROG}${EXE} -${PROG}: ${OBJS} ${NAMED_OBJS} ${LIBBIND} Makefile - ${CC} ${CDEBUG} ${LDFLAGS} -o ${PROG} ${OBJS} ${NAMED_OBJS} \ +${PROG}${EXE}: ${OBJS} ${NAMED_OBJS} ${LIBBIND} Makefile + ${CC} ${CDEBUG} ${LDFLAGS} ${BOUNDS} -o ${PROG}${EXE} ${OBJS} ${NAMED_OBJS} \ ${LIBBIND} ${SYSLIBS} +.c.${O}: + ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c distclean: clean clean: FRC - rm -f ${PROG} core .depend - rm -f *.BAK *.CKP *~ *.${O} *.orig + rm -f ${PROG}${EXE} ${OBJS} core .depend + rm -f *.BAK *.CKP *~ *.orig depend: ${SRCS} - mkdep -p ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS} + mkdep ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS} ${DESTDIR}${DESTEXEC}: mkdir -p ${DESTDIR}${DESTEXEC} -install: ${DESTDIR}${DESTEXEC} ${PROG} - ${INSTALL} ${STRIP} -c -m 755 ${PROG} ${DESTDIR}${DESTEXEC}/${PROG} +install: ${DESTDIR}${DESTEXEC} ${PROG}${EXE} + ${INSTALL} ${STRIP} -c ${INSTALL_EXEC} -m 755 ${PROG}${EXE} ${DESTDIR}${DESTEXEC}/${PROG}${EXE} links: FRC @set -e; ln -s SRC/*.[ch] . @@ -79,9 +83,6 @@ links: FRC tags: FRC ctags ${SRCS} *.h -commands.c: commands.l - ${LEX} -t $< > $@ || rm $@ - FRC: # DO NOT DELETE THIS LINE -- mkdep uses it. diff --git a/contrib/bind/bin/named-xfer/named-xfer.c b/contrib/bind/bin/named-xfer/named-xfer.c index 292714e..50c299e 100644 --- a/contrib/bind/bin/named-xfer/named-xfer.c +++ b/contrib/bind/bin/named-xfer/named-xfer.c @@ -1,5 +1,5 @@ /* - * The original version of xfer by Kevin Dunlap. + * The original version of named-xfer by Kevin Dunlap. * Completed and integrated with named by David Waitzman * (dwaitzman@bbn.com) 3/14/88. * Modified by M. Karels and O. Kure 10-88. @@ -84,7 +84,8 @@ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. */ -/* Portions Copyright (c) 1996, 1997 by Internet Software Consortium. +/* + * 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 @@ -100,27 +101,45 @@ * SOFTWARE. */ +/* + * Portions Copyright (c) 1998 by MetaInfo, Incorporated. + * + * 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 MetaInfo Incorporated 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 METAINFO INCORPORATED DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL METAINFO INCORPRATED + * 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(SABER) char copyright[] = "@(#) Copyright (c) 1988, 1990 The Regents of the University of California.\n\ portions Copyright (c) 1993 Digital Equipment Corporation\n\ + portions Copyright (c) 1998 MetaInfo, Inc.\n\ portions Copyright (c) 1995, 1996 Internet Software Consorium\n\ All rights reserved.\n"; #endif /* not lint */ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)named-xfer.c 4.18 (Berkeley) 3/7/91"; -static char rcsid[] = "$Id: named-xfer.c,v 8.38 1998/03/27 00:19:28 halley Exp $"; +static const char sccsid[] = "@(#)named-xfer.c 4.18 (Berkeley) 3/7/91"; +static const char rcsid[] = "$Id: named-xfer.c,v 8.89 1999/11/09 20:36:54 marka Exp $"; #endif /* not lint */ #include "port_before.h" -#include "fd_setsize.h" - #include <sys/types.h> #include <sys/param.h> #include <sys/file.h> #include <sys/stat.h> #include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <netdb.h> @@ -141,26 +160,39 @@ static char rcsid[] = "$Id: named-xfer.c,v 8.38 1998/03/27 00:19:28 halley Exp $ #include <stdarg.h> #include <isc/eventlib.h> +#include <isc/list.h> #include <isc/logging.h> +/* This still uses malloc/free, but the tsig routines allocate memory with + * memget, and we free it with memput. + */ +#include <isc/memcluster.h> + +#include <isc/dst.h> #include "port_after.h" + #define MAIN_PROGRAM #include "../named/named.h" #undef MAIN_PROGRAM #define MAX_XFER_RESTARTS 2 +#define ENABLE_IXFR 0 + # ifdef SHORT_FNAMES extern long pathconf __P((const char *path, int name)); /* XXX */ # endif + static struct zoneinfo zone; /* zone information */ -static char ddtfilename[] = _PATH_TMPXFER, - *ddtfile = ddtfilename, - *tmpname, - *domain; /* domain being xfered */ +static char *ddtfilename = NULL, + *ddtfile = NULL; + +static char *tmpname = NULL, + *tmpiname = NULL, /* temporary file name for ixfr transaction file */ + *domain; /* domain being xfered */ static int quiet = 0, read_interrupted = 0, @@ -168,30 +200,48 @@ static int quiet = 0, domain_len; /* strlen(domain) */ static FILE *fp = NULL, - *dbfp = NULL; + *dbfp = NULL, + *ixfp = NULL; static char *ProgName; -static void usage(const char *); +static void usage(const char *), + tsig_init(const char *); static int getzone(struct zoneinfo *, u_int32_t, int), print_output(struct zoneinfo *, u_int32_t, u_char *, int, u_char *), netread(int, char *, int, int), writemsg(int, const u_char *, int); +static void ixfr_log(const u_char *msg, int len, int *delete, + FILE *file, struct sockaddr_in *sin, + char *domain, u_int32_t serial_no, int *); static SIG_FN read_alarm(void); static SIG_FN term_handler(void); -static const char *soa_zinfo(struct zoneinfo *, u_char *, u_char*); +static const char *soa_zinfo(struct zoneinfo *, u_char *, u_char*), + *tsig_rcode(int); struct zoneinfo zp_start, zp_finish; static int restarts = 0; +static int check_serial = 0; +static int xfr_qtype = T_AXFR; +static u_int32_t old_serial; FILE *ddt = NULL; +int servermethode[NSMAX]; +char *soa_buf; + +typedef struct _tsig_node { + struct in_addr addr; + DST_KEY *dst_key; + LINK(struct _tsig_node) link; +} tsig_node; + +LIST(tsig_node) tsig_list; /* * Debugging printf. */ -#ifdef DEBUG void dprintf(int level, const char *format, ...) { va_list ap; @@ -201,10 +251,9 @@ dprintf(int level, const char *format, ...) { (void) vfprintf(ddt, format, ap); va_end(ap); } -#endif /*DEBUG*/ -static -int init_xfer_logging() { +static int +init_xfer_logging() { log_channel chan; if (log_new_context(ns_log_max_category, NULL, &log_ctx) < 0) { @@ -243,7 +292,26 @@ void cleanup_for_exit(void) { #ifdef DEBUG if (!debug) #endif + { (void) unlink(tmpname); + if (tmpiname != NULL) + (void) unlink(tmpiname); + } + if(tmpiname) + free(tmpiname); + tmpiname = NULL; + if (ddtfilename != NULL) { + free(ddtfilename); + if (ddtfilename == ddtfile) + ddtfile = NULL; + ddtfilename = NULL; + } + if(tmpname) + free(tmpname); + tmpname = NULL; + if(ddtfile) + free(ddtfile); + ddtfile = NULL; } @@ -252,18 +320,22 @@ main(int argc, char *argv[]) { struct zoneinfo *zp; struct hostent *hp; struct in_addr axfr_src; - char *dbfile = NULL, *tracefile = NULL, *tm = NULL; - int dbfd, ddtd, result, c, fd, closed = 0; + char *dbfile = NULL, *tracefile = NULL, *tm = NULL, *tsigfile = NULL; + char *ixfrfile = NULL; + u_int32_t new_serial_no = 0; + int dbfd, ddtd, result, c, fd, ixfd; u_int32_t serial_no = 0; u_int port = htons(NAMESERVER_PORT); struct stat statbuf; -#ifdef STUBS int stub_only = 0; -#endif int class = C_IN; int n; long num_files; +#ifdef _AUX_SOURCE + set42sig(); +#endif + memset(&axfr_src, 0, sizeof axfr_src); ProgName = strrchr(argv[0], '/'); if (ProgName != NULL) ProgName++; @@ -272,10 +344,9 @@ main(int argc, char *argv[]) { (void) umask(022); - /* this is a hack; closing everything in the parent is hard. */ - num_files = MIN(sysconf(_SC_OPEN_MAX), FD_SETSIZE); - for (fd = num_files - 1; fd > STDERR_FILENO; fd--) - closed += (close(fd) == 0); + ddtfilename = (char *)malloc(strlen(_PATH_TMPXFER) + 1); + strcpy(ddtfilename, _PATH_TMPXFER); + ddtfile = ddtfilename; #ifdef RENICE nice(-40); /* this is the recommended procedure to */ @@ -283,24 +354,21 @@ main(int argc, char *argv[]) { nice(0); /* to "normal" (== 0) - see nice(3) */ #endif + n = LOG_PID; #ifdef LOG_PERROR - n = LOG_PERROR; -#else - n = 0; + n |= LOG_PERROR; #endif -#ifdef SYSLOG_42BSD - openlog(ProgName, LOG_PID); -#else - openlog(ProgName, LOG_PID|LOG_CONS|n, LOG_DAEMON); +#if defined(LOG_CONS) && defined(USE_LOG_CONS) + n |= LOG_CONS; #endif - axfr_src.s_addr = 0; -#ifdef STUBS - while ((c = getopt(argc, argv, "C:d:l:s:t:z:f:p:P:qx:S")) != EOF) +#ifdef SYSLOG_42BSD + openlog(ProgName, n); #else - while ((c = getopt(argc, argv, "C:d:l:s:t:z:f:p:P:qx:")) != EOF) + openlog(ProgName, n, LOG_DAEMON); #endif - switch (c) { - case 'C': + while ((c = getopt(argc, argv, "C:d:l:s:t:z:f:i:p:P:qx:ST:Z")) != -1) + switch (c) { + case 'C': class = get_class(optarg); break; case 'd': @@ -322,6 +390,7 @@ main(int argc, char *argv[]) { break; case 's': serial_no = strtoul(optarg, (char **)NULL, 10); + check_serial++; break; case 't': tracefile = optarg; @@ -345,17 +414,29 @@ main(int argc, char *argv[]) { (void) strcpy(tmpname, optarg); #endif /* SHORT_FNAMES */ break; + case 'i': +#if ENABLE_IXFR + ixfrfile = optarg; + tmpiname = (char *) malloc(strlen(optarg) + + sizeof(".XXXXXX") + 1); + if (!tmpiname) + panic("malloc(tmpiname)", NULL); +#ifdef SHORT_FNAMES + filenamecpy(tmpiname, optarg); +#else + (void) strcpy(tmpiname, optarg); +#endif /* SHORT_FNAMES */ +#endif /* ENABLE_IXFR */ + break; case 'p': port = htons((u_int16_t)atoi(optarg)); break; case 'P': port = (u_int16_t)atoi(optarg); break; -#ifdef STUBS case 'S': stub_only = 1; break; -#endif case 'q': quiet++; break; @@ -363,13 +444,18 @@ main(int argc, char *argv[]) { if (!inet_aton(optarg, &axfr_src)) panic("bad -x addr: %s", optarg); break; + case 'T': + tsigfile = optarg; + break; + case 'Z': + xfr_qtype = ns_t_zxfr; + break; case '?': default: usage("unrecognized argument"); /* NOTREACHED */ - } - - if (!domain || !dbfile || optind >= argc) { + } + if (!domain || ((!dbfile) && (!ixfrfile)) || optind >= argc) { if (!domain) usage("no domain"); if (!dbfile) @@ -382,6 +468,14 @@ main(int argc, char *argv[]) { !S_ISREG(statbuf.st_mode) && !S_ISFIFO(statbuf.st_mode)) usage("dbfile must be a regular file or FIFO"); + if (ixfrfile && (stat(ixfrfile, &statbuf) != -1 && + !S_ISREG(statbuf.st_mode) && + !S_ISFIFO(statbuf.st_mode))) + usage("ixfrfile must be a regular file or FIFO"); + if (tsigfile && stat(tsigfile, &statbuf) != -1 && + !S_ISREG(statbuf.st_mode) && + !S_ISFIFO(statbuf.st_mode)) + usage("tsigfile must be a regular file or FIFO"); if (tracefile && (fp = fopen(tracefile, "w")) == NULL) perror(tracefile); (void) strcat(tmpname, ".XXXXXX"); @@ -389,8 +483,8 @@ main(int argc, char *argv[]) { if ((dbfd = mkstemp(tmpname)) == -1) { perror(tmpname); if (!quiet) - syslog(LOG_ERR, "can't make tmpfile (%s): %m\n", - tmpname); + syslog(LOG_ERR, "can't make tmpfile (%s): %s\n", + tmpname, strerror(errno)); exit(XFER_FAIL); } #ifdef HAVE_FCHMOD /* XXX */ @@ -401,8 +495,8 @@ main(int argc, char *argv[]) { { perror(tmpname); if (!quiet) - syslog(LOG_ERR, "can't [f]chmod tmpfile (%s): %m\n", - tmpname); + syslog(LOG_ERR, "can't [f]chmod tmpfile (%s): %s\n", + tmpname, strerror(errno)); exit(XFER_FAIL); } if ((dbfp = fdopen(dbfd, "r+")) == NULL) { @@ -411,6 +505,36 @@ main(int argc, char *argv[]) { syslog(LOG_ERR, "can't fdopen tmpfile (%s)", tmpname); exit(XFER_FAIL); } + if (ixfrfile) { + (void) strcat(tmpiname, ".XXXXXX"); + if ((ixfd = mkstemp(tmpiname)) == -1) { + perror(tmpiname); + if (!quiet) + syslog(LOG_ERR, + "can't make tmpifile (%s): %s\n", + tmpiname, strerror(errno)); + (void) fclose(dbfp); + (void) close(dbfd); + exit(XFER_FAIL); + } +#ifdef HAVE_FCHMOD /* XXX */ + if (fchmod(ixfd, 0644) == -1) +#else + if (chmod(tmpiname, 0644) == -1) +#endif + { + perror(tmpiname); + if (!quiet) + syslog(LOG_ERR, + "can't [f]chmod tmpifile (%s): %s\n", + tmpiname, strerror(errno)); + (void) fclose(dbfp); + (void) close(dbfd); + (void) close(ixfd); + exit(XFER_FAIL); + } + close(ixfd); + } #ifdef DEBUG if (debug) { /* ddtfile is now something like "/usr/tmp/xfer.ddt.XXXXXX" */ @@ -433,8 +557,8 @@ main(int argc, char *argv[]) { setvbuf(ddt, NULL, _IOLBF, 0); } #endif - if (!init_xfer_logging()) { + cleanup_for_exit(); perror("init_xfer_logging"); } @@ -464,20 +588,25 @@ main(int argc, char *argv[]) { (void) signal(SIGFPE, SIG_IGN); #endif /* SIGUSR1&&SIGUSR2 */ - dprintf(1, "domain `%s'; file `%s'; serial %u; closed %d\n", - domain, dbfile, serial_no, closed); + if (dbfile) + dprintf(1, "domain `%s'; file `%s'; serial %u\n", + domain, dbfile, serial_no); + + if (ixfrfile) + dprintf(1, "domain `%s'; ixfrfile `%s'; serial %u\n", + domain, ixfrfile, serial_no); buildservicelist(); buildprotolist(); + tsig_init(tsigfile); + /* init zone data */ zp = &zone; -#ifdef STUBS if (stub_only) zp->z_type = Z_STUB; else -#endif zp->z_type = Z_SECONDARY; zp->z_class = class; zp->z_origin = domain; @@ -490,8 +619,34 @@ main(int argc, char *argv[]) { zp->z_source); for (; optind != argc; optind++) { + int tmpsupportixfr; + tm = argv[optind]; + tmpsupportixfr = ISNOTIXFR; + if ((optind+1) != argc) { + if (strcasecmp("ixfr", argv[optind+1]) == 0) { +#if ENABLE_IXFR + tmpsupportixfr = ISIXFR; + servermethode[zp->z_addrcnt] = tmpsupportixfr; +#endif + optind++; + } else if (strcasecmp("axfr", argv[optind+1]) == 0) { + tmpsupportixfr = ISNOTIXFR; + optind++; + } + } if (!inet_aton(tm, &zp->z_addr[zp->z_addrcnt])) { + if (strcmp("-ixfr",tm)==0) { +#if ENABLE_IXFR + tmpsupportixfr = ISIXFR; + servermethode[zp->z_addrcnt-1] = tmpsupportixfr; +#endif + continue; + } else + if (strcmp("-axfr",tm)==0) { + tmpsupportixfr = ISNOTIXFR; + continue; + } hp = gethostbyname(tm); if (hp == NULL) { syslog(LOG_NOTICE, @@ -502,7 +657,7 @@ main(int argc, char *argv[]) { memcpy(&zp->z_addr[zp->z_addrcnt], hp->h_addr, INADDRSZ); - dprintf(1, "Arg: \"%s\"\n", tm); + dprintf(1, "Arg: \"%s\" %s\n", tm,((tmpsupportixfr) ? "IXFR":"AXFR")); } if (++zp->z_addrcnt >= NSMAX) { zp->z_addrcnt = NSMAX; @@ -512,24 +667,71 @@ main(int argc, char *argv[]) { } dprintf(1, "addrcnt = %d\n", zp->z_addrcnt); - res_init(); - _res.options &= ~(RES_DEFNAMES | RES_DNSRCH | RES_RECURSE); + res_ninit(&res); + res.options &= ~(RES_DEFNAMES | RES_DNSRCH | RES_RECURSE); result = getzone(zp, serial_no, port); - (void) my_fclose(dbfp); + (void) fclose(dbfp); + (void) close(dbfd); + + if (ixfp) + (void) my_fclose(ixfp); + else + close(ixfd); + switch (result) { - case XFER_SUCCESS: /* ok exit */ - if (rename(tmpname, dbfile) == -1) { - perror("rename"); + case XFER_SUCCESSAXFR: /* ok exit */ + if (tmpiname != NULL) + unlink(tmpiname); + if (ixfrfile) { + /* + * An IXFR was requested but we performed an + * AXFR. Rename the temporary file to the IXFR + * name, named will rename it again to the dbname. + */ + if (movefile(tmpname, ixfrfile) == -1) { + perror("movefile"); +#ifdef DEBUG + if (debug) + (void) unlink(ddtfile); +#endif + if (!quiet) + syslog(LOG_ERR, + "rename %s to %s: %s", + tmpname, ixfrfile, strerror(errno)); + cleanup_for_exit(); + exit(XFER_FAIL); + }; + exit(XFER_SUCCESSAXFRIXFRFILE); + } + if (movefile(tmpname, dbfile) == -1) { + perror("movefile"); if (!quiet) - syslog(LOG_ERR, "rename %s to %s: %m", + syslog(LOG_ERR, "movefile %s to %s: %m", tmpname, dbfile); + cleanup_for_exit(); exit(XFER_FAIL); } - exit(XFER_SUCCESS); + exit(XFER_SUCCESSAXFR); + + case XFER_SUCCESSIXFR: + unlink(tmpname); + if (movefile(tmpiname, ixfrfile) == -1) { + perror("movefile"); + if (!quiet) + syslog(LOG_ERR, "movefile %s to %s: %m", + tmpiname, ixfrfile); + cleanup_for_exit(); + exit(XFER_FAIL); + } + cleanup_for_exit(); + exit(XFER_SUCCESSIXFR); case XFER_UPTODATE: /* the zone was already uptodate */ (void) unlink(tmpname); + if (tmpiname != NULL) + (void) unlink(tmpiname); + cleanup_for_exit(); exit(XFER_UPTODATE); default: @@ -537,6 +739,7 @@ main(int argc, char *argv[]) { /* fall through */ case XFER_TIMEOUT: case XFER_FAIL: + (void) unlink(tmpname); cleanup_for_exit(); exit(result); /* error or timeout */ } @@ -547,17 +750,17 @@ main(int argc, char *argv[]) { static char *UsageText[] = { "\t-z zone_to_transfer\n", "\t-f db_file\n", - "\t-s serial_no\n", + "\t[-i ixfr_file]\n", + "\t[-s serial_no]\n", "\t[-d debug_level]\n", "\t[-l debug_log_file]\n", "\t[-t trace_file]\n", "\t[-p port]\n", -#ifdef STUBS - "\t[-S]\n", -#endif + "\t[-S] [-Z]\n", "\t[-C class]\n", "\t[-x axfr-src]\n", - "\tservers...\n", + "\t[-T tsig_info_file]\n", + "\tservers [-ixfr|-axfr]...\n", NULL }; @@ -572,13 +775,66 @@ usage(const char *msg) { exit(XFER_FAIL); } +static void +tsig_init(const char *file) { + char buf[1024]; + int n; + FILE *fp; + char *s; + + if (file == NULL) + return; + fp = fopen(file, "r"); + if (fp == NULL) + return; + dst_init(); + INIT_LIST(tsig_list); + while (1) { + tsig_node *n = malloc(sizeof(tsig_node)); + int alg, secret_len; + char *address, *name; + char *cp; + u_char secret[128]; + + s = fgets(buf, sizeof(buf), fp); + if (s == NULL) + break; + buf[strlen(buf)-1] = 0; + inet_aton(buf, &n->addr); + + fgets(buf, sizeof(buf), fp); + buf[strlen(buf)-1] = 0; + name = strdup(buf); + + fscanf(fp, "%d", &alg); + fgets(buf, sizeof(buf), fp); + + fgets(buf, sizeof(buf), fp); + buf[strlen(buf)-1] = 0; + cp = buf; + while (isspace(*cp)) + cp++; + + secret_len = b64_pton(cp, secret, sizeof(secret)); + n->dst_key = dst_buffer_to_key(name, alg, 0, 0, + secret, secret_len); + + free(name); + APPEND(tsig_list, n, link); + } + fclose(fp); + unlink(file); +} + #define DEF_DNAME '\001' /* '\0' means the root domain */ /* XXX: The following variables should probably all be "static" */ u_int32_t minimum_ttl = 0; -int soa_cnt = 0; -#ifdef STUBS +int soa_cnt = 0, scdsoa = 0, methode = ISNOTIXFR; +int delete_soa = 1; +u_int32_t final_serial = 0; +int ixfr_soa = 0; +int firstsoa = 1; int ns_cnt = 0; -#endif int query_type = 0; int prev_comment = 0; /* was previous record a comment? */ char zone_top[MAXDNAME]; /* the top of the zone */ @@ -592,19 +848,32 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { u_int len; u_int32_t serial; int s, n, l, error = 0; + int was_ixfr = 0; u_int cnt; u_char *cp, *nmp, *eom, *tmp ; - u_char *buf = NULL; + u_char *buf = NULL, *cpp = NULL; u_int bufsize = 0; char name[MAXDNAME], name2[MAXDNAME]; struct sockaddr_in sin; + struct sockaddr_in local; + int locallen; #ifdef POSIX_SIGNALS struct sigaction sv, osv; #else struct sigvec sv, osv; #endif - int qdcount, ancount, aucount, class, type; + int qdcount, ancount, aucount, arcount, class, type; const char *badsoa_msg = "Nil"; + struct sockaddr_in my_addr; + char my_addr_text[30]; + int alen, ret, tsig_req; + DST_KEY *tsig_key; + ns_tcp_tsig_state tsig_state; + int tsig_signed = 0; + u_char sig[64]; + int siglen; + int ixfr_first = 1; + time_t timesigned; #ifdef DEBUG if (debug) { @@ -648,9 +917,23 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { if ((l = strlen(zone_top)) != 0 && zone_top[l - 1] == '.') zone_top[l - 1] = '\0'; strcpy(prev_origin, zone_top); + for (cnt = 0; cnt < zp->z_addrcnt; cnt++) { + methode = servermethode[cnt]; + sin.sin_addr = zp->z_addr[cnt]; + dprintf(3, "address [%s] %s\n", + inet_ntoa(sin.sin_addr), + (methode == ISIXFR) ? "IXFR":"AXFR"); + } for (cnt = 0; cnt < zp->z_addrcnt; cnt++) { + methode = ISNOTIXFR; curclass = zp->z_class; + /* + * If we have been given a serial number and a ixfr log + * file name then set methode. + */ + if (check_serial && tmpiname != NULL) + methode = servermethode[cnt]; error = 0; if (buf == NULL) { if ((buf = (u_char *)malloc(2 * PACKETSZ)) == NULL) { @@ -661,6 +944,7 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { } bufsize = 2 * PACKETSZ; } + try_again: if ((s = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) { syslog(LOG_INFO, "socket: %m"); error++; @@ -684,20 +968,72 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { dprintf(2, "connecting to server #%d [%s].%d\n", cnt+1, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + if (zp->z_axfr_src.s_addr != 0) { + dprintf(2, "connect failed, trying w/o -x"); + zp->z_axfr_src.s_addr = 0; + (void) my_close(s); + goto try_again; + } if (!quiet) syslog(LOG_INFO, - "connect(%s) for zone %s failed: %m", - inet_ntoa(sin.sin_addr), zp->z_origin); + "connect(%s) for zone %s failed: %s", + inet_ntoa(sin.sin_addr), zp->z_origin, strerror(errno)); error++; (void) my_close(s); continue; } - n = res_mkquery(QUERY, zp->z_origin, curclass, - T_SOA, NULL, 0, NULL, buf, bufsize); + if (methode == ISIXFR) { + hp = (HEADER *) buf; + cpp = buf; + n = res_nmkquery(&res, QUERY, zp->z_origin, curclass, + T_IXFR, NULL, 0, NULL, buf, bufsize); + dprintf(1, "len = %d\n", n); + if (n < 0) { + if (!quiet) + syslog(LOG_INFO, + "zone %s: dn_comp for ixfr failed", + zp->z_origin); + (void) my_close(s); +#ifdef POSIX_SIGNALS + sigaction(SIGALRM, + &osv, + (struct sigaction*)0); +#else + sigvec(SIGALRM, + &osv, + (struct sigvec *)0); +#endif + return (XFER_FAIL); + } + hp->nscount = htons(1+ntohs(hp->nscount)); + cpp += n; + n = dn_comp(zp->z_origin, cpp, bufsize-(cpp-buf), + NULL, NULL); + if (n > 0) + cpp += n; + PUTSHORT(T_SOA, cpp); /* type */ + PUTSHORT(C_IN, cpp); /* class */ + PUTLONG(0, cpp); /* ttl */ + PUTSHORT(22, cpp); /* dlen */ + *cpp++ = 0; /* mname */ + *cpp++ = 0; /* rname */ + PUTLONG(serial_no, cpp); + PUTLONG(0xDEAD, cpp); /* Refresh */ + PUTLONG(0xBEEF, cpp); /* Retry */ + PUTLONG(0xABCD, cpp); /* Expire */ + PUTLONG(0x1776, cpp); /* Min TTL */ + n = cpp-buf; + dprintf(1, "len = %d\n", cpp-buf); + if (debug) + res_pquery(&res, buf, n, ddt); + } + else { + n = res_nmkquery(&res, QUERY, zp->z_origin, curclass, + T_SOA, NULL, 0, NULL, buf, bufsize); if (n < 0) { if (!quiet) syslog(LOG_INFO, - "zone %s: res_mkquery T_SOA failed", + "zone %s: res_nmkquery T_SOA failed", zp->z_origin); (void) my_close(s); #ifdef POSIX_SIGNALS @@ -707,6 +1043,19 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { #endif return (XFER_FAIL); } + } + /* + * Append TSIG to SOA query if desired + */ + tsig_key = tsig_key_from_addr(sin.sin_addr); + if (tsig_key != NULL) { + siglen = sizeof(sig); + ret = ns_sign(buf, &n, bufsize, NOERROR, tsig_key, + NULL, 0, sig, &siglen, timesigned); + if (ret == 0) + tsig_signed = 1; + } + /* * Send length & message for SOA query */ @@ -719,6 +1068,7 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { /* * Get out your butterfly net and catch the SOA */ + if (netread(s, (char *)buf, INT16SZ, XFER_TIMER) < 0) { error++; (void) my_close(s); @@ -745,16 +1095,52 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { (void) my_close(s); continue; } + /* + * Verify the TSIG if expected + */ + if (tsig_signed != 0) { + ret = ns_verify(buf, (int *)&len, tsig_key, sig, siglen, + NULL, NULL, ×igned, 0); + if (ret != 0) { + syslog(LOG_NOTICE, + "SOA TSIG verification from server [%s], zone %s: %s (%d)\n", + inet_ntoa(sin.sin_addr), zp->z_origin, + tsig_rcode(ret), ret); + error++; + continue; + } + } + #ifdef DEBUG if (debug >= 3) { (void)fprintf(ddt,"len = %d\n", len); - fp_nquery(buf, len, ddt); + res_pquery(&res, buf, len, ddt); } #endif + if ((methode == ISIXFR) && (ixfp == NULL)) { + delete_soa = 1; + firstsoa = 1; + ixfr_soa = 0; + old_serial = serial_no; + if (ixfp != NULL) { + fflush(ixfp); + /* XXX error */ + ftruncate(fileno(ixfp), 0); + } else if ((ixfp = fopen(tmpiname, "w+")) == NULL) { + perror(tmpiname); + if (!quiet) + syslog(LOG_ERR, + "can't fdopen ixfr log (%s)", + tmpname); + exit(XFER_FAIL); + } + } + hp = (HEADER *) buf; qdcount = ntohs(hp->qdcount); ancount = ntohs(hp->ancount); aucount = ntohs(hp->nscount); + arcount = ntohs(hp->arcount); /* * close socket if any of these apply: @@ -809,8 +1195,8 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { } NS_GET16(type, tmp); NS_GET16(class, tmp); - if (class != curclass || type != T_SOA || - strcasecmp(zp->z_origin, name2) != 0) { + if (class != curclass || ((type != T_SOA) && type != T_IXFR) || + ns_samename(zp->z_origin, name2) != 1) { syslog(LOG_INFO, "wrong query in resp from [%s], zone %s: [%s %s %s]\n", inet_ntoa(sin.sin_addr), zp->z_origin, @@ -857,7 +1243,7 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { tmp = cp4 + dlen; } while (1); - if (strcasecmp(zp->z_origin, name2) != 0) { + if (ns_samename(zp->z_origin, name2) != 1) { syslog(LOG_INFO, "wrong answer in resp from [%s], zone %s: [%s %s %s]\n", inet_ntoa(sin.sin_addr), zp->z_origin, @@ -869,16 +1255,35 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { badsoa_msg = soa_zinfo(&zp_start, tmp, eom); if (badsoa_msg) goto badsoa; - if (SEQ_GT(zp_start.z_serial, serial_no) || !serial_no) { - const char *l, *nl; + if (SEQ_GT(zp_start.z_serial, serial_no) || !check_serial) { + const char *l, *nl, *t; + dprintf(1, "need update, serial %u\n", zp_start.z_serial); hp = (HEADER *) buf; - soa_cnt = 0; -#ifdef STUBS + if ((methode == ISIXFR) && (soa_cnt == 0)) { + if (type == T_IXFR) { + if (ixfp) + ixfr_log(buf, len, &delete_soa, ixfp, + &sin, domain, serial_no, + &ixfr_first); + soa_cnt = 2; + } else { + dprintf(1, + "server %s rejected IXFR and responded with AXFR\n", + inet_ntoa(sin.sin_addr)); + methode = ISNOTIXFR; + was_ixfr++; + soa_cnt++; + } + } ns_cnt = 0; -#endif gettime(&tt); + locallen = sizeof local; + if (getsockname(s, (struct sockaddr *)&local, + &locallen) < 0) { + memset(&local, 0, sizeof local); + } for (l = Version; l; l = nl) { size_t len; if ((nl = strchr(l, '\n')) != NULL) { @@ -894,41 +1299,62 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { fprintf(dbfp, "; BIND version %.*s\n", (int)len, l); } - fprintf(dbfp, "; zone '%s' last serial %u\n", + fprintf(dbfp, check_serial? + "; zone '%s' last serial %u\n": + "; zone '%s' first transfer\n", domain, serial_no); - fprintf(dbfp, "; from %s at %s", - inet_ntoa(sin.sin_addr), + t = strdup(inet_ntoa(sin.sin_addr)); + fprintf(dbfp, "; from %s:%d (local %s) using %s at %s", + t, ntohs(sin.sin_port), + inet_ntoa(local.sin_addr), + (methode == ISIXFR) ? "IXFR":"AXFR", ctimel(tt.tv_sec)); + free((void *)t); for (;;) { if ((soa_cnt == 0) || (zp->z_type == Z_STUB)) { -#ifdef STUBS if (zp->z_type == Z_STUB) { if (soa_cnt == 1 && ns_cnt == 0) query_type = T_NS; else query_type = T_SOA; - } else -#endif - query_type = T_AXFR; - n = res_mkquery(QUERY, zp->z_origin, - curclass, query_type, - NULL, 0, - NULL, buf, bufsize); + } else if (methode == ISIXFR) + query_type = T_IXFR; + else + query_type = xfr_qtype; + n = res_nmkquery(&res, QUERY, + zp->z_origin, + curclass, query_type, + NULL, 0, + NULL, buf, bufsize); + syslog(LOG_INFO, + "send %s query %d to %s", + (query_type == T_IXFR) ? "IXFR" : + (query_type == T_AXFR) ? "AXFR" : + (query_type == ns_t_zxfr) ? "ZXFR" : + (query_type == T_SOA) ? "SOA" : "NS", + cnt, inet_ntoa(sin.sin_addr)); + dprintf(1, + "send %s query to %s\n", + (query_type == T_IXFR) ? "IXFR" : + (query_type == T_AXFR) ? "AXFR" : + (query_type == ns_t_zxfr) ? "ZXFR" : + (query_type == T_SOA) ? "SOA" : "NS", + inet_ntoa(sin.sin_addr)); + dprintf(1,"bufsize = %d\n", bufsize); if (n < 0) { if (!quiet) { -#ifdef STUBS if (zp->z_type == Z_STUB) syslog(LOG_INFO, (query_type == T_SOA) - ? "zone %s: res_mkquery T_SOA failed" - : "zone %s: res_mkquery T_NS failed", + ? "zone %s: res_nmkquery T_SOA failed" + : "zone %s: res_nmkquery T_NS failed", zp->z_origin); else -#endif syslog(LOG_INFO, - "zone %s: res_mkquery T_AXFR failed", - zp->z_origin); + "zone %s: res_nmkquery %s failed", + zp->z_origin, + p_type(query_type)); } (void) my_close(s); #ifdef POSIX_SIGNALS @@ -940,10 +1366,25 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { #endif return (XFER_FAIL); } + cpp = buf + n; + /* + * Append TSIG to AXFR query if desired + */ + if (tsig_signed != 0) { + siglen = sizeof(sig); + ns_sign(buf, &n, bufsize, + NOERROR, tsig_key, + NULL, 0, sig, &siglen, + timesigned); + cpp = buf + n; + ns_verify_tcp_init(tsig_key, + sig, siglen, + &tsig_state); + } /* * Send length & msg for zone transfer */ - if (writemsg(s, buf, n) < 0) { + if (writemsg(s, buf, cpp - buf) < 0) { syslog(LOG_INFO, "writemsg: %m"); error++; @@ -951,6 +1392,8 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { break; } } +/*XXX ZXFR*/ + if (methode == ISNOTIXFR && !was_ixfr) { /* * Receive length & response */ @@ -966,7 +1409,7 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { buf = (u_char *)realloc(buf, len); if (buf == NULL) { syslog(LOG_INFO, - "malloc(%u) failed for packet from server [%s], zone %s\n", + "malloc(%u) failed for packet from server [%s], zone %s\n", len, inet_ntoa(sin.sin_addr), zp->z_origin); @@ -982,18 +1425,36 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { error++; break; } + } #ifdef DEBUG if (debug >= 3) { (void)fprintf(ddt,"len = %d\n", len); - fp_nquery(buf, len, ddt); + res_pquery(&res, buf, len, ddt); } if (fp) - fp_nquery(buf, len, fp); + res_pquery(&res, buf, len, fp); #endif + /* + * Verify the TSIG if expected + */ + if (tsig_signed != 0) { + tsig_req = (soa_cnt == 0); + ret = ns_verify_tcp(buf, (int *)&len, + &tsig_state, + tsig_req); + eom = buf + len; + + if (ret != 0) { + syslog(LOG_NOTICE, + "TSIG verification from server [%s], zone %s: %s (%d)\n", + inet_ntoa(sin.sin_addr), + zp->z_origin, + tsig_rcode(ret), ret); + error++; + break; + } + } if (len < HFIXEDSZ) { - struct sockaddr_in my_addr; - char my_addr_text[30]; - int alen; badrec: error++; @@ -1009,25 +1470,54 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { sin_addr), ntohs(my_addr.sin_port) ); - syslog(LOG_INFO, + if ((hp->rcode == REFUSED) && + (len >= HFIXEDSZ)) { + syslog(LOG_INFO, + "[%s] transfer refused from [%s], zone %s\n", + my_addr_text, + inet_ntoa(sin.sin_addr), + zp->z_origin); + } else { + syslog(LOG_INFO, "[%s] record too short from [%s], zone %s\n", - my_addr_text, - inet_ntoa(sin.sin_addr), - zp->z_origin); + my_addr_text, + inet_ntoa(sin.sin_addr), + zp->z_origin); + } break; } + if (query_type == T_IXFR) + if (hp->rcode != NOERROR) { + dprintf(1, + "server %s did not support IXFR\n", + inet_ntoa(sin.sin_addr)); + methode = ISNOTIXFR; + continue; + }; cp = buf + HFIXEDSZ; - if (hp->qdcount) { - if ((n = dn_skipname(cp, eom)) == -1 - || n + QFIXEDSZ >= eom - cp) + if (ntohs(hp->qdcount) == 1) { + if ((query_type == T_IXFR) && (methode == ISIXFR)) { + dprintf(1, + "server %s rejected IXFR and responded with AXFR\n", + inet_ntoa(sin.sin_addr)); + methode = ISNOTIXFR; + } + n = dn_skipname(cp, eom); + if ((n == -1) || + ((n + QFIXEDSZ) >= (eom - cp))) goto badrec; cp += n + QFIXEDSZ; + } else { + if (methode == ISIXFR && ixfp) + ixfr_log(buf, len, &delete_soa, ixfp, + &sin, domain, serial_no, + &ixfr_first); + } nmp = cp; if ((n = dn_skipname(cp, eom)) == -1) goto badrec; tmp = cp + n; -#ifdef STUBS if (zp->z_type == Z_STUB) { ancount = ntohs(hp->ancount); n = 0; @@ -1091,11 +1581,8 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { break; } } else { -#endif /*STUBS*/ ancount = ntohs(hp->ancount); - for (n = cnt = 0; - cnt < (u_int)ancount; - cnt++) { + for (n = cnt = 0; cnt < (u_int)ancount; cnt++) { n = print_output(zp, serial_no, buf, len, cp); if (n < 0) @@ -1117,13 +1604,12 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { error++; break; } -#ifdef STUBS } -#endif - if (soa_cnt >= 2) + if ((soa_cnt >= 2) && (methode == ISNOTIXFR)) + break; + if ((soa_cnt == -1) && (methode == ISIXFR)) break; - } (void) my_close(s); if (error == 0) { @@ -1133,21 +1619,43 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { #else (void) sigvec(SIGALRM, &osv, (struct sigvec *)0); #endif - return (XFER_SUCCESS); + if (methode == ISIXFR) { + fprintf(ixfp, "update:\t{add} "); + if (soa_buf) + fputs(soa_buf, ixfp); + fprintf(ixfp, "[END_DELTA]\n"); + (void) my_close(s); + return (XFER_SUCCESSIXFR); + } else { + if (ixfp) { + (void) fclose(ixfp); + ixfp = NULL; + } + return (XFER_SUCCESSAXFR); + } + } + if (ixfp) { + (void) fclose(ixfp); + ixfp = NULL; } dprintf(2, "error receiving zone transfer\n"); } else if (zp_start.z_serial == serial_no) { - (void) my_close(s); - dprintf(1, "zone up-to-date, serial %u\n", zp_start.z_serial); - return (XFER_UPTODATE); + (void) my_close(s); + dprintf(1, "zone up-to-date, serial %u\n", zp_start.z_serial); + if (ixfp) { + (void) unlink (tmpiname); + (void) fclose(ixfp); + ixfp = NULL; + } + return (XFER_UPTODATE); } else { - (void) my_close(s); - if (!quiet) - syslog(LOG_NOTICE, + (void) my_close(s); + if (!quiet) + syslog(LOG_NOTICE, "serial from [%s], zone %s: %u lower than current: %u\n", inet_ntoa(sin.sin_addr), zp->z_origin, zp_start.z_serial, serial_no); - return (XFER_FAIL); + return (XFER_FAIL); } } #ifdef POSIX_SIGNALS @@ -1155,6 +1663,11 @@ getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) { #else (void) sigvec(SIGALRM, &osv, (struct sigvec *)0); #endif + if (ixfp) { + (void) unlink (tmpiname); + (void) my_fclose(ixfp); + ixfp = 0; + } if (!error) return (XFER_TIMEOUT); return (XFER_FAIL); @@ -1382,6 +1895,7 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, case T_NSAP: case T_AAAA: case T_KEY: + case ns_t_cert: cp1 = cp; n = dlen; cp += n; @@ -1640,14 +2154,14 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, */ if (type == T_SOA) { - if (strcasecmp(dname, zp->z_origin) != 0) { + if (ns_samename(dname, zp->z_origin) != 1) { syslog(LOG_INFO, - "wrong zone name in AXFR (wanted \"%s\", got \"%s\")", + "wrong zone name in XFR (wanted \"%s\", got \"%s\")", zp->z_origin, dname); hp->rcode = FORMERR; return (-1); } - if (!soa_cnt) { + if (soa_cnt == 0) { badsoa_msg = soa_zinfo(&zp_start, rr_type_ptr, eom); if (badsoa_msg) { syslog(LOG_INFO, @@ -1657,13 +2171,33 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, return (-1); } if (SEQ_GT(zp_start.z_serial, serial_no) || - !serial_no) + !check_serial) { soa_cnt++; - else { + } else { syslog(LOG_INFO, "serial went backwards after transfer started"); return (-1); } + } else if (soa_cnt == 1) { + badsoa_msg = soa_zinfo(&zp_finish, rr_type_ptr, eom); + if (badsoa_msg) { + syslog(LOG_INFO, + "malformed SOA for zone %s: %s", + zp->z_origin, badsoa_msg); + hp->rcode = FORMERR; + return (-1); + } + if (zp_start.z_serial == zp_finish.z_serial) { + methode = ISNOTIXFR; + } else if (zp_finish.z_serial != serial_no) { + syslog(LOG_INFO, + "Unexpected serial number for zone %s: %u", + zp->z_origin, zp_finish.z_serial); + } + soa_cnt++; + if ((methode == ISIXFR) || (soa_cnt >= 2)) { + return (result); + } } else { badsoa_msg = soa_zinfo(&zp_finish, rr_type_ptr, eom); if (badsoa_msg) { @@ -1673,45 +2207,56 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, hp->rcode = FORMERR; return (-1); } - dprintf(2, "SOA, serial %u\n", zp_finish.z_serial); - if (zp_start.z_serial != zp_finish.z_serial) { - dprintf(1, "serial changed, restart\n"); - restarts++; - if (restarts > MAX_XFER_RESTARTS) { - syslog(LOG_INFO, - "too many transfer restarts for zone %s", - zp->z_origin); - hp->rcode = FORMERR; - return (-1); - } - soa_cnt = 0; -#ifdef STUBS - ns_cnt = 0; -#endif - minimum_ttl = 0; - strcpy(prev_origin, zp->z_origin); - prev_dname[0] = DEF_DNAME; - /* - * Flush buffer, truncate file - * and seek to beginning to restart. - */ - fflush(dbfp); - if (ftruncate(fileno(dbfp), 0) != 0) { - if (!quiet) + if (methode == ISIXFR) { + if (zp_start.z_serial == zp_finish.z_serial) { + if (scdsoa) { + soa_cnt = -1; + return (result); + } else { + scdsoa = 1; + soa_cnt++; + }; + } else + soa_cnt++; + } else { + dprintf(2, "SOA, serial %u\n", + zp_finish.z_serial); + if (zp_start.z_serial != zp_finish.z_serial) { + dprintf(1, "serial changed, restart\n"); + restarts++; + if (restarts > MAX_XFER_RESTARTS) { syslog(LOG_INFO, - "ftruncate %s: %m\n", - tmpname); - return (-1); + "too many transfer restarts for zone %s", + zp->z_origin); + hp->rcode = FORMERR; + return (-1); + } + soa_cnt = 0; + ns_cnt = 0; + minimum_ttl = 0; + strcpy(prev_origin, zp->z_origin); + prev_dname[0] = DEF_DNAME; + /* + * Flush buffer, truncate file + * and seek to beginning to restart. + */ + fflush(dbfp); + if (ftruncate(fileno(dbfp), 0) != 0) { + if (!quiet) + syslog(LOG_INFO, + "ftruncate %s: %m\n", + tmpname); + return (-1); + } + fseek(dbfp, 0L, 0); + return (result); } - fseek(dbfp, 0L, 0); + soa_cnt++; return (result); } - soa_cnt++; - return (result); } } -#ifdef STUBS if (zp->z_type == Z_STUB) { if (query_type == T_NS && type == T_NS) ns_cnt++; @@ -1724,9 +2269,8 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, if (query_type == T_SOA && type != T_SOA) return (result); } -#endif - if (!soa_cnt || soa_cnt >= 2) { + if ((!soa_cnt || soa_cnt > 2) && methode == ISNOTIXFR) { char *gripe; if (!soa_cnt) @@ -1756,17 +2300,21 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, * where the remote server sends MX records soon after the * NS records for a particular domain. If sent earlier, we lose. XXX */ - if (!samedomain(dname, domain)) { + if (!ns_samedomain(dname, domain)) { (void) fprintf(dbfp, "; Ignoring info about %s, not in zone %s.\n", dname, domain); ignore = "; "; } else if (type != T_NS && type != T_A && - strcasecmp(zone_top, dname) != 0 && - strcasecmp(prev_ns_dname, dname) == 0) + ns_samename(zone_top, dname) != 1 && + ns_samename(prev_ns_dname, dname) == 1) { (void) fprintf(dbfp, "; Ignoring extra info about %s, invalid after NS delegation.\n", dname); ignore = "; "; + } else if (class != zp->z_class) { + (void) fprintf(dbfp, "; Ignoring info about %s, not class %s\n", + dname, p_class(zp->z_class)); + ignore = "; "; } /* @@ -1794,13 +2342,13 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, /* * If the origin has changed, print the new origin */ - if (strcasecmp(prev_origin, origin)) { + if (ns_samename(prev_origin, origin) != 1) { (void) strcpy(prev_origin, origin); (void) fprintf(dbfp, "%s$ORIGIN %s.\n", ignore, origin); } tab = 0; - if (strcasecmp(prev_dname, dname)) { + if (ns_samename(prev_dname, dname) != 1) { /* * set the prev_dname to be the current dname, then cut off all * characters of dname after (and including) the first '.' @@ -1837,10 +2385,7 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, tab = 1; } - if (ttl != minimum_ttl) - (void) fprintf(dbfp, "%d\t", (int) ttl); - else if (tab) - (void) putc('\t', dbfp); + (void) fprintf(dbfp, "%d\t", (int) ttl); (void) fprintf(dbfp, "%s\t%s\t", p_class(class), p_type(type)); cp = cdata; @@ -2085,8 +2630,8 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, /* algorithm id */ (void) fprintf(dbfp," %d",*cp++); - /* labels (# of labels in name) - skip in textual record */ - cp++; + /* labels (# of labels in name) */ + (void) fprintf(dbfp," %d",*cp++); /* orig time to live (TTL)) */ (void) fprintf(dbfp," %u", (u_int32_t)ns_get32((u_char*)cp)); @@ -2128,6 +2673,33 @@ print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg, fprintf(dbfp,"\n"); break; + case ns_t_cert: { + int databufsize = n * 4 / 3 + 4; + char *databuf = malloc(databufsize); + + if (databuf == NULL) + panic("cert malloc failed", NULL); + + /* Object id */ + (void) fprintf(dbfp,"%d ", ns_get16((u_char*)cp)); + cp += INT16SZ; + + /* Key tag */ + (void) fprintf(dbfp,"%d ", ns_get16((u_char*)cp)); + cp += INT16SZ; + + /* Algorithm id */ + (void) fprintf(dbfp,"%d ", (u_char)*cp); + cp += 1; + + n = b64_ntop(cp, n - 2 * INT16SZ - 1, databuf, databufsize); + if (n < 0) + panic ("cert b64_ntop failed", NULL); + fprintf (dbfp, "%s\n", databuf); + free(databuf); + break; + } + default: cp1 = cp + n; while (cp < cp1) @@ -2175,3 +2747,199 @@ filenamecpy(char *ddtfile, char *optarg) { (void) strcpy(ddtfile, optarg); } #endif /* SHORT_FNAMES */ + +DST_KEY * +tsig_key_from_addr(struct in_addr addr) { + tsig_node *n; + for (n = HEAD(tsig_list); n != NULL; n = NEXT(n, link)) + if (memcpy(&addr, &n->addr, sizeof(struct in_addr))) + return n->dst_key; + return NULL; +} + +static void +do_section(ns_msg *handle, ns_sect section, int pflag, FILE *file, int *delete) { + int n, sflag, rrnum; + char buf[2048]; /* XXX need to malloc */ + ns_opcode opcode; + ns_rr rr; + const unsigned char *cp; + const unsigned char *eom; + u_int32_t serial; + time_t now; + + time(&now); + + /* + * Print answer records. + */ + sflag = (_res.pfcode & pflag); + if (_res.pfcode && !sflag) + 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 && + (_res.pfcode & RES_PRF_HEAD1)) + putc('\n', file); + return; + } + if (rrnum == 0 && sflag != 0 && (_res.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 { + int print_record = 1; + if (rr.type == ns_t_soa) { + print_record = 0; + *delete = !*delete; + cp = ns_rr_rdata(rr); + eom = cp + ns_rr_rdlen(rr); + if ((n = dn_skipname(cp, eom)) < 0) { + rrnum++; + continue; + } + cp += n; + if ((n = dn_skipname(cp, eom)) < 0) { + rrnum++; + continue; + } + cp += n; + NS_GET32(serial, cp); + if (*delete && serial != old_serial) + /*XXX*/; + old_serial = serial; + switch (++ixfr_soa) { + case 1: + final_serial = serial; + if (soa_buf == NULL) { + if ((soa_buf = (char *)malloc(2 * PACKETSZ)) == NULL) { + syslog(LOG_INFO, "malloc(%u) failed", 2 * PACKETSZ); + return; + } + n = ns_sprintrr(handle, &rr, NULL, NULL, + soa_buf, 2*PACKETSZ); + if (n < 0) { + fprintf(file, ";; ns_sprintrr: %s\n", + strerror(errno)); + return; + } + } + print_record = 0; + break; + case 2: + fprintf(file, + "zone:\torigin %s class %s serial %u\n", + ns_rr_name(rr), + p_class(ns_rr_class(rr)), + serial); + print_record = 0; + break; + default: + print_record = 0; + break; + } + + } + + if (print_record) { + if (rr.type != ns_t_soa) { + fprintf(file, "update:\t{%s} ", + *delete ? "delete" : "add"); + + n = ns_sprintrr(handle, &rr, NULL, NULL, + buf, sizeof buf); + if (n < 0) { + fprintf(file, ";; ns_sprintrr: %s\n", + strerror(errno)); + return; + } + fputs(buf, file); + fputc('\n', file); + } + } + + } + rrnum++; + } +} + +static void +ixfr_log(const u_char *msg, int len, int *delete, FILE *file, + struct sockaddr_in *sin, char *domain, u_int32_t serial_no, + int *first_rr) +{ + ns_msg handle; + ns_type type; + ns_class class; + ns_opcode opcode; + ns_rcode rcode; + u_int id, n; + char time[25]; + ns_rr rr; + char *cp; + HEADER *hp; + + if ((_res.options & RES_INIT) == 0 && res_init() == -1) + return; + + if (ns_initparse(msg, len, &handle) < 0) { + fprintf(file, ";; ns_initparse: %s\n", strerror(errno)); + return; + } + opcode = (ns_opcode) ns_msg_getflag(handle, ns_f_opcode); + rcode = (ns_rcode) ns_msg_getflag(handle, ns_f_rcode); + id = ns_msg_id(handle); + + if (ns_parserr(&handle, ns_s_an, 0, &rr)) + { + + (void) fprintf(file,"ns_parserr() failed"); + return; + } + type = (ns_type)rr.type; + class = (ns_class)rr.rr_class; + + if (*first_rr == 1) { + gettime(&tt); + (void) fprintf(file,"%s", LogSignature); + sprintf(time, "at %lu", (u_long)tt.tv_sec); + fprintf(file, + "[IXFR_UPDATE] id %u from [%s].%d %s (named-xfr pid %ld):\n", + id, inet_ntoa(sin->sin_addr), + ntohs(sin->sin_port), time, (long)getpid()); + (*first_rr)++; + } + do_section(&handle, ns_s_an, RES_PRF_ANS, file, delete); +} + +static const char * +tsig_rcode(int rcode) { + static char buffer[64]; + + switch (rcode) { + case ns_r_badkey: + case ns_r_badsig: + case ns_r_badtime: + sprintf(buffer, "message had %s set", p_rcode(rcode)); + return (buffer); + case -ns_r_badkey: + case -ns_r_badsig: + case -ns_r_badtime: + return (p_rcode(-rcode)); + case NS_TSIG_ERROR_NO_TSIG: + return ("no TSIG present"); + default: + break; + } + return ("FORMERR"); +} diff --git a/contrib/bind/bin/named/Makefile b/contrib/bind/bin/named/Makefile index 7e30cd0..6eac2b1 100644 --- a/contrib/bind/bin/named/Makefile +++ b/contrib/bind/bin/named/Makefile @@ -1,4 +1,4 @@ -## Copyright (c) 1996, 1997 by Internet Software Consortium +## 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 @@ -13,7 +13,7 @@ ## ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ## SOFTWARE. -# $Id: Makefile,v 8.31 1998/03/20 00:49:46 halley Exp $ +# $Id: Makefile,v 8.47 1999/08/26 18:42:31 vixie Exp $ DESTDIR= CC= cc @@ -29,18 +29,21 @@ PORTINCL = ${TOP}/port/${SYSTYPE}/include LIBBIND = ${TOP}/lib/libbind.a A=a O=o -LEX = lex -I +EXE= YACC = yacc -d SYSLIBS = -ll -lutil -PIDDIR = /var/run DESTBIN = /usr/local/bin DESTSBIN = /usr/local/sbin DESTEXEC = /usr/local/libexec DESTMAN = /usr/share/man DESTHELP= /usr/share/misc -AR= ar cruv +DESTETC= /etc +DESTRUN= /var/run +AR= ar cru INSTALL= install STRIP=-s +INSTALL_EXEC= +INSTALL_LIB=-o bin -g bin PS=ps LDFLAGS= @@ -52,23 +55,25 @@ HOSTNAMECMD= hostname || uname -n PROG= named HDRS= db_defs.h db_glob.h ns_defs.h ns_glob.h named.h pathnames.h SRCS= db_dump.c db_load.c db_lookup.c db_save.c db_update.c \ - db_glue.c \ - ns_parser.c ns_lexer.c ns_parseutil.c \ + db_glue.c db_ixfr.c db_sec.c db_tsig.c \ + ns_parser.c ns_lexer.c ns_parseutil.c ns_ctl.c \ ns_forw.c ns_init.c ns_main.c ns_maint.c ns_req.c \ ns_resp.c ns_stats.c ns_ncache.c ns_xfr.c ns_glue.c \ - ns_udp.c ns_config.c ns_update.c + ns_udp.c ns_config.c ns_update.c ns_ixfr.c ns_signal.c \ + ns_sort.c ns_notify.c OBJS= db_dump.${O} db_load.${O} db_lookup.${O} db_save.${O} db_update.${O} \ - db_glue.${O} \ - ns_parser.${O} ns_lexer.${O} ns_parseutil.${O} \ + db_glue.${O} db_ixfr.${O} db_sec.${O} db_tsig.${O} \ + ns_parser.${O} ns_lexer.${O} ns_parseutil.${O} ns_ctl.${O} \ ns_forw.${O} ns_init.${O} ns_main.${O} ns_maint.${O} ns_req.${O} \ ns_resp.${O} ns_stats.${O} ns_ncache.${O} ns_xfr.${O} ns_glue.${O} \ - ns_udp.${O} ns_config.${O} ns_update.${O} + ns_udp.${O} ns_config.${O} ns_update.${O} ns_ixfr.${O} ns_signal.${O} \ + ns_sort.${O} ns_notify.${O} -all: ${PROG} pathnames +all: ${PROG}${EXE} -${PROG}: pathnames.h ${OBJS} ${LIBBIND} Makefile tmp_version.${O} - ${CC} ${CDEBUG} ${LDFLAGS} -o ${PROG} ${OBJS} tmp_version.${O} \ - ${LIBBIND} ${SYSLIBS} +${PROG}${EXE}: pathnames.h ${OBJS} ${LIBBIND} Makefile tmp_version.${O} + ${CC} ${CDEBUG} ${LDFLAGS} ${BOUNDS} -o ${PROG}${EXE} ${OBJS} \ + tmp_version.${O} ${LIBBIND} ${SYSLIBS} ns_parser.c ns_parser.h: ns_parser.y ${YACC} ns_parser.y @@ -83,7 +88,7 @@ tmp_version.c: version.c Makefile ../Makefile ${SRCS} ${HDRS} -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \ < version.c > tmp_version.c) -pathnames.h: ${TOP}/.settings Makefile +pathnames.h: ${TOP}/.settings Makefile pathtemplate.h rm -f pathnames.h sed -e "s|%DESTSBIN%|${DESTSBIN}|" \ -e "s|%DESTEXEC%|${DESTEXEC}|" \ @@ -91,19 +96,20 @@ pathnames.h: ${TOP}/.settings Makefile -e "s|%DESTRUN%|${DESTRUN}|" \ < pathtemplate.h > pathnames.h -pathnames: pathnames.${O} pathnames.h ${LIBBIND} Makefile - ${CC} ${CDEBUG} ${LDFLAGS} -o $@ pathnames.${O} \ - ${LIBBIND} ${SYSLIBS} +ns_signal.${O}: ns_signal.c + ${CC} ${CPPFLAGS} ${CFLAGS} -c $*.c + +.c.${O}: + ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c distclean: clean rm -f ns_parser.c ns_parser.h clean: FRC - rm -f ${PROG} ${OBJS} core .depend + rm -f ${PROG}${EXE} ${OBJS} core .depend rm -f *.BAK *.CKP *~ *.orig rm -f tmp_version.c tmp_version.${O} - rm -f pathnames pathnames.${O} tmp_pathnames.h pathnames.h - rm -f y.tab.h y.tab.c + rm -f pathnames.h y.tab.h y.tab.c depend: ${SRCS} pathnames.h mkdep ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${DEFS} ${SRCS} @@ -111,8 +117,8 @@ depend: ${SRCS} pathnames.h ${DESTDIR}${DESTSBIN}: mkdir -p ${DESTDIR}${DESTSBIN} -install: ${DESTDIR}${DESTSBIN} ${PROG} - ${INSTALL} ${STRIP} -c -m 755 ${PROG} ${DESTDIR}${DESTSBIN}/${PROG} +install: ${DESTDIR}${DESTSBIN} ${PROG}${EXE} + ${INSTALL} ${STRIP} -c ${INSTALL_EXEC} -m 755 ${PROG}${EXE} ${DESTDIR}${DESTSBIN}/${PROG}${EXE} links: FRC @ln -s SRC/*.[chy] SRC/test .; rm -f ns_parser.[ch] diff --git a/contrib/bind/bin/named/db_defs.h b/contrib/bind/bin/named/db_defs.h index ab93480..9fe2021 100644 --- a/contrib/bind/bin/named/db_defs.h +++ b/contrib/bind/bin/named/db_defs.h @@ -1,9 +1,10 @@ /* * from db.h 4.16 (Berkeley) 6/1/90 - * $Id: db_defs.h,v 8.17 1998/02/17 17:17:43 vixie Exp $ + * $Id: db_defs.h,v 8.36 1999/08/26 18:42:32 vixie Exp $ */ -/* Copyright (c) 1985, 1990 +/* + * Copyright (c) 1985, 1990 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,7 +36,8 @@ * SUCH DAMAGE. */ -/* Portions Copyright (c) 1993 by Digital Equipment Corporation. +/* + * 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 @@ -54,7 +56,8 @@ * SOFTWARE. */ -/* Portions Copyright (c) 1996, 1997 by Internet Software Consortium. +/* + * 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 @@ -74,12 +77,12 @@ * Global definitions for data base routines. */ -#define INVBLKSZ 7 /* # of namebuf pointers per block */ -#define INVHASHSZ 919 /* size of inverse hash table */ - /* max length of data in RR data field */ #define MAXDATA (2*MAXDNAME + 5*INT32SZ) + /* max length of data in a TXT RR segment */ +#define MAXCHARSTRING 255 + #define DB_ROOT_TIMBUF 3600 #define TIMBUF 300 @@ -87,6 +90,16 @@ #define DICT_MAXLENGTH 127 #define DICT_INSERT_P 0x0001 +/* Average hash chain depths. */ +#define AVGCH_MARSHAL 5 +#define AVGCH_NLOOKUP 3 + +/* Nonstandard maximum class to force better packing. */ +#define ZONE_BITS 24 +#define CLASS_BITS 8 +#define ZONE_MAX ((1<<ZONE_BITS)-1) +#define CLASS_MAX ((1<<CLASS_BITS)-1) + /* * Hash table structures. */ @@ -101,17 +114,18 @@ struct databuf { * primary and secondary zones), * d_ttl is the time to live. */ - unsigned d_flags :7; /* see below */ + unsigned d_zone :ZONE_BITS; /* zone number or 0 for the cache */ + unsigned d_class :CLASS_BITS; /* class number (nonstandard limit) */ + unsigned d_flags :4; /* DB_F_{??????} */ + unsigned d_secure :2; /* DB_S_{??????} */ unsigned d_cred :3; /* DB_C_{??????} */ unsigned d_clev :6; - u_int16_t d_zone; /* zone number or 0 for the cache */ - int16_t d_class; /* class number */ + unsigned d_rcode :4; /* rcode for negative caching */ + unsigned d_mark :3; /* place to mark data */ int16_t d_type; /* type number */ int16_t d_size; /* size of data area */ u_int32_t d_rcnt; - unsigned d_rcode :4; /* rcode for negative caching */ - unsigned d_mark :12; /* place to mark data */ - u_int16_t d_nstime; /* NS response time, milliseconds */ + u_int16_t d_nstime; /* NS response time, milliseconds */ u_char d_data[sizeof(void*)]; /* dynamic (padded) */ }; #define DATASIZE(n) (sizeof(struct databuf) - sizeof(void*) + n) @@ -131,6 +145,7 @@ struct databuf { #define DB_F_HINT 0x01 /* databuf belongs to fcachetab */ #define DB_F_ACTIVE 0x02 /* databuf is linked into a cache */ #define DB_F_FREE 0x04 /* databuf has been freed */ +#define DB_F_LAME 0x08 /* databuf may refer to lame server */ /* * d_cred definitions @@ -141,6 +156,13 @@ struct databuf { #define DB_C_ADDITIONAL 1 /* additional data */ #define DB_C_CACHE 0 /* cache - worst */ +/* + * d_secure definitions + */ +#define DB_S_SECURE 2 /* secure (verified) data */ +#define DB_S_INSECURE 1 /* insecure data */ +#define DB_S_FAILED 0 /* data that failed a security check */ + struct namebuf { u_int n_hashval; /* hash value of _n_name */ struct namebuf *n_next; /* linked list */ @@ -162,6 +184,51 @@ struct hashbuf { #define HASHSHIFT 3 #define HASHMASK 0x1f +#define HASHROTATE(v) \ + (((v) << HASHSHIFT) | ((v) >> ((sizeof(v) * 8) - HASHSHIFT))) +#define HASHLOWER(c) ((isascii(c) && isupper(c)) ? tolower(c) : (c)) +#define HASHIMILATE(v,c) ((v) = (HASHROTATE(v)) + (HASHLOWER(c) & HASHMASK)) + +#define TSIG_BUF_SIZE 640 +#define TSIG_SIG_SIZE 20 + +struct tsig_record { + u_int8_t sig[TSIG_SIG_SIZE]; + struct dst_key *key; + int siglen; +}; + +struct sig_record { + u_int16_t sig_type_n; + u_int8_t sig_alg_n, sig_labels_n; + u_int32_t sig_ottl_n, sig_exp_n, sig_time_n; + u_int16_t sig_keyid_n; +}; + +/* This is the wire format size of "struct sig_record", i.e., no padding. */ +#define SIG_HDR_SIZE 18 + +struct dnode { + struct databuf *dp; + struct dnode *dn_next; + int line; + char *file; +}; + +typedef struct dnode * dlist; + +struct db_rrset { + dlist rr_list; + dlist rr_sigs; + char *rr_name; + int16_t rr_class; + int16_t rr_type; + struct db_rrset *rr_next; +}; +#define DBHASHSIZE(s) (sizeof(struct hashbuf) + \ + (s-1) * sizeof(struct db_rrset *)) + +#define SIG_COVERS(dp) (ns_get16(dp->d_data)) /* * Flags to updatedb @@ -172,6 +239,8 @@ struct hashbuf { #define DB_NOTAUTH 0x08 /* must not update authoritative data */ #define DB_NOHINTS 0x10 /* don't reflect update in fcachetab */ #define DB_PRIMING 0x20 /* is this update the result of priming? */ +#define DB_MERGE 0x40 /* make no control on rr in db_update (for ixfr) */ +#define DB_REPLACE 0x80 /* replace data if it exists */ #define DB_Z_CACHE 0 /* cache-zone-only db_dump() */ #define DB_Z_ALL 65535 /* normal db_dump() */ @@ -194,6 +263,8 @@ struct hashbuf { #ifdef BIND_UPDATE #define SERIAL (-11) #endif +#define CNAMEANDOTHER (-12) +#define DNSSECFAIL (-13) /* db_set_update */ /* * getnum() options @@ -203,13 +274,18 @@ struct hashbuf { #define GETNUM_SCALED 0x02 /* permit "k", "m" suffixes, scale result */ /* + * db_load() options + */ +#define ISNOTIXFR 0 +#define ISIXFR 1 +#define ISAXFRIXFR 2 + +/* * Database access abstractions. */ #define foreach_rr(dp, np, ty, cl, zn) \ for ((dp) = (np)->n_data; (dp) != NULL; (dp) = (dp)->d_next) \ - if ((cl) != C_ANY && (cl) != (dp)->d_class) \ - continue; \ - else if ((ty) != T_ANY && (ty) != (dp)->d_type) \ + if (!match(dp, (cl), (ty))) \ continue; \ else if (((zn) == DB_Z_CACHE) \ ? stale(dp) \ diff --git a/contrib/bind/bin/named/db_dump.c b/contrib/bind/bin/named/db_dump.c index 9c15af3..75a59b7 100644 --- a/contrib/bind/bin/named/db_dump.c +++ b/contrib/bind/bin/named/db_dump.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)db_dump.c 4.33 (Berkeley) 3/3/91"; -static char rcsid[] = "$Id: db_dump.c,v 8.24 1998/02/13 19:49:09 halley Exp $"; +static const char sccsid[] = "@(#)db_dump.c 4.33 (Berkeley) 3/3/91"; +static const char rcsid[] = "$Id: db_dump.c,v 8.40 1999/10/13 16:39:01 vixie Exp $"; #endif /* not lint */ /* @@ -82,7 +82,7 @@ static char rcsid[] = "$Id: db_dump.c,v 8.24 1998/02/13 19:49:09 halley Exp $"; */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -104,6 +104,7 @@ static char rcsid[] = "$Id: db_dump.c,v 8.24 1998/02/13 19:49:09 halley Exp $"; #include <sys/param.h> #include <sys/stat.h> #include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -141,7 +142,7 @@ doadump() return; gettime(&tt); fprintf(fp, "; Dumped at %s", ctimel(tt.tv_sec)); - if (zones && nzones) + if (zones != NULL && nzones != 0) zt_dump(fp); fputs( "; Note: Cr=(auth,answer,addtnl,cache) tag only shown for non-auth RR's\n", @@ -164,7 +165,7 @@ zt_dump(FILE *fp) { struct zoneinfo *zp; fprintf(fp, ";; ++zone table++\n"); - for (zp = &zones[1]; zp < &zones[nzones]; zp++) { + for (zp = &zones[0]; zp < &zones[nzones]; zp++) { char *pre, buf[64]; u_int cnt; @@ -183,8 +184,8 @@ zt_dump(FILE *fp) { fprintf(fp, ";\trefresh=%u, retry=%u, expire=%u, minimum=%u\n", zp->z_refresh, zp->z_retry, zp->z_expire, zp->z_minimum); - fprintf(fp, ";\tftime=%lu, xaddr=[%s], state=%04x, pid=%d\n", - (u_long)zp->z_ftime, inet_ntoa(zp->z_xaddr), + fprintf(fp, ";\tftime=%lu, xaddrcnt=%d, state=%04x, pid=%d\n", + (u_long)zp->z_ftime, zp->z_xaddrcnt, zp->z_flags, (int)zp->z_xferpid); sprintf(buf, ";\tz_addr[%d]: ", zp->z_addrcnt); pre = buf; @@ -195,7 +196,7 @@ zt_dump(FILE *fp) { if (zp->z_addrcnt) fputc('\n', fp); if (zp->z_axfr_src.s_addr != 0) - fprintf(fp, "; update source [%s]\n", + fprintf(fp, ";\tupdate source [%s]\n", inet_ntoa(zp->z_axfr_src)); } fprintf(fp, ";; --zone table--\n"); @@ -209,13 +210,12 @@ db_dump(struct hashbuf *htp, FILE *fp, int zone, char *origin) { struct namebuf **npp, **nppend; char dname[MAXDNAME]; u_int32_t n; - u_int32_t addr; int j, i, found_data, tab, printed_origin; u_char *cp, *end; const char *proto, *sep; int16_t type; u_int16_t keyflags; - u_char *sigdata; + u_char *sigdata, *certdata; u_char *savecp; char temp_base64[NS_MD5RSA_MAX_BASE64]; @@ -275,11 +275,11 @@ db_dump(struct hashbuf *htp, FILE *fp, int zone, char *origin) { else fprintf(fp, "%d\t", (int)(dp->d_ttl - tt.tv_sec)); - } else if (dp->d_ttl != USE_MINIMUM && - dp->d_ttl != zones[dp->d_zone].z_minimum) + } else if (dp->d_ttl != USE_MINIMUM) fprintf(fp, "%d\t", (int)dp->d_ttl); - else if (tab) - (void) putc('\t', fp); + else + fprintf(fp, "%d\t", + zones[dp->d_zone].z_minimum); fprintf(fp, "%s\t%s\t", p_class(dp->d_class), p_type(dp->d_type)); @@ -538,9 +538,8 @@ db_dump(struct hashbuf *htp, FILE *fp, int zone, char *origin) { fprintf(fp, "%s ", p_type(n)); /* Algorithm id (8-bit decimal) */ fprintf(fp, "%d ", *cp++); - /* Labels (8-bit decimal) (not saved in file) */ - /* FIXME -- check value and print err if bad */ - cp++; + /* Labels (8-bit decimal) */ + fprintf(fp, "%d ", *cp++); /* OTTL (u_long) */ NS_GET32(n, cp); fprintf(fp, "%u ", n); @@ -573,10 +572,28 @@ db_dump(struct hashbuf *htp, FILE *fp, int zone, char *origin) { i = 8 * (dp->d_size - n); /* How many bits? */ for (n = 0; n < (u_int32_t)i; n++) { if (NS_NXT_BIT_ISSET(n, cp)) - fprintf(fp," %s",__p_type(n)); + fprintf(fp," %s", p_type(n)); } break; + case ns_t_cert: + certdata = cp; + NS_GET16(n,cp); + fprintf(fp, "%d ", n); /* cert type */ + + NS_GET16(n,cp); + fprintf(fp, "%d %d ", n, *cp++); /* tag & alg */ + + /* Certificate (base64 of any length) */ + i = b64_ntop(cp, + dp->d_size - (cp - certdata), + temp_base64, sizeof(temp_base64)); + if (i < 0) + fprintf(fp, "; BAD BASE64"); + else + fprintf(fp, "%s", temp_base64); + break; + default: fprintf(fp, "%s?d_type=%d?", sep, dp->d_type); @@ -591,6 +608,17 @@ db_dump(struct hashbuf *htp, FILE *fp, int zone, char *origin) { sep, dp->d_clev); sep = " "; } + if ((dp->d_flags & DB_F_LAME) != 0) { + time_t when; + getname(np, dname, sizeof(dname)); + when = db_lame_find(dname, dp); + if (when != 0 && when > tt.tv_sec) { + fprintf(fp, "%sLAME=%d", + sep, when - tt.tv_sec); + sep = " "; + } + } + eoln: if (dp->d_ns != NULL){ fprintf(fp, "%s[%s]", diff --git a/contrib/bind/bin/named/db_func.h b/contrib/bind/bin/named/db_func.h index 2d4c05b..9ba5299 100644 --- a/contrib/bind/bin/named/db_func.h +++ b/contrib/bind/bin/named/db_func.h @@ -1,4 +1,5 @@ -/* Copyright (c) 1985, 1990 +/* + * Copyright (c) 1985, 1990 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,7 +31,8 @@ * SUCH DAMAGE. */ -/* Portions Copyright (c) 1993 by Digital Equipment Corporation. +/* + * 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 @@ -49,7 +51,8 @@ * SOFTWARE. */ -/* Portions Copyright (c) 1996, 1997 by Internet Software Consortium. +/* + * 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 @@ -65,9 +68,29 @@ * SOFTWARE. */ +/* + * Portions Copyright (c) 1999 by Check Point Software Technologies, 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, and that + * the name of Check Point Software Technologies Incorporated 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 CHECK POINT SOFTWARE TECHNOLOGIES + * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED + * 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. + */ + /* db_proc.h - prototypes for functions in db_*.c * - * $Id: db_func.h,v 8.22 1997/12/04 06:47:00 halley Exp $ + * $Id: db_func.h,v 8.40 1999/10/07 08:24:06 vixie Exp $ */ /* ++from db_update.c++ */ @@ -96,19 +119,30 @@ extern void doadump(void); /* --from db_dump.c-- */ /* ++from db_load.c++ */ +extern int makename_ok(char *name, const char *origin, int class, + struct zoneinfo *zp, + enum transport transport, + enum context context, + const char *owner, const char *filename, + int lineno, int size); extern void endline(FILE *); extern int getword(char *, size_t, FILE *, int), + getttl(FILE *, const char *, int, u_int32_t *, int *), getnum(FILE *, const char *, int), - db_load(const char *, const char *, - struct zoneinfo *, const char *); + db_load(const char *, const char *, struct zoneinfo *, + const char *, int); extern int getnonblank(FILE *, const char *), getservices(int, char *, FILE *, const char *); extern char getprotocol(FILE *, const char *); extern int makename(char *, const char *, int); -#ifdef BIND_NOTIFY -extern void notify_after_load(evContext, void *, const void *), - db_cancel_pending_notifies(void); -#endif +extern void db_err(int, char *, int, const char *, int); +extern int parse_sec_rdata(char *inp, int inp_len, int inp_full, + u_char *data, int data_len, + FILE *fp, struct zoneinfo *zp, + char *domain, u_int32_t ttl, + int type, enum context context, + enum transport transport, + char **errmsg); /* --from db_load.c-- */ /* ++from db_glue.c++ */ @@ -119,10 +153,8 @@ extern void buildservicelist(void), getname(struct namebuf *, char *, int); extern int servicenumber(const char *), protocolnumber(const char *), - get_class(const char *), - samedomain(const char *, const char *); -extern u_int dhash(const u_char *, int), - nhash(const char *); + get_class(const char *); +extern u_int nhash(const char *); extern const char *protocolname(int), *servicename(u_int16_t, const char *); #ifndef BSD @@ -137,15 +169,45 @@ extern struct namebuf *rm_name(struct namebuf *, struct namebuf *); extern void rm_hash(struct hashbuf *); extern void db_freedata(struct databuf *); +extern void db_lame_add(char *zone, char *server, time_t when); +extern time_t db_lame_find(char *zone, struct databuf *dp); +extern void db_lame_clean(void); +extern void db_lame_destroy(void); /* --from db_glue.c-- */ /* ++from db_lookup.c++ */ extern struct namebuf *nlookup(const char *, struct hashbuf **, const char **, int); extern struct namebuf *np_parent __P((struct namebuf *)); -extern int match(struct databuf *, int, int); +extern int match(struct databuf *, int, int), + nxtmatch(const char *, struct databuf *, + struct databuf *), + rrmatch(const char *, struct databuf *, + struct databuf *); /* --from db_lookup.c-- */ -/* ++from db_dict.c++ */ -int dict_lookup(const char *, int, int); -/* --from db_dict.c-- */ +/* ++from db_ixfr.c++ */ +struct ns_updrec * ixfr_get_change_list(struct zoneinfo *, u_int32_t, + u_int32_t); +int ixfr_have_log(struct zoneinfo *, u_int32_t, + u_int32_t); +/* --from db_ixfr.c++ */ + +/* ++from db_sec.c++ */ +int add_trusted_key(const char *name, const int flags, + const int proto, const int alg, + const char *str); +int db_set_update(char *name, struct databuf *dp, + void **state, int flags, + struct hashbuf **htp, + struct sockaddr_in from, + int *rrcount, int line, + const char *file); +/* --from db_sec.c-- */ +/* ++from db_tsig.c++ */ +char * tsig_alg_name(int value); +int tsig_alg_value(char *name); +struct dst_key * tsig_key_from_addr(struct in_addr addr); +struct tsig_record * new_tsig(struct dst_key *key, u_char *sig, int siglen); +void free_tsig(struct tsig_record *tsig); +/* --from db_tsig.c-- */ diff --git a/contrib/bind/bin/named/db_glob.h b/contrib/bind/bin/named/db_glob.h index 79d915d..3d11739 100644 --- a/contrib/bind/bin/named/db_glob.h +++ b/contrib/bind/bin/named/db_glob.h @@ -1,9 +1,10 @@ /* * from db.h 4.16 (Berkeley) 6/1/90 - * $Id: db_glob.h,v 8.8 1997/06/09 17:46:51 halley Exp $ + * $Id: db_glob.h,v 8.12 1999/08/08 21:10:01 vixie Exp $ */ -/* Copyright (c) 1985, 1990 +/* + * Copyright (c) 1985, 1990 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,7 +36,8 @@ * SUCH DAMAGE. */ -/* Portions Copyright (c) 1993 by Digital Equipment Corporation. +/* + * 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 @@ -54,7 +56,8 @@ * SOFTWARE. */ -/* Portions Copyright (c) 1996, 1997 by Internet Software Consortium. +/* + * 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 @@ -75,20 +78,26 @@ */ /* ONE_WEEK maximum ttl */ -DECL u_int max_cache_ttl INIT(7*24*60*60); +DECL u_int max_cache_ttl INIT(7*24*60*60); /* no minimum ttl */ -DECL u_int min_cache_ttl INIT(0); +DECL u_int min_cache_ttl INIT(0); /* current line number */ -DECL int lineno; +DECL int lineno INIT(0); /* root hash table */ -DECL struct hashbuf *hashtab INIT(NULL); +DECL struct hashbuf *hashtab INIT(NULL); /* hash table of cache read from file */ -DECL struct hashbuf *fcachetab INIT(NULL); +DECL struct hashbuf *fcachetab INIT(NULL); + + /* state of ns_reload() and ns_reconfig(). */ +DECL int reloading INIT(0); +DECL int reconfiging INIT(0); -#ifdef FORCED_RELOAD -DECL int reloading INIT(0); -#endif /* FORCED_RELOAD */ +DECL const int hashsizes[] +#ifdef MAIN_PROGRAM + = { 2, 11, 113, 337, 977, 2053, 4073, 8011, 16001, 99887, 0 } +#endif + ; diff --git a/contrib/bind/bin/named/db_glue.c b/contrib/bind/bin/named/db_glue.c index bc6aed4..f1fae69 100644 --- a/contrib/bind/bin/named/db_glue.c +++ b/contrib/bind/bin/named/db_glue.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)db_glue.c 4.4 (Berkeley) 6/1/90"; -static char rcsid[] = "$Id: db_glue.c,v 8.27 1998/02/14 00:41:39 halley Exp $"; +static const char sccsid[] = "@(#)db_glue.c 4.4 (Berkeley) 6/1/90"; +static const char rcsid[] = "$Id: db_glue.c,v 8.39 1999/10/15 19:48:57 vixie Exp $"; #endif /* not lint */ /* @@ -57,7 +57,7 @@ static char rcsid[] = "$Id: db_glue.c,v 8.27 1998/02/14 00:41:39 halley Exp $"; */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -79,6 +79,8 @@ static char rcsid[] = "$Id: db_glue.c,v 8.27 1998/02/14 00:41:39 halley Exp $"; #include <sys/uio.h> #include <sys/param.h> #include <sys/stat.h> +#include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/inet.h> @@ -147,6 +149,7 @@ destroyservicelist() { freestr(slp->proto); memput(slp, sizeof *slp); } + servicelist = NULL; } void @@ -183,6 +186,7 @@ destroyprotolist() { freestr(plp->name); memput(plp, sizeof *plp); } + protolist = NULL; } static int @@ -451,29 +455,11 @@ getname(struct namebuf *np, char *buf, int buflen) { *cp = '\0'; } -/* - * Compute hash value from data. - */ -u_int -dhash(const u_char *dp, int dlen) { - u_char *cp; - u_int hval; - int n; - - n = dlen; - if (n > 8) - n = 8; - hval = 0; - while (--n >= 0) { - hval <<= 1; - hval += *dp++; - } - return (hval % INVHASHSZ); -} - /* u_int * nhash(name) * compute hash for this name and return it; ignore case differences + * note: + * this logic is intended to produce the same result as nlookup()'s. */ u_int nhash(const char *name) { @@ -481,136 +467,190 @@ nhash(const char *name) { u_int hval; hval = 0; - while ((ch = (u_char)*name++) != (u_char)'\0') { - if (isascii(ch) && isupper(ch)) - ch = tolower(ch); - hval <<= 1; - hval += ch; - } - return (hval % INVHASHSZ); + while ((ch = (u_char)*name++) != (u_char)'\0') + HASHIMILATE(hval, ch); + return (hval); } -/* -** SAMEDOMAIN -- Check whether a name belongs to a domain -** ------------------------------------------------------ -** -** Returns: -** TRUE if the given name lies in the domain. -** FALSE otherwise. -** -** 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" -*/ +void +db_freedata(struct databuf *dp) { + int bytes = DATASIZE(dp->d_size); -int -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 && 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 && 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--; - } + if (dp->d_rcnt != 0) + panic("db_freedata: d_rcnt != 0", NULL); + if ((dp->d_flags & (DB_F_ACTIVE|DB_F_FREE)) != 0) + panic("db_freedata: %s set", + (dp->d_flags & DB_F_FREE) != 0 ? "DB_F_FREE" : + "DB_F_ACTIVE"); + if (dp->d_next != NULL) + panic("db_free: d_next != NULL", NULL); + dp->d_flags |= DB_F_FREE; + memput(dp, bytes); +} - /* lb==0 means 'b' is the root domain, so 'a' must be in 'b'. */ - if (lb == 0) - return (1); +struct lame_hash { + struct lame_hash *next; + char *zone; + char *server; + time_t when; + unsigned int hval; +} **lame_hash = NULL; - /* 'b' longer than 'a' means 'a' can't be in 'b'. */ - if (lb > la) - return (0); +static int lame_hash_size = 0; +static int lame_hash_cnt = 0; - /* We use strncasecmp because we might be trying to - * ignore a trailing dot. */ - if (lb == la) - return (strncasecmp(a, b, lb) == 0); +void +db_lame_add(char *zone, char *server, time_t when) { + unsigned int hval = nhash(zone); + struct lame_hash *last, *this; + struct lame_hash **new; + int n; + int newsize; + + db_lame_clean(); + + /* grow / initalise hash table */ + if (lame_hash_cnt >= lame_hash_size) { + if (lame_hash_size == 0) + newsize = hashsizes[0]; + else { + for (n = 0; (newsize = hashsizes[n++]) != 0; (void)NULL) + if (lame_hash_size == newsize) { + newsize = hashsizes[n]; + break; + } + if (newsize == 0) + newsize = lame_hash_size * 2 + 1; + } + new = memget(newsize * sizeof this); + if (new == NULL) + return; + memset(new, 0, newsize * sizeof this); + for (n = 0 ; n < lame_hash_size; n++) { + this = lame_hash[n]; + while (this) { + last = this; + this = this->next; + last->next = new[hval%newsize]; + new[hval%newsize] = last; + } + } + if (lame_hash != NULL) + memput(lame_hash, lame_hash_size * sizeof this); + lame_hash = new; + lame_hash_size = newsize; + } - /* Ok, we know la > lb. */ + last = NULL; + this = lame_hash[hval%lame_hash_size]; + while (this) { + if ((ns_samename(this->server, server) == 1) && + (ns_samename(this->zone, zone) == 1)) { + this->when = when; + return; + } + last = this; + this = this->next; + } + this = memget(sizeof *this); + if (this == NULL) + return; + this->server = savestr(server, 0); + this->zone = savestr(zone, 0); + if (this->server == NULL || this->zone == NULL) { + if (this->server != NULL) + freestr(this->server); + if (this->zone != NULL) + freestr(this->zone); + memput(this, sizeof *this); + return; + } + this->when = when; + this->hval = hval; + this->next = NULL; + if (last != NULL) + last->next = this; + else + lame_hash[hval%lame_hash_size] = this; + lame_hash_cnt++; +} - diff = la - lb; +time_t +db_lame_find(char *zone, struct databuf *dp) { + unsigned int hval = nhash(zone); + struct lame_hash *this; - /* 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) + if (lame_hash_size == 0) { + /* db_lame_destroy() must have been called. */ + dp->d_flags &= ~DB_F_LAME; 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); + db_lame_clean(); /* Remove expired record so that we can + * clear DB_F_LAME when there are no + * additions. */ - /* 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); - - /* We use strncasecmp because we might be trying to - * ignore trailing dots. */ - cp = a + diff; - return (strncasecmp(cp, b, lb) == 0); + this = lame_hash[hval % lame_hash_size]; + while (this) { + if ((ns_samename(this->server, (char*)dp->d_data) == 1) && + (ns_samename(this->zone, zone) == 1)) + return (this->when); + this = this->next; + } + dp->d_flags &= ~DB_F_LAME; + return (0); } void -db_freedata(struct databuf *dp) { - int bytes = (dp->d_type == T_NS) ? - DATASIZE(dp->d_size)+INT32SZ : DATASIZE(dp->d_size); +db_lame_clean(void) { + int i; + struct lame_hash *last, *this; + + for (i = 0 ; i < lame_hash_size; i++) { + last = NULL; + this = lame_hash[i]; + while (this != NULL) { + if (this->when < tt.tv_sec) { + freestr(this->zone); + freestr(this->server); + if (last != NULL) { + last->next = this->next; + memput(this, sizeof *this); + this = last->next; + } else { + lame_hash[i] = this->next; + memput(this, sizeof *this); + this = lame_hash[i]; + } + lame_hash_cnt--; + } else { + last = this; + this = this->next; + } + } + } +} - if (dp->d_rcnt != 0) - panic("db_freedata: d_rcnt != 0", NULL); - if ((dp->d_flags & (DB_F_ACTIVE|DB_F_FREE)) != 0) - panic("db_freedata: %s set", - (dp->d_flags & DB_F_FREE) != 0 ? "DB_F_FREE" : - "DB_F_ACTIVE"); - if (dp->d_next != NULL) - panic("db_free: d_next != NULL", NULL); - dp->d_flags |= DB_F_FREE; - memput(dp, bytes); +void +db_lame_destroy(void) { + int i; + struct lame_hash *last, *this; + + if (lame_hash_size == 0) + return; + + for (i = 0 ; i < lame_hash_size; i++) { + this = lame_hash[i]; + while (this != NULL) { + last = this; + this = this->next; + freestr(last->zone); + freestr(last->server); + memput(last, sizeof *this); + } + } + memput(lame_hash, lame_hash_size * sizeof this); + lame_hash_cnt = 0; + lame_hash_size = 0; + lame_hash = NULL; } diff --git a/contrib/bind/bin/named/db_ixfr.c b/contrib/bind/bin/named/db_ixfr.c new file mode 100644 index 0000000..a009f4d --- /dev/null +++ b/contrib/bind/bin/named/db_ixfr.c @@ -0,0 +1,861 @@ +#if !defined(lint) && !defined(SABER) +static char rcsid[] = "$Id: db_ixfr.c,v 8.18 1999/10/15 19:48:57 vixie Exp $"; +#endif /* not lint */ + +/* + * Portions Copyright (c) 1999 by Check Point Software Technologies, 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, and that + * the name of Check Point Software Technologies Incorporated 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 CHECK POINT SOFTWARE TECHNOLOGIES + * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED + * 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. + */ + +/* + * Manage ixfr transaction log + */ + +#include "port_before.h" + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/stat.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 <res_update.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <time.h> + +#include <isc/eventlib.h> +#include <isc/logging.h> + +#include "port_after.h" + +#include "named.h" + +#define DBIXFR_ERROR -1 +#define DBIXFR_FOUND_RR 2 +#define DBIXFR_END 3 + +static int ixfr_getrr(struct zoneinfo *, FILE *, const char *, char *, + ns_updrec **, u_int32_t *, u_int32_t *); + +ns_updrec * +ixfr_get_change_list(struct zoneinfo *zp, + u_int32_t from_serial, u_int32_t to_serial) +{ + FILE * fp; + u_int32_t old_serial, new_serial; + char origin[MAXDNAME]; + struct namebuf *np, *listnp, *finlistnp; + LIST(ns_updrec) listuprec; + int ret, mode; + ns_updrec *uprec; + + if (SEQ_GT(from_serial, to_serial)) + return (NULL); + listnp = finlistnp = NULL; + INIT_LIST(listuprec); + if ((fp = fopen(zp->z_ixfr_base, "r")) == NULL) { + ns_warning(ns_log_db, "%s: %s", + zp->z_ixfr_base, strerror(errno)); + return (NULL); + } + strcpy(origin, zp->z_origin); + lineno = 1; + np = NULL; + mode = 0; + old_serial = new_serial = 0; + for (;;) { + ret = ixfr_getrr(zp, fp, zp->z_ixfr_base, origin, &uprec, + &old_serial, &new_serial); + switch (ret) { + case DBIXFR_ERROR: + (void) my_fclose(fp); + ns_warning(ns_log_db, "Logical error in %s line %d", + zp->z_ixfr_base, lineno); + return (NULL); + case DBIXFR_FOUND_RR: + if (EMPTY(listuprec)) { + /* skip updates prior to the one we want */ + if (uprec->r_zone != from_serial) { + while (uprec != NULL) { + ns_updrec *prev; + + if (uprec->r_dp != NULL) + db_freedata(uprec->r_dp); + uprec->r_dp = NULL; + prev = PREV(uprec, r_link); + res_freeupdrec(uprec); + uprec = prev; + } + break; + } + } + APPEND(listuprec, uprec, r_link); + /* continue; */ + break; + case DBIXFR_END: + (void) my_fclose(fp); + return (HEAD(listuprec)); + default: + (void) my_fclose(fp); + return (NULL); + } + } +} + +/* + * int ixfr_have_log(struct zoneinfo *zp,u_int32_t from_serial, + * u_int32_t to_serial) + * + * verify that ixfr transaction log contains changes + * from from_serial to to_serial + * + * returns: + * 0 = serial number is up to date + * 1 = transision is possible + * -1 = error while opening the ixfr transaction log + * -2 = error in parameters + * -3 = logical error in the history file + */ +int +ixfr_have_log(struct zoneinfo *zp, u_int32_t from_serial, u_int32_t to_serial) +{ + FILE *fp; + u_int32_t old_serial = 0, new_serial = 0; + char buf[BUFSIZ]; + char *cp; + struct stat st; + int nonempty_lineno = -1, prev_pktdone = 0, cont = 0, + inside_next = 0; + int err; + int id, rcode = NOERROR; + + if (SEQ_GT(from_serial, to_serial)) + return (-2); + if (from_serial == to_serial) + return (0); + /* If there is no log file, just return. */ + if (zp->z_ixfr_base == NULL || zp->z_updatelog == NULL) + return (-1); + if (stat(zp->z_ixfr_base, &st) < 0) { + if (errno != ENOENT) + ns_error(ns_log_db, + "unexpected stat(%s) failure: %s", + zp->z_ixfr_base, strerror(errno)); + return (-1); + } + if ((fp = fopen(zp->z_ixfr_base, "r")) == NULL) { + ns_warning(ns_log_db, "%s: %s", + zp->z_ixfr_base, strerror(errno)); + return (-1); + } + if (fgets(buf, sizeof(buf), fp) == NULL) { + ns_error(ns_log_update, "fgets() from %s failed: %s", + zp->z_updatelog, strerror(errno)); + fclose(fp); + return (-1); + } + if (strcmp(buf, LogSignature) != 0) { + ns_error(ns_log_update, "invalid log file %s", + zp->z_updatelog); + fclose(fp); + return (-3); + } + lineno = 1; + for (;;) { + if (getword(buf, sizeof buf, fp, 0)) { + nonempty_lineno = lineno; + } else { + if (lineno == (nonempty_lineno + 1)) + continue; + inside_next = 0; + prev_pktdone = 1; + cont = 1; + } + if (!strcasecmp(buf, "[DYNAMIC_UPDATE]") || + !strcasecmp(buf, "[IXFR_UPDATE]")) { + err = 0; + rcode = NOERROR; + cp = fgets(buf, sizeof buf, fp); + if (cp != NULL) + lineno++; + if (cp == NULL || !sscanf((char *) cp, "id %d", &id)) + id = -1; + inside_next = 1; + prev_pktdone = 1; + cont = 1; + } else if (!strcasecmp(buf, "serial")) { + cp = fgets(buf, sizeof buf, fp); + if (cp != NULL) + lineno++; + if (sscanf((char *) cp, "%u", &old_serial)) { + if (from_serial >= old_serial) { + fclose(fp); + return (1); + } else { + fclose(fp); + return (-1); + } + } + prev_pktdone = 1; + cont = 1; + } else if (!strcasecmp(buf, "[INCR_SERIAL]")) { + /* XXXRTH not enough error checking here */ + cp = fgets(buf, sizeof buf, fp); + if (cp != NULL) + lineno++; + if (cp == NULL || + sscanf((char *) cp, "from %u to %u", + &old_serial, &new_serial) != 2) { + fclose(fp); + return (-3); + } else if (from_serial >= old_serial) { + fclose(fp); + return (1); + } + fclose(fp); + return (-1); + } + if (prev_pktdone) { + prev_pktdone = 0; + if (feof(fp)) + break; + } + } + fclose(fp); + return (0); +} + +/* from db_load.c */ + +static struct map m_section[] = { + {"zone", S_ZONE}, + {"prereq", S_PREREQ}, + {"update", S_UPDATE}, + {"reserved", S_ADDT}, +}; +#define M_SECTION_CNT (sizeof(m_section) / sizeof(struct map)) + +/* from ns_req.c */ + +static struct map m_opcode[] = { + {"nxdomain", NXDOMAIN}, + {"yxdomain", YXDOMAIN}, + {"nxrrset", NXRRSET}, + {"yxrrset", YXRRSET}, + {"delete", DELETE}, + {"add", ADD}, +}; +#define M_OPCODE_CNT (sizeof(m_opcode) / sizeof(struct map)) + +/* XXXRTH workaround map difficulties */ +#define M_CLASS_CNT m_class_cnt +#define M_TYPE_CNT m_type_cnt + +/* + * int + * ixfr_getrr(struct zoneinfo *zp, FILE *fp, + * const char *filename, char *origin, struct namebuf **np, + * u_int32_t *old_serial, u_int32_t *new_serial) + * + * read a line from the historic of a zone. + * + * returns: + * + * DBIXFR_ERROR = an error occured + * DBIXFR_FOUND_RR = a rr encountered + * DBIXFR_END = end of file + */ +static int +ixfr_getrr(struct zoneinfo *zp, FILE *fp, const char *filename, char *origin, + ns_updrec **uprec, u_int32_t *old_serial, + u_int32_t *new_serial) +{ + static int read_soa, read_ns, rrcount; + + char data[MAXDATA], dnbuf[MAXDNAME], sclass[3]; + const char *errtype = "Database"; + char *dname, *cp, *cp1; + char buf[MAXDATA]; + u_int32_t serial, ttl; + int nonempty_lineno = -1, prev_pktdone = 0, cont = 0, + inside_next = 0; + int id, rcode = NOERROR; + int i, c, section, opcode, matches, zonenum, err, multiline; + int type, class; + u_int32_t n; + enum transport transport; + struct map *mp; + int zonelist[MAXDNAME]; + struct databuf *dp; + struct in_addr ina; + struct sockaddr_in empty_from; + int datasize; + ns_updque listuprec; + ns_updrec * rrecp; + u_long l; + +#define ERRTO(msg) if (1) { errtype = msg; goto err; } else (void)NULL + + err = 0; + transport = primary_trans; + lineno = 1; + INIT_LIST(listuprec); + for (;;) { + if (!getword(buf, sizeof buf, fp, 0)) { + if (lineno == (nonempty_lineno + 1) && !(feof(fp))) { + /* + * End of a nonempty line inside an update + * packet or not inside an update packet. + */ + continue; + } + /* + * Empty line or EOF. + * + * Marks completion of current update packet. + */ + inside_next = 0; + prev_pktdone = 1; + cont = 1; + } else { + nonempty_lineno = lineno; + } + + if (!strcasecmp(buf, "[DYNAMIC_UPDATE]") || + !strcasecmp(buf, "[IXFR_UPDATE]")) { + err = 0; + rcode = NOERROR; + cp = fgets(buf, sizeof buf, fp); + if (cp != NULL) + lineno++; + if (cp == NULL || !sscanf((char *) cp, "id %d", &id)) + id = -1; + inside_next = 1; + prev_pktdone = 1; + cont = 1; + } else if (!strcasecmp(buf, "[INCR_SERIAL]")) { + /* XXXRTH not enough error checking here */ + cp = fgets(buf, sizeof buf, fp); + if (cp != NULL) + lineno++; + if (cp == NULL || + sscanf((char *) cp, "from %u to %u", + old_serial, new_serial) != 2) { + ns_error(ns_log_update, + "incr_serial problem with %s", + zp->z_updatelog); + } else { + serial = get_serial(zp); + } + cont = 1; + } else if (!strcasecmp(buf, "[END_DELTA]")) { + prev_pktdone = 1; + cont = 1; + lineno++; + } + if (prev_pktdone) { + if (!EMPTY(listuprec)) { + n++; + *uprec = TAIL(listuprec); + return (DBIXFR_FOUND_RR); + } + prev_pktdone = 0; + if (feof(fp)) + break; + } + if (cont) { + cont = 0; + continue; + } + if (!inside_next) + continue; + /* + * inside the same update packet, continue accumulating + * records. + */ + section = -1; + n = strlen(buf); + if (buf[n - 1] == ':') + buf[--n] = '\0'; + for (mp = m_section; mp < m_section + M_SECTION_CNT; mp++) + if (!strcasecmp(buf, mp->token)) { + section = mp->val; + break; + } + ttl = 0; + type = -1; + class = zp->z_class; + n = 0; + data[0] = '\0'; + switch (section) { + case S_ZONE: + cp = fgets(buf, sizeof buf, fp); + if (!cp) + *buf = '\0'; + n = sscanf(cp, "origin %s class %s serial %ul", + origin, sclass, &serial); + if (n != 3 || ns_samename(origin, zp->z_origin) != 1) + err++; + if (cp) + lineno++; + if (!err && inside_next) { + int success; + + dname = origin; + type = T_SOA; + class = sym_ston(__p_class_syms, sclass, + &success); + if (!success) { + err++; + break; + } + matches = findzone(dname, class, 0, + zonelist, MAXDNAME); + if (matches) + zonenum = zonelist[0]; + else + err++; + } + break; + case S_PREREQ: + case S_UPDATE: + /* Operation code. */ + if (!getword(buf, sizeof buf, fp, 0)) { + err++; + break; + } + opcode = -1; + if (buf[0] == '{') { + n = strlen(buf); + for (i = 0; (u_int32_t) i < n; i++) + buf[i] = buf[i + 1]; + if (buf[n - 2] == '}') + buf[n - 2] = '\0'; + } + for (mp = m_opcode; mp < m_opcode + M_OPCODE_CNT; mp++) + if (!strcasecmp(buf, mp->token)) { + opcode = mp->val; + break; + } + if (opcode == -1) { + err++; + break; + } + /* Owner's domain name. */ + if (!getword((char *) dnbuf, sizeof dnbuf, fp, 0)) { + err++; + break; + } + n = strlen((char *) dnbuf) - 1; + if (dnbuf[n] == '.') + dnbuf[n] = '\0'; + dname = dnbuf; + ttl = 0; + type = -1; + class = zp->z_class; + n = 0; + data[0] = '\0'; + (void) getword(buf, sizeof buf, fp, 1); + if (isdigit(buf[0])) { /* ttl */ + if (ns_parse_ttl(buf, &l) < 0) { + err++; + break; + } + ttl = l; + (void) getword(buf, sizeof buf, fp, 1); + } + /* possibly class */ + if (buf[0] != '\0') { + int success; + int maybe_class; + + maybe_class = sym_ston(__p_class_syms, + buf, &success); + if (success) { + class = maybe_class; + (void) getword(buf, sizeof buf, fp, 1); + } + } + /* possibly type */ + if (buf[0] != '\0') { + int success; + int maybe_type; + + maybe_type = sym_ston(__p_type_syms, + buf, &success); + + if (success) { + type = maybe_type; + (void) getword(buf, sizeof buf, fp, 1); + } + } + if (buf[0] != '\0') /* possibly rdata */ + /* + * Convert the ascii data 'buf' to the proper + * format based on the type and pack into + * 'data'. + * + * XXX - same as in db_load(), consolidation + * needed + */ + switch (type) { + case T_A: + if (!inet_aton(buf, &ina)) { + err++; + break; + } + n = ntohl(ina.s_addr); + cp = data; + PUTLONG(n, cp); + n = INT32SZ; + break; + case T_HINFO: + case T_ISDN: + n = strlen(buf); + data[0] = n; + memcpy(data + 1, buf, n); + n++; + if (!getword(buf, sizeof buf, fp, 0)) { + i = 0; + } else { + endline(fp); + i = strlen(buf); + } + data[n] = i; + n++; + memcpy(data + n + 1, buf, i); + n += i; + break; + case T_SOA: + case T_MINFO: + case T_RP: + (void) strcpy(data, buf); + cp = data + strlen(data) + 1; + if (!getword((char *) cp, + sizeof data - (cp - data), + fp, 1)) { + err++; + break; + } + cp += strlen((char *) cp) + 1; + if (type != T_SOA) { + n = cp - data; + break; + } + if (class != zp->z_class || + ns_samename(dname, zp->z_origin) != 1) { + err++; + break; + } + c = getnonblank(fp, zp->z_updatelog); + if (c == '(') { + multiline = 1; + } else { + multiline = 0; + ungetc(c, fp); + } + n = getnum(fp, zp->z_updatelog, GETNUM_SERIAL); + if (getnum_error) { + err++; + break; + } + if (opcode == ADD && i == 0) + *new_serial = n; + PUTLONG(n, cp); + for (i = 0; i < 4; i++) { + if (!getword(buf, sizeof buf, fp, 1)) { + err++; + break; + } + if (ns_parse_ttl(buf, &l) < 0) { + err++; + break; + } + n = l; + PUTLONG(n, cp); + } + if (multiline && + getnonblank(fp, zp->z_updatelog) != ')') + { + err++; + break; + } + endline(fp); + n = cp - data; + break; + case T_WKS: + if (!inet_aton(buf, &ina)) { + err++; + break; + } + n = ntohl(ina.s_addr); + cp = data; + PUTLONG(n, cp); + *cp = (char) getprotocol(fp, zp->z_updatelog); + n = INT32SZ + sizeof(char); + n = getservices((int) n, data, + fp, zp->z_updatelog); + break; + case T_NS: + case T_CNAME: + case T_MB: + case T_MG: + case T_MR: + case T_PTR: + (void) strcpy(data, buf); + if (makename(data, origin, + sizeof(data)) == -1) { + err++; + break; + } + n = strlen(data) + 1; + break; + case T_MX: + case T_AFSDB: + case T_RT: + n = 0; + cp = buf; + while (isdigit(*cp)) + n = n * 10 + (*cp++ - '0'); + /* catch bad values */ + cp = data; + PUTSHORT((u_int16_t) n, cp); + if (!getword(buf, sizeof(buf), fp, 1)) { + err++; + break; + } + (void) strcpy((char *) cp, buf); + if (makename((char *) cp, origin, + sizeof(data) - (cp - data)) == -1) + { + err++; + break; + } + /* advance pointer to end of data */ + cp += strlen((char *) cp) + 1; + /* now save length */ + n = (cp - data); + break; + case T_PX: + n = 0; + data[0] = '\0'; + cp = buf; + while (isdigit(*cp)) + n = n * 10 + (*cp++ - '0'); + cp = data; + PUTSHORT((u_int16_t) n, cp); + for (i = 0; i < 2; i++) { + if (!getword(buf, sizeof(buf), fp, 0)) + { + err++; + break; + } + (void) strcpy((char *) cp, buf); + cp += strlen((char *) cp) + 1; + } + n = cp - data; + break; + case T_TXT: + case T_X25: + i = strlen(buf); + cp = data; + datasize = sizeof data; + cp1 = buf; + while (i > MAXCHARSTRING) { + if (datasize <= MAXCHARSTRING) { + ns_error(ns_log_update, + "record too big"); + return (-1); + } + datasize -= MAXCHARSTRING; + *cp++ = (char)MAXCHARSTRING; + memcpy(cp, cp1, MAXCHARSTRING); + cp += MAXCHARSTRING; + cp1 += MAXCHARSTRING; + i -= MAXCHARSTRING; + } + if (datasize < i + 1) { + ns_error(ns_log_update, + "record too big"); + return (-1); + } + *cp++ = i; + memcpy(cp, cp1, i); + cp += i; + n = cp - data; + endline(fp); + /* XXXVIX: segmented texts 4.9.5 */ + break; + case T_NSAP: + n = inet_nsap_addr(buf, (u_char *) data, + sizeof data); + endline(fp); + break; + case T_LOC: + cp = buf + (n = strlen(buf)); + *cp = ' '; + cp++; + while ((i = getc(fp), *cp = i, i != EOF) + && *cp != '\n' && (n < MAXDATA)) + { + cp++; + n++; + } + if (*cp == '\n') + ungetc(*cp, fp); + *cp = '\0'; + n = loc_aton(buf, (u_char *) data); + if (n == 0) { + err++; + break; + } + endline(fp); + break; + case ns_t_sig: + case ns_t_nxt: + case ns_t_key: + case ns_t_cert:{ + char *errmsg = NULL; + + n = parse_sec_rdata(buf, sizeof(buf), 1, + (u_char *) data, + sizeof(data), + fp, zp, dname, ttl, + type, domain_ctx, + transport, &errmsg); + if (errmsg) { + err++; + endline(fp); + n = 0; + } + break; + } + default: + err++; + } + if (section == S_PREREQ) { + ttl = 0; + if (opcode == NXDOMAIN) { + class = C_NONE; + type = T_ANY; + n = 0; + } else if (opcode == YXDOMAIN) { + class = C_ANY; + type = T_ANY; + n = 0; + } else if (opcode == NXRRSET) { + class = C_NONE; + n = 0; + } else if (opcode == YXRRSET) { + if (n == 0) + class = C_ANY; + } + } else {/* section == S_UPDATE */ + if (opcode == DELETE) { + if (n == 0) { + class = C_ANY; + if (type == -1) + type = T_ANY; + } else { + class = zp->z_class; + } + } + } + break; + case S_ADDT: + default: + ns_debug(ns_log_update, 1, + "cannot interpret section: %d", section); + inside_next = 0; + err++; + } + if (err) { + inside_next = 0; + ns_debug(ns_log_update, 1, + "merge of update id %d failed due to error at line %d", + id, lineno); + memset(&empty_from, 0, sizeof empty_from); + free_rrecp(&listuprec, rcode, empty_from); + continue; + } + rrecp = res_mkupdrec(section, dname, class, type, ttl); + if (section != S_ZONE) { + dp = savedata(class, type, ttl, (u_char *) data, n); + dp->d_zone = zonenum; + dp->d_cred = DB_C_ZONE; + dp->d_clev = nlabels(zp->z_origin); + rrecp->r_dp = dp; + rrecp->r_opcode = opcode; + } else { + rrecp->r_zone = zonenum; + rrecp->r_opcode = opcode; + } + + /* remove add/delete pairs */ + if (section == S_UPDATE) { + ns_updrec *arp; + int foundmatch; + + arp = TAIL(listuprec); + foundmatch = 0; + while (arp) { + if (arp->r_section == S_UPDATE && + ((arp->r_opcode == DELETE && + opcode == ADD) || + (opcode == DELETE && + arp->r_opcode == ADD)) && + arp->r_dp->d_type == dp->d_type && + arp->r_dp->d_class == dp->d_class && + arp->r_dp->d_ttl == dp->d_ttl && + ns_samename(arp->r_dname, dname) == 1 && + db_cmp(arp->r_dp, dp) == 0) { + db_freedata(dp); + db_freedata(arp->r_dp); + UNLINK(listuprec, arp, r_link); + res_freeupdrec(arp); + res_freeupdrec(rrecp); + foundmatch = 1; + break; + } + arp = PREV(arp, r_link); + } + if (foundmatch) + continue; + } + + APPEND(listuprec, rrecp, r_link); + /* Override zone number with current zone serial number */ + rrecp->r_zone = serial; + } + + if (err) + return (DBIXFR_ERROR); + + return (DBIXFR_END); +} diff --git a/contrib/bind/bin/named/db_load.c b/contrib/bind/bin/named/db_load.c index d05a969..9b6fedb 100644 --- a/contrib/bind/bin/named/db_load.c +++ b/contrib/bind/bin/named/db_load.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)db_load.c 4.38 (Berkeley) 3/2/91"; -static char rcsid[] = "$Id: db_load.c,v 8.41 1998/02/13 20:02:28 halley Exp $"; +static const char sccsid[] = "@(#)db_load.c 4.38 (Berkeley) 3/2/91"; +static const char rcsid[] = "$Id: db_load.c,v 8.97 1999/10/30 03:21:35 vixie Exp $"; #endif /* not lint */ /* @@ -82,7 +82,7 @@ static char rcsid[] = "$Id: db_load.c,v 8.41 1998/02/13 20:02:28 halley Exp $"; */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -110,6 +110,7 @@ static char rcsid[] = "$Id: db_load.c,v 8.41 1998/02/13 20:02:28 halley Exp $"; #include <sys/param.h> #include <sys/stat.h> #include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -137,27 +138,28 @@ static char rcsid[] = "$Id: db_load.c,v 8.41 1998/02/13 20:02:28 halley Exp $"; /* Forward. */ static int gettoken(FILE *, const char *); -static int getttl(FILE *, const char *, int, u_int32_t *, int *); static int getcharstring(char *, char *, int, int, int, FILE *, const char *); -static int makename_ok(char *name, const char *origin, int class, - struct zoneinfo *zp, - enum transport transport, - enum context context, - const char *owner, const char *filename, - int lineno, int size); +static int genname(char *, int, const char *, char *, int); static int getmlword(char *, size_t, FILE *, int); static int getallwords(char *, size_t, FILE *, int); static u_int32_t wordtouint32(char *); -static int datepart(const char *, int, int, int, int *); -static u_int32_t datetosecs(const char *, int *); -static int get_nxt_types(u_char *, FILE *, const char *); static void fixup_soa(const char *fn, struct zoneinfo *zp); -#ifdef BIND_NOTIFY -static void notify_after_delay(evContext ctx, void *uap, - struct timespec due, - struct timespec inter); -#endif +static int get_nxt_types(u_char *, FILE *, const char *); + +static int parse_sig_rr(char *, int, u_char *, int, FILE *, + struct zoneinfo *, char *, u_int32_t , + enum context , enum transport , char **); +static int parse_key_rr(char *, int, u_char *, int, FILE *, + struct zoneinfo *, char *, enum context, + enum transport, char **); + +static int parse_cert_rr(char *, int, u_char *, int, FILE *, char **); +static int parse_nxt_rr(char *, int, u_char *, int, FILE *, + struct zoneinfo *, char *, enum context, + enum transport, char **); + + static int wordtouint32_error = 0; static int empty_token = 0; static int getmlword_nesting = 0; @@ -166,37 +168,50 @@ static int getmlword_nesting = 0; static int clev; /* a zone deeper in a hierarchy has more credibility */ -#ifdef BIND_NOTIFY -static notify_info_list pending_notifies; -#endif - /* * Parser token values */ -#define CURRENT 1 -#define DOT 2 -#define AT 3 -#define DNAME 4 -#define INCLUDE 5 -#define ORIGIN 6 -#define ERROR 7 +#define CURRENT 1 +#define DOT 2 +#define AT 3 +#define DNAME 4 +#define INCLUDE 5 +#define ORIGIN 6 +#define GENERATE 7 +#define DEFAULTTTL 8 +#define ERRTOK 9 #define MAKENAME_OK(N) \ do { \ if (!makename_ok(N, origin, class, zp, \ - transport, context, \ + transport, context, \ domain, filename, lineno, \ - sizeof(data) - ((u_char*)N - data))) { \ + data_size - ((u_char*)N - data))) { \ + errs++; \ + sprintf(buf, "bad name \"%s\"", N); \ + goto err; \ + } \ + } while (0) + +#define MAKENAME_OKZP(N, SI) \ + do { \ + if (!makename_ok(N, zp->z_origin, zp->z_class, zp, \ + transport, context, \ + domain, zp->z_source, lineno, \ + SI - ((u_char*)N - data))) { \ errs++; \ sprintf(buf, "bad name \"%s\"", N); \ goto err; \ } \ } while (0) +#define RANGE(x, min, max) \ + (((x) > (max)) ? (max) : (((x) < (min)) ? (min) : (x))) + /* Public. */ /* int - * db_load(filename, in_origin, zp, def_domain) + * db_load(filename, in_origin, zp, def_domain, isixfr) * load a database from `filename' into zone `zp'. append `in_origin' * to all nonterminal domain names in the file. `def_domain' is the * default domain for include files or NULL for zone base files. @@ -207,18 +222,24 @@ static notify_info_list pending_notifies; */ int db_load(const char *filename, const char *in_origin, - struct zoneinfo *zp, const char *def_domain) + struct zoneinfo *zp, const char *def_domain, int isixfr) { static int read_soa, read_ns, rrcount; + static u_int32_t default_ttl, default_warn; + static struct filenames { + struct filenames *next; + char *name; + } *filenames, *fn; const char *errtype = "Database"; char *cp; char domain[MAXDNAME], origin[MAXDNAME], tmporigin[MAXDNAME]; char buf[MAXDATA]; + char genlhs[MAXDNAME], genrhs[MAXDNAME]; u_char data[MAXDATA]; - const char *op; - int c, someclass, class, type, dbflags, dataflags, multiline; - int slineno, i, errs, didinclude, escape, success, dateerror; + int data_size = sizeof(data); + int c, someclass, class, type, dbflags, dataflags, multiline = 0; + int slineno, i, errs, didinclude, ininclude, escape, success; u_int32_t ttl, n, serial; u_long tmplong; struct databuf *dp; @@ -227,9 +248,10 @@ db_load(const char *filename, const char *in_origin, struct in_addr ina; enum transport transport; enum context context; - u_int32_t sig_type; - u_int32_t keyflags; struct sockaddr_in empty_from; + int genstart, genend, genstep; + char *thisfile; + void *state = NULL; empty_from.sin_family = AF_INET; empty_from.sin_addr.s_addr = htonl(INADDR_ANY); @@ -241,40 +263,57 @@ db_load(const char *filename, const char *in_origin, * and complains. */ #define ERRTO(msg) do { if (1) { errtype = msg; goto err; } } while (0) +#define ERRTOZ(msg) do { if (1) { errtype = msg; buf[0] = '\0'; goto err; } } while (0) switch (zp->z_type) { case Z_PRIMARY: - case Z_CACHE: + case Z_HINT: transport = primary_trans; break; case Z_SECONDARY: case Z_STUB: transport = secondary_trans; break; + case Z_CACHE: + transport = response_trans; + break; default: transport = response_trans; /*guessing*/ break; } errs = 0; didinclude = 0; - if (!def_domain) { - /* This is not the result of a $INCLUDE. */ + ininclude = (def_domain != NULL); + if (!ininclude) { rrcount = 0; read_soa = 0; read_ns = 0; + default_ttl = USE_MINIMUM; + default_warn = 1; clev = nlabels(in_origin); + filenames = NULL; } + ttl = default_ttl; - ns_debug(ns_log_load, 1, "db_load(%s, %s, %d, %s)", + ns_debug(ns_log_load, 1, "db_load(%s, %s, %d, %s, %s)", filename, in_origin, zp - zones, - def_domain ? def_domain : "Nil"); + def_domain ? def_domain : "Nil", isixfr ? "IXFR" : "Normal"); + + fn = (struct filenames *)memget(sizeof *filenames); + if (fn == NULL) + ns_panic(ns_log_db, 0, "db_load: memget failed"); + thisfile = fn->name = savestr(filename, 1); + fn->next = filenames; + filenames = fn; strcpy(origin, in_origin); if ((fp = fopen(filename, "r")) == NULL) { - ns_warning(ns_log_load, "%s: %s", filename, strerror(errno)); + ns_warning(ns_log_load, "db_load could not open: %s: %s", + filename, strerror(errno)); + zp->z_ftime = 0; return (-1); } - if (zp->z_type == Z_CACHE) { + if (zp->z_type == Z_HINT) { dbflags = DB_NODATA | DB_NOHINTS; dataflags = DB_F_HINT; #ifdef STUBS @@ -288,7 +327,8 @@ db_load(const char *filename, const char *in_origin, } gettime(&tt); if (fstat(fileno(fp), &sb) < 0) { - ns_warning(ns_log_load, "%s: %s", filename, strerror(errno)); + ns_warning(ns_log_load, "fstat failed: %s: %s", + filename, strerror(errno)); sb.st_mtime = (int)tt.tv_sec; } slineno = lineno; @@ -302,6 +342,10 @@ db_load(const char *filename, const char *in_origin, while ((c = gettoken(fp, filename)) != EOF) { switch (c) { case INCLUDE: + if (isixfr) { + c = ERRTOK; + break; + } if (!getword(buf, sizeof buf, fp, 0)) /* file name*/ break; @@ -309,12 +353,12 @@ db_load(const char *filename, const char *in_origin, strcpy(tmporigin, origin); else { if (makename(tmporigin, origin, - sizeof(tmporigin)) == -1) + sizeof(tmporigin)) == -1) ERRTO("$INCLUDE makename failed"); endline(fp); } didinclude = 1; - errs += db_load(buf, tmporigin, zp, domain); + errs += db_load(buf, tmporigin, zp, domain, ISNOTIXFR); continue; case ORIGIN: @@ -329,6 +373,123 @@ db_load(const char *filename, const char *in_origin, origin); continue; + case GENERATE: + if (!getword(buf, sizeof(buf), fp, 0)) + ERRTOZ("$GENERATE missing RANGE"); + n = sscanf(buf, "%d-%d/%d", &genstart, &genend, + &genstep); + if (n != 2 && n != 3) + ERRTO("$GENERATE invalid range"); + if (n == 2) + genstep = 1; + if ((genend < genstart) || (genstart < 0) || + (genstep < 0)) + ERRTO("$GENERATE invalid range"); + if (!getword(genlhs, sizeof(genlhs), fp, 2)) + ERRTOZ("$GENERATE missing LHS"); + if (!getword(buf, sizeof(buf), fp, 0)) + ERRTOZ("GENERATE missing TYPE"); + type = sym_ston(__p_type_syms, buf, &success); + if (success == 0 || type == ns_t_any) { + ns_info(ns_log_load, + "%s: Line %d: $GENERATE unknown type: %s.", + filename, lineno, buf); + errs++; + endline(fp); + continue; + } + switch (type) { + case ns_t_ns: + case ns_t_ptr: + case ns_t_cname: + case ns_t_a: + case ns_t_aaaa: + break; + default: + ERRTO("$GENERATE unsupported type"); + } + if (!getword(genrhs, sizeof(genrhs), fp, 2)) + ERRTOZ("$GENERATE missing RHS"); + for (i = genstart; i <= genend; i += genstep) { + if (genname(genlhs, i, origin, domain, + sizeof domain) == -1) + ERRTOZ("$GENERATE genname LHS failed"); + context = ns_ownercontext(type, transport); + if (!ns_nameok(NULL, domain, class, zp, transport, + context, domain, inaddr_any)) { + strcpy(buf, domain); + ERRTO("$GENERATE owner name error"); + } + switch (type) { + case ns_t_ns: + case ns_t_ptr: + case ns_t_cname: + if (genname(genrhs, i, origin, (char *)data, + sizeof data) == -1) + ERRTOZ("$GENERATE genname RHS failed"); + switch (type) { + case ns_t_ns: + context = hostname_ctx; + break; + case ns_t_ptr: + context = ns_ptrcontext(domain); + break; + case ns_t_cname: + context = domain_ctx; + break; + } + if (!ns_nameok(NULL, (char *)data, class, zp, + transport, context, + domain, inaddr_any)) { + strncpy(buf, domain, sizeof(buf)); + buf[sizeof(buf)-1] = '\0'; + ERRTO("$GENERATE name error"); + } + n = strlen((char *)data) + 1; + break; + case ns_t_a: + case ns_t_aaaa: + if (genname(genrhs, i, NULL, (char *)data, + sizeof data) == -1) + ERRTOZ("$GENERATE genname RHS failed"); + strncpy(buf, (char*)data, sizeof(buf)); + buf[sizeof(buf)-1] = '\0'; + switch (type) { + case ns_t_a: + if (!inet_aton(buf, &ina)) + ERRTO("IP Address"); + (void) ina_put(ina, data); + n = NS_INT32SZ; + break; + case ns_t_aaaa: + if (inet_pton(AF_INET6, buf, data) <= 0) + ERRTO("IPv6 Address"); + n = NS_IN6ADDRSZ; + break; + } + break; + default: + ERRTOZ("$GENERATE unsupported context"); + } + dp = savedata(class, type, (u_int32_t)ttl, + (u_char *)data, (int)n); + dp->d_zone = zp - zones; + dp->d_flags = dataflags; + dp->d_cred = DB_C_ZONE; + dp->d_clev = clev; + c = db_set_update(domain, dp, &state, dbflags, + (dataflags & DB_F_HINT) != 0 ? + &fcachetab : &hashtab, + empty_from, &rrcount, lineno, + filename); + if (c != OK) { + if (c == CNAMEANDOTHER) + errs++; + } + } + endline(fp); + continue; + case DNAME: if (!getword(domain, sizeof(domain), fp, 1)) break; @@ -336,6 +497,14 @@ db_load(const char *filename, const char *in_origin, ERRTO("ownername makename failed"); goto gotdomain; + case DEFAULTTTL: + if (getttl(fp, filename, lineno, &n, + &multiline) <= 0 || n > MAXIMUM_TTL) { + ERRTO("$TTL bad TTL value"); + } + ttl = default_ttl = n; + continue; + case AT: (void) strcpy(domain, origin); goto gotdomain; @@ -350,10 +519,19 @@ db_load(const char *filename, const char *in_origin, continue; break; } - if (ns_parse_ttl(buf, &tmplong) < 0) - ttl = USE_MINIMUM; - else { - ttl = (u_int32_t)tmplong; + if (ns_parse_ttl(buf, &tmplong) < 0) { + if (zp->z_type == z_master && + default_warn && + (default_ttl == USE_MINIMUM)) { + ns_warning(ns_log_load, + "Zone \"%s\" (file %s): %s", + zp->z_origin, filename, + "No default TTL set using SOA minimum instead"); + default_warn = 0; + } + ttl = (u_int32_t)default_ttl; + } else { + ttl = tmplong; if (ttl > MAXIMUM_TTL) { ns_info(ns_log_load, "%s: Line %d: TTL > %u; converted to 0", @@ -375,6 +553,14 @@ db_load(const char *filename, const char *in_origin, /* Parse class (IN, etc) */ someclass = sym_ston(__p_class_syms, buf, &success); + if (success && someclass != zp->z_class) { + ns_info(ns_log_load, + "%s: Line %d: wrong class: %s.", + filename, lineno, + p_class(someclass)); + errs++; + break; + } if (success && someclass != C_ANY) { class = someclass; (void) getword(buf, sizeof buf, fp, 0); @@ -389,9 +575,10 @@ db_load(const char *filename, const char *in_origin, errs++; break; } - + if (ttl == USE_MINIMUM) + ttl = zp->z_minimum; context = ns_ownercontext(type, transport); - if (!ns_nameok(domain, class, zp, transport, context, + if (!ns_nameok(NULL, domain, class, zp, transport, context, domain, inaddr_any)) { errs++; ns_notice(ns_log_load, @@ -404,6 +591,7 @@ db_load(const char *filename, const char *in_origin, case ns_t_key: case ns_t_sig: case ns_t_nxt: + case ns_t_cert: /* * Don't do anything here for these types -- * they read their own input separately later. @@ -451,7 +639,7 @@ db_load(const char *filename, const char *in_origin, /* FALLTHROUGH */ soa_rp_minfo: (void) strcpy((char *)data, buf); - + MAKENAME_OK((char *)data); cp = (char *)(data + strlen((char *)data) + 1); if (!getword(cp, @@ -469,13 +657,7 @@ db_load(const char *filename, const char *in_origin, n = cp - (char *)data; break; } - if (class != zp->z_class) { - errs++; - ns_info(ns_log_load, "%s:%d: %s", - filename, lineno, - "SOA class not same as zone's"); - } - if (strcasecmp(zp->z_origin, domain) != 0) { + if (ns_samename(zp->z_origin, domain) != 1) { errs++; ns_error(ns_log_load, "%s:%d: SOA for \"%s\" not at zone top \"%s\"", @@ -509,9 +691,10 @@ db_load(const char *filename, const char *in_origin, n = INIT_REFRESH; } PUTLONG(n, cp); - zp->z_refresh = MAX(n, MIN_REFRESH); + zp->z_refresh = RANGE(n, MIN_REFRESH, + MAX_REFRESH); if (zp->z_type == Z_SECONDARY -#if defined(STUBS) +#if defined(STUBS) || zp->z_type == Z_STUB #endif ) { @@ -520,7 +703,7 @@ db_load(const char *filename, const char *in_origin, sched_zone_maint(zp); } #ifdef BIND_UPDATE - if ((zp->z_type == Z_PRIMARY) && + if ((zp->z_type == Z_PRIMARY) && (zp->z_flags & Z_DYNAMIC)) if ((u_int32_t)zp->z_soaincrintvl > zp->z_refresh/3) { @@ -537,14 +720,15 @@ db_load(const char *filename, const char *in_origin, n = INIT_REFRESH; } PUTLONG(n, cp); - zp->z_retry = MAX(n, MIN_RETRY); + zp->z_retry = RANGE(n, MIN_RETRY, MAX_RETRY); if (getttl(fp, filename, lineno, - &zp->z_expire, &multiline) <= 0) { + &n, &multiline) <= 0) { errs++; - zp->z_expire = INIT_REFRESH; + n = INIT_REFRESH; } - n = zp->z_expire; PUTLONG(n, cp); + zp->z_expire = RANGE(n, zp->z_refresh, + MAX_EXPIRE); if (getttl(fp, filename, lineno, &n, &multiline) <= 0) { errs++; @@ -556,8 +740,10 @@ db_load(const char *filename, const char *in_origin, "%s: Line %d: SOA minimum TTL > %u; converted to 0", filename, lineno, MAXIMUM_TTL); zp->z_minimum = 0; - } else + } else zp->z_minimum = n; + if (default_ttl == USE_MINIMUM) + ttl = n; n = cp - (char *)data; if (multiline) { buf[0] = getnonblank(fp, filename); @@ -584,7 +770,7 @@ db_load(const char *filename, const char *in_origin, break; case ns_t_ns: - if (strcasecmp(zp->z_origin, domain) == 0) + if (ns_samename(zp->z_origin, domain) == 1) read_ns++; context = hostname_ctx; goto cname_etc; @@ -625,22 +811,28 @@ db_load(const char *filename, const char *in_origin, if (!getword(buf, sizeof buf, fp, 0)) ERRTO("NAPTR Flags"); n = strlen(buf); + if (n > 255) + ERRTO("NAPTR Flags too big"); *cp++ = n; memcpy(cp, buf, (int)n); cp += n; - + /* Service Classes */ if (!getword(buf, sizeof buf, fp, 0)) ERRTO("NAPTR Service Classes"); n = strlen(buf); + if (n > 255) + ERRTO("NAPTR Service Classes too big"); *cp++ = n; memcpy(cp, buf, (int)n); cp += n; - + /* Pattern */ if (!getword(buf, sizeof buf, fp, 0)) ERRTO("NAPTR Pattern"); n = strlen(buf); + if (n > 255) + ERRTO("NAPTR Pattern too big"); *cp++ = n; memcpy(cp, buf, (int)n); cp += n; @@ -648,6 +840,9 @@ db_load(const char *filename, const char *in_origin, /* Replacement */ if (!getword(buf, sizeof buf, fp, 1)) ERRTO("NAPTR Replacement"); + n = strlen(buf); + if (n > data_size - ((u_char *)cp - data)) + ERRTO("NAPTR Replacement too big"); (void) strcpy((char *)cp, buf); context = domain_ctx; MAKENAME_OK(cp); @@ -771,422 +966,31 @@ db_load(const char *filename, const char *in_origin, endline(fp); break; - case ns_t_key: { - /* The KEY record looks like this in the db file: - * Name Cl KEY Flags Proto Algid PublicKeyData - * where: - * Name,Cl per usual - * KEY RR type - * Flags 4 digit hex value (unsigned_16) - * Proto 8 bit u_int - * Algid 8 bit u_int - * PublicKeyData - * a string of base64 digits, - * skipping any embedded whitespace. - */ - u_int32_t al, pr; - int nk, klen; - char *expstart; - u_int expbytes, modbytes; - - i = 0; - data[i] = '\0'; - cp = (char *)data; - getmlword_nesting = 0; /* KLUDGE err recov. */ - /*>>> Flags (unsigned_16) */ - if (!getmlword((char*)buf, sizeof buf, fp, 0)) - ERRTO("KEY Flags Field"); - keyflags = wordtouint32(buf); - if (wordtouint32_error || 0xFFFF < keyflags) + case ns_t_nxt: + case ns_t_key: + case ns_t_cert: + case ns_t_sig: { + char *errmsg = NULL; + int ret = parse_sec_rdata(buf, sizeof(buf), 0, + data, sizeof(data), + fp, zp, domain, ttl, + type, domain_ctx, + transport, &errmsg); + if (ret < 0) { + errtype = errmsg; goto err; - if (keyflags & NS_KEY_RESERVED_BITMASK) - ERRTO("KEY Reserved Flag Bit"); - PUTSHORT(keyflags, cp); - - /*>>> Protocol (8-bit decimal) */ - if (!getmlword((char*)buf, sizeof buf, fp, 0)) - ERRTO("KEY Protocol Field"); - pr = wordtouint32(buf); - if (wordtouint32_error || 255 < pr) - ERRTO("KEY Protocol Field"); - *cp++ = (u_char) pr; - - /*>>> Algorithm id (8-bit decimal) */ - if (!getmlword((char*)buf, sizeof buf, fp, 0)) - ERRTO("KEY Algorithm ID"); - al = wordtouint32(buf); - if (wordtouint32_error || - 0 == al || 255 == al || 255 < al) - ERRTO("KEY Algorithm ID"); - *cp++ = (u_char) al; - - /*>>> Public Key data is in BASE64. - * We don't care what algorithm it uses or what - * the internal structure of the BASE64 data is. - */ - if (!getallwords(buf, MAXDATA, fp, 0)) - klen = 0; - else { - /* Convert from BASE64 to binary. */ - klen = b64_pton(buf, (u_char*)cp, - sizeof data - - (cp - (char *)data)); - if (klen < 0) - ERRTO("KEY Public Key"); } - - /* set total length */ - n = cp + klen - (char *)data; - - /* - * Now check for valid key flags & algs & etc, - * from the RFC. - */ - - if (keyflags & (NS_KEY_ZONEKEY | NS_KEY_IPSEC - | NS_KEY_EMAIL)) - pr |= 1; /* A nonzero proto. */ - if (NS_KEY_TYPE_NO_KEY == - (keyflags & NS_KEY_TYPEMASK)) - nk = 1; /* No-key */ else - nk = 0; /* have a key */ - - if ((keyflags & NS_KEY_ZONEKEY) && - (NS_KEY_TYPE_CONF_ONLY == - (keyflags & NS_KEY_TYPEMASK))) - /* Zone key must have Auth bit set. */ - ERRTO("KEY Zone Key Auth. bit"); - - if (al == 0 && nk == 0) - ERRTO("KEY Algorithm"); - if (al != 0 && pr == 0) - ERRTO("KEY Protocols"); - - if (nk == 1 && klen != 0) - ERRTO("KEY No-Key Flags Set"); - - if (nk == 0 && klen == 0) - ERRTO("KEY Type Spec'd"); - - /* Check algorithm-ID and key structure, for - the algorithm-ID's that we know about. */ - switch (al) { - case NS_ALG_MD5RSA: - if (klen == 0) - break; - expstart = cp; - expbytes = *expstart++; - if (expbytes == 0) - GETSHORT(expbytes, expstart); - - if (expbytes < 1) - ERRTO("Exponent too short"); - if (expbytes > - (NS_MD5RSA_MAX_BITS + 7) / 8 - ) - ERRTO("Exponent too long"); - if (*expstart == 0) - ERRTO("Exponent w/ 0"); - - modbytes = klen - - (expbytes + (expstart - cp)); - if (modbytes < - (NS_MD5RSA_MIN_BITS + 7) / 8 - ) - ERRTO("Modulus too short"); - if (modbytes > - (NS_MD5RSA_MAX_BITS + 7) / 8 - ) - ERRTO("Modulus too long"); - if (*(expstart+expbytes) == 0) - ERRTO("Modulus starts w/ 0"); - break; - - case NS_ALG_EXPIRE_ONLY: - if (klen != 0) - ERRTO( - "Key provided for expire-only algorithm" - ); - break; - case NS_ALG_PRIVATE_OID: - if (klen == 0) - ERRTO("No ObjectID in key"); - break; - } - - endline(fp); /* flush the rest of the line */ + n = ret; break; - } /*T_KEY*/ - - case ns_t_sig: - { - /* The SIG record looks like this in the db file: - Name Cl SIG RRtype Algid [OTTL] Texp Tsig Kfoot Signer Sig - - where: Name and Cl are as usual - SIG is a keyword - RRtype is a char string - ALGid is 8 bit u_int - OTTL is 32 bit u_int (optionally present) - Texp is YYYYMMDDHHMMSS - Tsig is YYYYMMDDHHMMSS - Kfoot is 16-bit unsigned decimal integer - Signer is a char string - Sig is 64 to 319 base-64 digits - A missing OTTL is detected by the magnitude of the Texp value - that follows it, which is larger than any u_int. - The Labels field in the binary RR does not appear in the - text RR. - - It's too crazy to run these pages of SIG code at the right - margin. I'm exdenting them for readability. - */ - int siglen; - u_int32_t al; - u_int32_t signtime, exptime, timetilexp; - u_int32_t origTTL; - time_t now; - - /* The TTL gets checked against the Original TTL, - and bounded by the signature expiration time, which - are both under the signature. We can't let TTL drift - based on the SOA record. If defaulted, fix it now. - (It's not clear to me why USE_MINIMUM isn't eliminated - before putting ALL RR's into the database. -gnu@toad.com) */ - if (ttl == USE_MINIMUM) - ttl = zp->z_minimum; - - i = 0; - data[i] = '\0'; - getmlword_nesting = 0; /* KLUDGE err recovery */ - - /* RRtype (char *) */ - if (!getmlword((char*)buf, sizeof buf, fp, 0)) - ERRTO("SIG record doesn't specify type"); - sig_type = sym_ston(__p_type_syms, buf, &success); - if (!success || sig_type == ns_t_any) { - /* - * We'll also accept a numeric RR type, - * for signing RR types that this version - * of named doesn't yet understand. - * In the ns_t_any case, we rely on wordtouint32 - * to fail when scanning the string "ANY". - */ - sig_type = wordtouint32 (buf); - if (wordtouint32_error || sig_type > 0xFFFF) - ERRTO("Unknown RR type in SIG record"); - } - cp = (char *)&data[i]; - PUTSHORT((u_int16_t)sig_type, cp); - i += 2; - - /* Algorithm id (8-bit decimal) */ - if (!getmlword(buf, sizeof buf, fp, 0)) - ERRTO("Missing algorithm ID"); - al = wordtouint32(buf); - if (0 == al || wordtouint32_error || 255 <= al) - goto err; - data[i] = (u_char) al; - i++; - - /* - * Labels (8-bit decimal) - * Not given in the file. Must compute. - */ - n = dn_count_labels(domain); - if (0 >= n || 255 < n) - ERRTO("SIG label count invalid"); - data[i] = (u_char) n; - i++; - - /* - * OTTL (optional u_int32_t) and - * Texp (u_int32_t date) - */ - if (!getmlword(buf, sizeof buf, fp, 0)) - ERRTO("OTTL and expiration time missing"); - /* - * See if OTTL is missing and this is a date. - * This relies on good, silent error checking - * in datetosecs. - */ - exptime = datetosecs(buf, &dateerror); - if (!dateerror) { - /* Output TTL as OTTL */ - origTTL = ttl; - cp = (char *)&data[i]; - PUTLONG (origTTL, cp); - i += 4; - } else { - /* Parse and output OTTL; scan TEXP */ - origTTL = wordtouint32(buf); - if (0 >= origTTL || wordtouint32_error || - (origTTL > 0x7fffffff)) - goto err; - cp = (char *)&data[i]; - PUTLONG(origTTL, cp); - i += 4; - if (!getmlword(buf, sizeof buf, fp, 0)) - ERRTO("Expiration time missing"); - exptime = datetosecs(buf, &dateerror); - } - if (dateerror || exptime > 0x7fffffff || exptime <= 0) - ERRTO("Invalid expiration time"); - cp = (char *)&data[i]; - PUTLONG(exptime, cp); - i += 4; - - /* Tsig (u_int32_t) */ - if (!getmlword(buf, sizeof buf, fp, 0)) - ERRTO("Missing signature time"); - signtime = datetosecs(buf, &dateerror); - if (0 == signtime || dateerror) - ERRTO("Invalid signature time"); - cp = (char *)&data[i]; - PUTLONG(signtime, cp); - i += 4; - - /* Kfootprint (unsigned_16) */ - if (!getmlword(buf, sizeof buf, fp, 0)) - ERRTO("Missing key footprint"); - n = wordtouint32(buf); - if (wordtouint32_error || n >= 0x0ffff) - ERRTO("Invalid key footprint"); - cp = (char *)&data[i]; - PUTSHORT((u_int16_t)n, cp); - i += 2; - - /* Signer's Name */ - if (!getmlword((char*)buf, sizeof buf, fp, 0)) - ERRTO("Missing signer's name"); - cp = (char *)&data[i]; - strcpy(cp,buf); - context = domain_ctx; - MAKENAME_OK(cp); - i += strlen(cp) + 1; - - /* - * Signature (base64 of any length) - * We don't care what algorithm it uses or what - * the internal structure of the BASE64 data is. - */ - if (!getallwords(buf, sizeof buf, fp, 0)) { - siglen = 0; - } else { - cp = (char *)&data[i]; - siglen = b64_pton(buf, (u_char*)cp, sizeof data - i); - if (siglen < 0) - goto err; - } - - /* set total length and we're done! */ - n = i + siglen; - - /* - * Check signature time, expiration, and adjust TTL. Note - * that all time values are in GMT (UTC), *not* local time. - */ - - now = time (0); - - /* Don't let bogus name servers increase the signed TTL */ - if (ttl > origTTL) - ERRTO("TTL is greater than signed original TTL"); - - /* Don't let bogus signers "sign" in the future. */ - if (signtime > (u_int32_t)now) - ERRTO("signature time is in the future"); - - /* Ignore received SIG RR's that are already expired. */ - if (exptime <= (u_int32_t)now) - ERRTO("expiration time is in the past"); - - /* Lop off the TTL at the expiration time. */ - timetilexp = exptime - now; - if (timetilexp < ttl) { - ns_debug(ns_log_load, 1, - "shrinking expiring %s SIG TTL from %d to %d", - p_secstodate(exptime), ttl, timetilexp); - ttl = timetilexp; - } - - /* - * Check algorithm-ID and key structure, for - * the algorithm-ID's that we know about. - */ - switch (al) { - case NS_ALG_MD5RSA: - if (siglen == 0) - ERRTO("No key for RSA algorithm"); - if (siglen < 1) - ERRTO("Signature too short"); - if (siglen > (NS_MD5RSA_MAX_BITS + 7) / 8) - ERRTO("Signature too long"); - /* We rely on cp from parse */ - if (*cp == 0) - ERRTO("Signature starts with zeroes"); - break; - - case NS_ALG_EXPIRE_ONLY: - if (siglen != 0) - ERRTO( - "Signature supplied to expire-only algorithm"); - break; - case NS_ALG_PRIVATE_OID: - if (siglen == 0) - ERRTO("No ObjectID in key"); - break; - } - - /* Should we complain about algorithm-ID's that we - don't understand? It may help debug some obscure - cases, but in general we should accept any RR whether - we could cryptographically process it or not; it - may be being published for some newer DNS clients - to validate themselves. */ - - endline(fp); /* flush the rest of the line */ + } - break; /* Accept this RR. */ - } - - case ns_t_nxt: - /* The NXT record looks like: - Name Cl NXT nextname RRT1 RRT2 MX A SOA ... - - where: Name and Cl are as usual - NXT is a keyword - nextname is the next valid name in - the zone after "Name". All - names between the two are - known to be nonexistent. - RRT's... are a series of RR type - names, which indicate that - RR's of these types are - published for "Name", and - that no RR's of any other - types are published for - "Name". - - When a NXT record is cryptographically - signed, it proves the nonexistence of an - RR (actually a whole set of RR's). */ - - getmlword_nesting = 0; /* KLUDGE err recov. */ - if (!getmlword(buf, sizeof buf, fp, 1)) - goto err; - (void) strcpy((char *)data, buf); - MAKENAME_OK((char *)data); - n = strlen((char *)data) + 1; - cp = n + (char *)data; - n += get_nxt_types((u_char *)cp, fp, filename); - break; case ns_t_loc: cp = buf + (n = strlen(buf)); *cp = ' '; cp++; + n++; while ((i = getc(fp), *cp = i, i != EOF) && *cp != '\n' && (n < MAXDATA)) { @@ -1202,6 +1006,7 @@ db_load(const char *filename, const char *in_origin, endline(fp); break; + default: goto err; } @@ -1209,7 +1014,7 @@ db_load(const char *filename, const char *in_origin, * Ignore data outside the zone. */ if (zp->z_type != Z_CACHE && - !samedomain(domain, zp->z_origin)) + !ns_samedomain(domain, zp->z_origin)) { ns_info(ns_log_load, "%s:%d: data \"%s\" outside zone \"%s\" (ignored)", @@ -1223,42 +1028,44 @@ db_load(const char *filename, const char *in_origin, dp->d_flags = dataflags; dp->d_cred = DB_C_ZONE; dp->d_clev = clev; - if ((c = db_update(domain, dp, dp, NULL, dbflags, - (dataflags & DB_F_HINT) - ? fcachetab - : hashtab, empty_from)) - != OK) { - if (c != DATAEXISTS) - ns_debug(ns_log_load, 1, - "update failed %s %d", - domain, type); - db_freedata(dp); - } else { - rrcount++; - } + c = db_set_update(domain, dp, &state, dbflags, + (dataflags & DB_F_HINT) != 0 ? + &fcachetab : &hashtab, + empty_from, &rrcount, lineno, + filename); + if (c == CNAMEANDOTHER) + errs++; continue; - case ERROR: + case ERRTOK: break; } err: errs++; - ns_notice(ns_log_load, "%s:%d: %s error (%s)", + ns_notice(ns_log_load, "%s:%d: %s error near (%s)", filename, empty_token ? (lineno - 1) : lineno, errtype, buf); if (!empty_token) endline(fp); } + c = db_set_update(NULL, NULL, &state, dbflags, + (dataflags & DB_F_HINT) ? &fcachetab : &hashtab, + empty_from, &rrcount, lineno, filename); + if (c != OK) { + if (c == CNAMEANDOTHER) + errs++; + } + (void) my_fclose(fp); lineno = slineno; - if (!def_domain) { + if (!ininclude) { if (didinclude) { zp->z_flags |= Z_INCLUDE; zp->z_ftime = 0; } else zp->z_ftime = sb.st_mtime; zp->z_lastupdate = sb.st_mtime; - if (zp->z_type != Z_CACHE) { + if (zp->z_type != Z_CACHE && zp->z_type != Z_HINT) { const char *msg = NULL; if (read_soa == 0) @@ -1276,62 +1083,45 @@ db_load(const char *filename, const char *in_origin, zp->z_origin, filename, msg); } } - } - if (!def_domain) { - if (errs) + while (filenames) { + fn = filenames; + filenames = filenames->next; + freestr(fn->name); + memput(fn, sizeof *fn); + } + if (errs != 0) ns_warning(ns_log_load, "%s zone \"%s\" (%s) rejected due to errors (serial %u)", - zoneTypeString(zp), zp->z_origin, + zoneTypeString(zp->z_type), zp->z_origin, p_class(zp->z_class), zp->z_serial); else ns_info(ns_log_load, "%s zone \"%s\" (%s) loaded (serial %u)", - zoneTypeString(zp), zp->z_origin, + zoneTypeString(zp->z_type), zp->z_origin, p_class(zp->z_class), zp->z_serial); } - if (errs) { + if (errs != 0) { zp->z_flags |= Z_DB_BAD; zp->z_ftime = 0; } #ifdef BIND_NOTIFY - if (!errs && !def_domain && - (zp->z_type == z_master || zp->z_type == z_slave)) { - static const char no_room[] = - "%s failed, cannot notify for zone %s"; - notify_info ni; - - ni = memget(sizeof *ni); - if (ni == NULL) - ns_info(ns_log_load, no_room, "memget", zp->z_origin); - else { - ni->name = savestr(zp->z_origin, 0); - if (ni->name == NULL) { - memput(ni, sizeof *ni); - ns_info(ns_log_load, no_room, - "memget", zp->z_origin); - } else { - ni->class = zp->z_class; - ni->state = notify_info_waitfor; - if (evWaitFor(ev, - (const void *)notify_after_load, - notify_after_load, ni, - &ni->wait_id) < 0) { - ns_error(ns_log_load, - "evWaitFor() failed: %s", - strerror(errno)); - freestr(ni->name); - memput(ni, sizeof *ni); - } else { - APPEND(pending_notifies, ni, link); - ns_need(MAIN_NEED_NOTIFY); - } - } - } - } + if (errs == 0 && (!ininclude) && + (zp->z_type == z_master || zp->z_type == z_slave)) + ns_notify(zp->z_origin, zp->z_class, ns_t_soa); #endif return (errs); } +void +db_err(int err, char *domain, int type, const char *filename, int lineno) { + if (filename != NULL && err == CNAMEANDOTHER) + ns_notice(ns_log_load, "%s:%d:%s: CNAME and OTHER data error", + filename, lineno, domain); + if (err != DATAEXISTS) + ns_debug(ns_log_load, 1, "update failed %s %d", + domain, type); +} + static int gettoken(FILE *fp, const char *src) { int c; @@ -1350,11 +1140,15 @@ gettoken(FILE *fp, const char *src) { return (INCLUDE); if (!strcasecmp("origin", op)) return (ORIGIN); + if (!strcasecmp("generate", op)) + return (GENERATE); + if (!strcasecmp("ttl", op)) + return (DEFAULTTTL); } ns_notice(ns_log_db, "%s:%d: Unknown $ option: $%s", src, lineno, op); - return (ERROR); + return (ERRTOK); case ';': while ((c = getc(fp)) != EOF && c != '\n') @@ -1375,6 +1169,10 @@ gettoken(FILE *fp, const char *src) { lineno++; continue; + case '\r': + if (NS_OPTION_P(OPTION_TREAT_CR_AS_SPACE) != 0) + return (CURRENT); + default: (void) ungetc(c, fp); return (DNAME); @@ -1391,6 +1189,7 @@ gettoken(FILE *fp, const char *src) { * size - of destination * fp - file to read from * preserve - should we preserve \ before \\ and \.? + * if preserve == 2, then keep all \ * return value: * 0 = no word; perhaps EOL or EOF; lineno was incremented. * 1 = word was read @@ -1398,10 +1197,12 @@ gettoken(FILE *fp, const char *src) { int getword(char *buf, size_t size, FILE *fp, int preserve) { char *cp = buf; - int c, spaceok; + int c, spaceok, once; empty_token = 0; /* XXX global side effect. */ + once = 0; while ((c = getc(fp)) != EOF) { + once++; if (c == ';') { /* Comment. Skip to end of line. */ while ((c = getc(fp)) != EOF && c != '\n') @@ -1427,6 +1228,9 @@ getword(char *buf, size_t size, FILE *fp, int preserve) { c = '\\'; if (preserve) switch (c) { + default: + if (preserve == 1) + break; case '\\': case '.': case '0': @@ -1474,6 +1278,9 @@ getword(char *buf, size_t size, FILE *fp, int preserve) { c = '\\'; if (preserve) switch (c) { + default: + if (preserve == 1) + break; case '\\': case '.': case '0': @@ -1510,6 +1317,8 @@ getword(char *buf, size_t size, FILE *fp, int preserve) { *cp = '\0'; if (cp == buf) empty_token = 1; + if (!once) + lineno++; return (cp != buf); } @@ -1524,7 +1333,7 @@ getword(char *buf, size_t size, FILE *fp, int preserve) { * side effects: * *ttl is written if the return value is to be 1. */ -static int +int getttl(FILE *fp, const char *fn, int lineno, u_int32_t *ttl, int *multiline) { char buf[MAXDATA]; u_long tmp; @@ -1748,6 +1557,103 @@ getnonblank(FILE *fp, const char *src) { } /* + * Replace all single "$"'s in "name" with "it". + * ${delta} will add delta to "it" before printing. + * ${delta,width} will change print width as well, zero fill is implied + * ${delta,width,radix} will change radix as well, can be d, o, x, X. + * i.e. ${0,2,X} will produce a two digit hex (upper case) with zero fill. + * Append "origin" to name if required and validate result with makename. + * To get a "$" or "{" in the output use \ before it. + * Return 0 on no error or -1 on error. + * Resulting name stored in "buf". + */ + +static int +genname(char *name, int it, const char *origin, char *buf, int size) { + char *bp = buf; + char *eom = buf + size; + char *cp; + char numbuf[32]; + char fmt[32]; + int delta = 0; + int width; + + while (*name) { + if (*name == '$') { + if (*(++name) == '$') { + /* should be deprecated. how? */ + if (bp >= eom) + return (-1); + *bp++ = *name++; + } else { + strcpy(fmt, "%d"); + if (*name == '{') { + switch (sscanf(name, "{%d,%d,%1[doxX]}", &delta, &width, numbuf)) { + case 1: + break; + case 2: + sprintf(fmt, "%%0%dd", width); + break; + case 3: + sprintf(fmt, "%%0%d%c", width, numbuf[0]); + break; + default: + return (-1); + } + while (*name && *name++ != '}') { + continue; + } + } + sprintf(numbuf, fmt, it + delta); + cp = numbuf; + while (*cp) { + if (bp >= eom) + return (-1); + *bp++ = *cp++; + } + } + } else if (*name == '\\') { + if (*(++name) == '\0') { + if (bp >= eom) + return (-1); + *bp++ = '\\'; + } else { + switch (*name) { + case '\\': + case '.': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (bp >= eom) + return (-1); + *bp++ = '\\'; + default: + if (bp >= eom) + return (-1); + *bp++ = *name++; + } + } + } else { + if (bp >= eom) + return (-1); + *bp++ = *name++; + } + } + if (bp >= eom) + return (-1); + *bp = '\0'; + return (origin == NULL ? 0 : makename(buf, origin, size)); +} + + +/* * Take name and fix it according to following rules: * "." means root. * "@" means current origin. @@ -1786,7 +1692,7 @@ makename(char *name, const char *origin, int size) { return (0); } -static int +int makename_ok(char *name, const char *origin, int class, struct zoneinfo *zp, enum transport transport, enum context context, const char *owner, const char *filename, int lineno, int size) @@ -1798,7 +1704,7 @@ makename_ok(char *name, const char *origin, int class, struct zoneinfo *zp, filename, lineno); return (0); } - if (!ns_nameok(name, class, zp, transport, context, owner, + if (!ns_nameok(NULL, name, class, zp, transport, context, owner, inaddr_any)) { ns_info(ns_log_db, "%s:%d: database naming error", filename, lineno); @@ -1928,91 +1834,6 @@ wordtouint32(buf) return (res2); } - -/* - * 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); -} - - -/* 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. */ - -static u_int32_t -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); -} - - -#define MAXCHARSTRING 255 - static int getcharstring(char *buf, char *data, int type, int minfields, int maxfields, @@ -2029,7 +1850,7 @@ getcharstring(char *buf, char *data, int type, if (type == ns_t_txt || type == ns_t_x25) { while (i > MAXCHARSTRING && n + MAXCHARSTRING + 1 < MAXDATA) { - data[n] = MAXCHARSTRING; + data[n] = (char)MAXCHARSTRING; memmove(data + n + 1, b, MAXCHARSTRING); n += MAXCHARSTRING + 1; b += MAXCHARSTRING; @@ -2040,13 +1861,13 @@ getcharstring(char *buf, char *data, int type, if (i > MAXCHARSTRING) { ns_info(ns_log_db, "%s:%d: RDATA field %d too long", - src, lineno, nfield); + src, lineno -1, nfield); return (0); } if (n + i + 1 > MAXDATA) { ns_info(ns_log_db, "%s:%d: total RDATA too long", - src, lineno); + src, lineno -1); return (0); } data[n] = i; @@ -2058,7 +1879,7 @@ getcharstring(char *buf, char *data, int type, if (nfield < minfields) { ns_info(ns_log_db, "%s:%d: expected %d RDATA fields, only saw %d", - src, lineno, minfields, nfield); + src, lineno -1, minfields, nfield); return (0); } @@ -2083,18 +1904,18 @@ getcharstring(char *buf, char *data, int type, static int get_nxt_types(u_char *data, FILE *fp, const char *filename) { char b[MAXLABEL]; /* Not quite the right size, but good enough */ - int maxtype=0; + int maxtype=0; int success; int type; int errs = 0; - memset(data, 0, ns_t_any/NS_NXT_BITS+1); + memset(data, 0, NS_NXT_MAX/NS_NXT_BITS+1); while (getmlword(b, sizeof(b), fp, 0)) { if (feof(fp) || ferror(fp)) - break; + break; if (strlen(b) == 0 || b[0] == '\n') - continue; + continue; /* Parse RR type (A, MX, etc) */ type = sym_ston(__p_type_syms, (char *)b, &success); @@ -2106,7 +1927,7 @@ get_nxt_types(u_char *data, FILE *fp, const char *filename) { continue; } NS_NXT_BIT_SET(type, data); - if (type > maxtype) + if (type > maxtype) maxtype = type; } if (errs) @@ -2157,62 +1978,623 @@ fixup_soa(const char *fn, struct zoneinfo *zp) { fn, zp->z_refresh, zp->z_retry); } -#ifdef BIND_NOTIFY -static void -free_notify_info(notify_info ni) { - if (ni->state == notify_info_waitfor) - evUnwait(ev, ni->wait_id); - else if (ni->state == notify_info_delay) - evClearTimer(ev, ni->timer_id); - freestr(ni->name); - memput(ni, sizeof *ni); -} +/* this function reads in the sig record rdata from the input file and + * returns the following codes + * > 0 length of the recrod + * ERR_EOF end of file + * + */ -void -notify_after_load(evContext ctx, void *uap, const void *tag) { - int delay, max_delay; - notify_info ni = uap; +static int +parse_sig_rr(char *buf, int buf_len, u_char *data, int data_size, + FILE *fp, struct zoneinfo *zp, char *domain, u_int32_t ttl, + enum context domain_ctx, enum transport transport, char **errmsg) +{ +/* The SIG record looks like this in the db file: + Name Cl SIG RRtype Algid [OTTL] Texp Tsig Kfoot Signer Sig + + where: Name and Cl are as usual + SIG is a keyword + RRtype is a char string + ALGid is 8 bit u_int + Labels is 8 bit u_int + OTTL is 32 bit u_int (optionally present) + Texp is YYYYMMDDHHMMSS + Tsig is YYYYMMDDHHMMSS + Kfoot is 16-bit unsigned decimal integer + Signer is a char string + Sig is 64 to 319 base-64 digits + A missing OTTL is detected by the magnitude of the Texp value + that follows it, which is larger than any u_int. + The Labels field in the binary RR does not appear in the + text RR. + + It's too crazy to run these pages of SIG code at the right + margin. I'm exdenting them for readability. +*/ + u_int32_t sig_type; + int dateerror; + int siglen, success; + u_char *cp; + u_int32_t al, la, n; + u_int32_t signtime, exptime, timetilexp; + u_int32_t origTTL; + enum context context; + time_t now; + char *errtype = "SIG error"; + int i, my_buf_size = MAXDATA, errs = 0; + + + /* The TTL gets checked against the Original TTL, + and bounded by the signature expiration time, which + are both under the signature. We can't let TTL drift + based on the SOA record. If defaulted, fix it now. + (It's not clear to me why USE_MINIMUM isn't eliminated + before putting ALL RR's into the database. -gnu@toad.com) */ + if (ttl == USE_MINIMUM) + ttl = zp->z_minimum; + + i = 0; + data[i] = '\0'; + + getmlword_nesting = 0; /* KLUDGE err recovery */ - INSIST(tag == (const void *)notify_after_load); - - /* delay notification for from five seconds up to fifteen minutes */ - max_delay = MIN(nzones/5, 895); - max_delay = MAX(max_delay, 25); - delay = 5 + (rand() % max_delay); - ns_debug(ns_log_notify, 3, "notify_after_load: uap %p tag %p delay %d", - uap, tag, delay); - if (evSetTimer(ctx, notify_after_delay, ni, - evAddTime(evNowTime(), evConsTime(delay, 0)), - evConsTime(0, 0), &ni->timer_id) < 0) { - ns_error(ns_log_notify, "evSetTimer() failed: %s", - strerror(errno)); - UNLINK(pending_notifies, ni, link); - ni->state = notify_info_error; - free_notify_info(ni); + /* RRtype (char *) + * if old style inp will contain the next token + *copy that into buffer, otherwise read from file + */ + if (buf && buf_len == 0) + if (!getmlword((char*)buf, my_buf_size, fp, 0)) + ERRTO("SIG record doesn't specify type"); + sig_type = sym_ston(__p_type_syms, buf, &success); + if (!success || sig_type == ns_t_any) { + /* + * We'll also accept a numeric RR type, + * for signing RR types that this version + * of named doesn't yet understand. + * In the ns_t_any case, we rely on wordtouint32 + * to fail when scanning the string "ANY". + */ + sig_type = wordtouint32 (buf); + if (wordtouint32_error || sig_type > 0xFFFF) + ERRTO("Unknown RR type in SIG record"); + } + cp = &data[i]; + PUTSHORT((u_int16_t)sig_type, cp); + i += 2; + + /* Algorithm id (8-bit decimal) */ + if (!getmlword(buf, my_buf_size, fp, 0)) + ERRTO("Missing algorithm ID"); + al = wordtouint32(buf); + if (0 == al || wordtouint32_error || 255 <= al) + ERRTO("Bad algorithm number"); + data[i] = (u_char) al; + i++; + + /* + * Labels (8-bit decimal) + */ + if (!getmlword(buf, my_buf_size, fp, 0)) + ERRTO("Missing label count"); + la = wordtouint32(buf); + if (0 == la || wordtouint32_error || 255 <= la) + ERRTO("Bad label count number"); + data[i] = (u_char) la; + i++; + + /* + * OTTL (optional u_int32_t) and + * Texp (u_int32_t date) + */ + if (!getmlword(buf, my_buf_size, fp, 0)) + ERRTO("OTTL and expiration time missing"); + /* + * See if OTTL is missing and this is a date. + * This relies on good, silent error checking + * in ns_datetosecs. + */ + exptime = ns_datetosecs(buf, &dateerror); + if (!dateerror) { + /* Output TTL as OTTL */ + origTTL = ttl; + cp = &data[i]; + PUTLONG (origTTL, cp); + i += 4; + } else { + /* Parse and output OTTL; scan TEXP */ + origTTL = wordtouint32(buf); + if (0 >= origTTL || wordtouint32_error || + (origTTL > 0x7fffffff)) + ERRTO("Original TTL value bad"); + cp = &data[i]; + PUTLONG(origTTL, cp); + i += 4; + if (!getmlword(buf, my_buf_size, fp, 0)) + ERRTO("Expiration time missing"); + exptime = ns_datetosecs(buf, &dateerror); } - ni->state = notify_info_delay; + if (dateerror || exptime > 0x7fffffff || exptime <= 0) + ERRTO("Invalid expiration time"); + cp = &data[i]; + PUTLONG(exptime, cp); + i += 4; + + /* Tsig (u_int32_t) */ + if (!getmlword(buf, my_buf_size, fp, 0)) + ERRTO("Missing signature time"); + signtime = ns_datetosecs(buf, &dateerror); + if (0 == signtime || dateerror) + ERRTO("Invalid signature time"); + cp = &data[i]; + PUTLONG(signtime, cp); + i += 4; + + /* Kfootprint (unsigned_16) */ + if (!getmlword(buf, my_buf_size, fp, 0)) + ERRTO("Missing key footprint"); + n = wordtouint32(buf); + if (wordtouint32_error || n >= 0x0ffff) + ERRTO("Invalid key footprint"); + cp = &data[i]; + PUTSHORT((u_int16_t)n, cp); + i += 2; + + /* Signer's Name */ + if (!getmlword((char*)buf, my_buf_size, fp, 0)) + ERRTO("Missing signer's name"); + cp = &data[i]; + strcpy((char *)cp, buf); + context = domain_ctx; + MAKENAME_OKZP((char *)cp, data_size); + i += strlen((char *)cp) + 1; + + /* + * Signature (base64 of any length) + * We don't care what algorithm it uses or what + * the internal structure of the BASE64 data is. + */ + if (!getallwords(buf, my_buf_size, fp, 0)) { + siglen = 0; + } else { + cp = &data[i]; + siglen = b64_pton(buf, (u_char*)cp, data_size - i); + if (siglen < 0) + ERRTO("Signature block bad"); + } + + /* set total length and we're done! */ + n = i + siglen; + + /* + * Check signature time, expiration, and adjust TTL. Note + * that all time values are in GMT (UTC), *not* local time. + */ + + now = time (0); /* need to find a better place for this XXX ogud */ + /* Don't let bogus name servers increase the signed TTL */ + if (ttl > origTTL) + ERRTO("TTL is greater than signed original TTL"); + + /* Don't let bogus signers "sign" in the future. */ + if (signtime > (u_int32_t)now) + ERRTO("signature time is in the future"); + + /* Ignore received SIG RR's that are already expired. */ + if (exptime <= (u_int32_t)now) + ERRTO("expiration time is in the past"); + + /* Lop off the TTL at the expiration time. */ + timetilexp = exptime - now; + if (timetilexp < ttl) { + ns_debug(ns_log_load, 1, + "shrinking expiring %s SIG TTL from %d to %d", + p_secstodate(exptime), ttl, timetilexp); + ttl = timetilexp; + } + + /* + * Check algorithm-ID and key structure, for + * the algorithm-ID's that we know about. + */ + switch (al) { + case NS_ALG_MD5RSA: + if (siglen == 0) + ERRTO("No key for RSA algorithm"); + if (siglen < 1) + ERRTO("Signature too short"); + if (siglen > (NS_MD5RSA_MAX_BITS + 7) / 8) + ERRTO("Signature too long"); + break; + + case NS_ALG_DH: + if (siglen < 1) + ERRTO("DH Signature too short"); + break; /* need more tests here */ + + case NS_ALG_DSA: + if (siglen < NS_DSA_SIG_SIZE) + ERRTO("DSS Signature too short"); + else if (siglen > NS_DSA_SIG_SIZE) + ERRTO("DSS Signature too long "); + break; /* need more tests here */ + + case NS_ALG_EXPIRE_ONLY: + if (siglen != 0) + ERRTO( + "Signature supplied to expire-only algorithm"); + break; + case NS_ALG_PRIVATE_OID: + if (siglen == 0) + ERRTO("No ObjectID in key"); + break; + default: + ERRTO("UNKOWN SIG algorithm"); + } + + /* Should we complain about algorithm-ID's that we + don't understand? It may help debug some obscure + cases, but in general we should accept any RR whether + we could cryptographically process it or not; it + may be being published for some newer DNS clients + to validate themselves. */ + + endline(fp); /* flush the rest of the line */ + + return (n); + err: + *errmsg = errtype; + return (-1); } -static void -notify_after_delay(evContext ctx, void *uap, - struct timespec due, - struct timespec inter) +static int +parse_nxt_rr(char *buf, int buf_len, u_char *data, int data_size, + FILE *fp, struct zoneinfo *zp, char *domain, enum context context, + enum transport transport, char **errmsg) { - notify_info ni = uap; + + /* The NXT record looks like: + Name Cl NXT nextname RRT1 RRT2 MX A SOA ... + + where: Name and Cl are as usual + NXT is a keyword + nextname is the next valid name in the zone after "Name". + All names between the two are known to be nonexistent. + RRT's... are a series of RR type names, which indicate that + RR's of these types are published for "Name", and + that no RR's of any other types are published for "Name". + + When a NXT record is cryptographically signed, it proves the + nonexistence of an RR (actually a whole set of RR's). + */ + int n, errs = 0, i; + u_char *cp; +/* char *origin = zp->z_origin; + int class = zp->z_class; */ + *errmsg = "NXT name error"; + + (void) strcpy((char *)data, buf); + MAKENAME_OKZP((char *)data, data_size); + n = strlen((char *)data) + 1; + cp = n + data; + i = get_nxt_types(cp, fp, zp->z_source); + if( i > 0) + return (n + i); + *errmsg = "NXT type error"; + err: + return (-1); +} - UNLINK(pending_notifies, ni, link); - ni->state = notify_info_done; - sysnotify(ni->name, ni->class, ns_t_soa); - free_notify_info(ni); + +static int +parse_cert_rr(char *buf, int buf_len, u_char *data, int data_size, + FILE *fp, char **errmsg) +{ + /* Cert record looks like: + * Type Key_tag Alg Cert + * Type: certification type number (16) + * Key_tag: tag of corresponding KEY RR (16) + * Alg: algorithm of the KEY RR (8) + * Cert: base64 enocded block + */ + u_char *cp; + u_int32_t cert_type, key_tag, alg; + char *errtype = "CERT parse error"; + int certlen, i, n, success; + + i = 0; + cp = &data[i]; + cert_type = sym_ston(__p_cert_syms, buf, &success); + if (!success) { + cert_type = wordtouint32(buf); + if (wordtouint32_error || cert_type > 0xFFFF) + ERRTO("CERT type out of range"); + } + PUTSHORT((u_int16_t)cert_type, cp); + i += INT16SZ; + + if (!getmlword((char*)buf, buf_len, fp, 0)) + ERRTO("CERT doesn't specify type"); + + key_tag = wordtouint32(buf); + if (wordtouint32_error || key_tag > 0xFFFF) + ERRTO("CERT KEY tag out of range"); + + PUTSHORT((u_int16_t)key_tag, cp); + i += INT16SZ; + + if (!getmlword(buf, buf_len, fp, 0)) + ERRTO("CERT missing algorithm ID"); + + alg = sym_ston(__p_key_syms, buf, &success); + if (!success) { + alg = wordtouint32(buf); + if (wordtouint32_error || alg > 0xFF) + ERRTO("CERT KEY alg out of range"); + } + + data[i++] = (u_char)alg; + + if (!getallwords(buf, buf_len, fp, 0)) { + certlen = 0; + } + else { + cp = &data[i]; + certlen = b64_pton(buf, (u_char*)cp, sizeof(data) - i); + if (certlen < 0) + ERRTO("CERT blob has encoding error"); + } + /* set total length */ + n = i + certlen; + return (n); + err: + *errmsg = errtype; + return (-1); + } -void -db_cancel_pending_notifies(void) { - notify_info ni, ni_next; - for (ni = HEAD(pending_notifies); ni != NULL; ni = ni_next) { - ni_next = NEXT(ni, link); - free_notify_info(ni); +static int +parse_key_rr(char *buf, int buf_len, u_char *data, int data_size, + FILE *fp, struct zoneinfo *zp, char *domain, enum context context, + enum transport transport, char **errmsg) +{ + /* The KEY record looks like this in the db file: + * Name Cl KEY Flags Proto Algid PublicKeyData + * where: + * Name,Cl per usual + * KEY RR type + * Flags 4 digit hex value (unsigned_16) + * Proto 8 bit u_int + * Algid 8 bit u_int + * PublicKeyData + * a string of base64 digits, + * skipping any embedded whitespace. + */ + u_int32_t al, pr; + int nk, klen,i, n; + u_int32_t keyflags; + char *errtype = "KEY error"; + u_char *cp, *expstart; + u_int expbytes, modbytes; + + i = n = 0; + data[i] = '\0'; + cp = data; + getmlword_nesting = 0; /* KLUDGE err recov. */ + + /*>>> Flags (unsigned_16) */ + keyflags = wordtouint32(buf); + if (wordtouint32_error || 0xFFFF < keyflags) + ERRTO("KEY flags error"); + if (keyflags & NS_KEY_RESERVED_BITMASK) + ERRTO("KEY Reserved Flag Bit"); + PUTSHORT(keyflags, cp); + + /*>>> Protocol (8-bit decimal) */ + if (!getmlword((char*)buf, buf_len, fp, 0)) + ERRTO("KEY Protocol Field"); + pr = wordtouint32(buf); + if (wordtouint32_error || 255 < pr) + ERRTO("KEY Protocol Field"); + *cp++ = (u_char) pr; + + /*>>> Algorithm id (8-bit decimal) */ + if (!getmlword((char*)buf, buf_len, fp, 0)) + ERRTO("KEY Algorithm ID"); + al = wordtouint32(buf); + if (wordtouint32_error || 0 == al || 255 == al || 255 < al) + ERRTO("KEY Algorithm ID"); + *cp++ = (u_char) al; + + /*>>> Extended KEY flag field in bytes 5 and 6 */ + if (NS_KEY_EXTENDED_FLAGS & keyflags) { + u_int32_t keyflags2; + + if (!getmlword((char*)buf, buf_len, fp, 0)) + ERRTO("KEY Flags Field"); + keyflags2 = wordtouint32(buf); + if (wordtouint32_error || 0xFFFF < keyflags2) + ERRTO("Extended key flags error"); + if (keyflags2 & NS_KEY_RESERVED_BITMASK2) + ERRTO("KEY Reserved Flag2 Bit"); + PUTSHORT(keyflags2, cp); + } + + /*>>> Public Key data is in BASE64. + * We don't care what algorithm it uses or what + * the internal structure of the BASE64 data is. + */ + if (!getallwords(buf, MAXDATA, fp, 0)) + klen = 0; + else { + /* Convert from BASE64 to binary. */ + klen = b64_pton(buf, (u_char*)cp, + data_size - (cp - data)); + if (klen < 0) + ERRTO("KEY Public Key"); + } + + /* set total length */ + n = klen + (cp - data); + + /* + * Now check for valid key flags & algs & etc, from the RFC. + */ + + if (NS_KEY_TYPE_NO_KEY == (keyflags & NS_KEY_TYPEMASK)) + nk = 1; /* No-key */ + else + nk = 0; /* have a key */ + + if ((keyflags & (NS_KEY_NAME_TYPE | NS_KEY_TYPEMASK)) == + (NS_KEY_NAME_ZONE | NS_KEY_TYPE_CONF_ONLY)) + /* Zone key must have Auth bit set. */ + ERRTO("KEY Zone Key Auth. bit"); + + if (al == 0 && nk == 0) + ERRTO("KEY Algorithm"); + if (al != 0 && pr == 0) + ERRTO("KEY Protocols"); + + if (nk == 1 && klen != 0) + ERRTO("KEY No-Key Flags Set"); + + if (nk == 0 && klen == 0) + ERRTO("KEY Type Spec'd"); + + /* + * Check algorithm-ID and key structure, for the algorithm-ID's + * that we know about. + */ + switch (al) { + case NS_ALG_MD5RSA: + if (klen == 0) + break; + expstart = cp; + expbytes = *expstart++; + if (expbytes == 0) + GETSHORT(expbytes, expstart); + + if (expbytes < 1) + ERRTO("Exponent too short"); + if (expbytes > (NS_MD5RSA_MAX_BITS + 7) / 8) + ERRTO("Exponent too long"); + if (*expstart == 0) + ERRTO("Exponent w/ 0"); + + modbytes = klen - (expbytes + (expstart - cp)); + if (modbytes < (NS_MD5RSA_MIN_BITS + 7) / 8) + ERRTO("Modulus too short"); + if (modbytes > (NS_MD5RSA_MAX_BITS + 7) / 8) + ERRTO("Modulus too long"); + if (*(expstart+expbytes) == 0) + ERRTO("Modulus starts w/ 0"); + break; + + case NS_ALG_DH: { + u_char *dh_cp; + u_int16_t dh_len, plen, glen, ulen; + + dh_cp = (u_char *)cp; + GETSHORT(plen, dh_cp); + if(plen < 16) + ERRTO("DH short plen"); + dh_len = 2 + plen; + if(dh_len > klen) + ERRTO("DH plen > klen"); + + GETSHORT(glen, dh_cp); + if(glen <= 0 || glen > plen) + ERRTO("DH glen bad"); + dh_len = 2 + glen; + if(dh_len > klen) + ERRTO("DH glen > klen"); + + GETSHORT(ulen, dh_cp); + if(ulen <= 0 || ulen > plen) + ERRTO("DH ulen bad"); + dh_len = 2 + ulen; + if(dh_len > klen) + ERRTO("DH ulen > klen"); + else if (dh_len < klen) + ERRTO("DH *len < klen"); + break; } - INIT_LIST(pending_notifies); + + case NS_ALG_DSA: { + u_int8_t t; + + if ( klen == 0) + break; + t = *cp; + if (t > 8) + ERRTO("DSA T value"); + if (klen != (1 + 20 + 3 *(64+8*t))) + ERRTO("DSA length"); + break; + } + + case NS_ALG_PRIVATE_OID: + if (klen == 0) + ERRTO("No ObjectID in key"); + break; + default: + ERRTO("Unknown Key algorithm"); + } + + endline(fp); /* flush the rest of the line */ + return (n); + err: + *errmsg = errtype; + return (-1); +} /*T_KEY*/ + +/* + * function to invoke DNSSEC specific parsing routines. + * this is simpler than copying these complicated blocks into the + * multiple souce files that read files (ixfr, nsupdate etc..). + * this code should be in a library rather than in this file but + * what the heck for now (ogud@tislabs.com) + */ +int +parse_sec_rdata(char *buf, int buf_len, int buf_full, u_char *data, + int data_size, FILE *fp, struct zoneinfo *zp, + char *domain, u_int32_t ttl, int type, enum context context, + enum transport transport, char **errmsg) +{ + int ret = -1; + + getmlword_nesting = 0; /* KLUDGE err recov. */ + if (!buf_full && buf && buf_len != 0) /* check if any data in buf */ + if (!getmlword(buf, buf_len, fp, 1)) { + *errmsg = "unexpected end of input"; + goto err; + } + + switch (type) { + case ns_t_sig: + ret = parse_sig_rr(buf, buf_len, data, data_size, fp, zp, + domain, ttl, context, transport, errmsg); + break; + case ns_t_key: + ret = parse_key_rr(buf, buf_len, data, data_size, fp, zp, + domain, context, transport, errmsg); + break; + case ns_t_nxt: + ret = parse_nxt_rr(buf, buf_len, data, data_size, fp, zp, + domain, context, transport, errmsg); + break; + case ns_t_cert: + ret = parse_cert_rr(buf, buf_len, data, data_size, fp, errmsg); + break; + default: + ret = -1; + *errmsg = "parse_sec_rdata():Unsupported SEC type type"; + goto err; + } + return (ret); + err: + endline(fp); + return (ret); } -#endif + diff --git a/contrib/bind/bin/named/db_lookup.c b/contrib/bind/bin/named/db_lookup.c index ddf17ad..400523e 100644 --- a/contrib/bind/bin/named/db_lookup.c +++ b/contrib/bind/bin/named/db_lookup.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)db_lookup.c 4.18 (Berkeley) 3/21/91"; -static char rcsid[] = "$Id: db_lookup.c,v 8.13 1998/02/13 19:52:54 halley Exp $"; +static const char sccsid[] = "@(#)db_lookup.c 4.18 (Berkeley) 3/21/91"; +static const char rcsid[] = "$Id: db_lookup.c,v 8.24 1999/10/15 19:48:58 vixie Exp $"; #endif /* not lint */ /* @@ -57,7 +57,7 @@ static char rcsid[] = "$Id: db_lookup.c,v 8.13 1998/02/13 19:52:54 halley Exp $" */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -82,6 +82,7 @@ static char rcsid[] = "$Id: db_lookup.c,v 8.13 1998/02/13 19:52:54 halley Exp $" #include <sys/types.h> #include <sys/param.h> #include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -139,11 +140,7 @@ nlookup(const char *name, struct hashbuf **htpp, break; } - /* rotate left HASHSHIFT */ - hval = (hval << HASHSHIFT) | - (hval>>((sizeof(hval)*8)-HASHSHIFT)); - hval += ((isascii(c) && isupper(c)) ? tolower(c) : c) - & HASHMASK; + HASHIMILATE(hval, c); if (escaped) escaped = 0; else if (c == '\\') @@ -186,7 +183,7 @@ nlookup(const char *name, struct hashbuf **htpp, np->n_next = htp->h_tab[hval]; htp->h_tab[hval] = np; /* Increase hash table size. */ - if (++htp->h_cnt > htp->h_size * 2) { + if (++htp->h_cnt > (htp->h_size * AVGCH_NLOOKUP)) { *htpp = savehash(htp); if (parent == NULL) { if (htp == hashtab) { @@ -209,12 +206,10 @@ nlookup(const char *name, struct hashbuf **htpp, * This is tricky since the parent of "com" is "" and both are stored * in the same hashbuf. * See also: - * the AXFR wart description in ns_req.c + * the AXFR wart description in ns_axfr.c */ struct namebuf * -np_parent(np) - struct namebuf *np; -{ +np_parent(struct namebuf *np) { struct hashbuf *htp; struct namebuf *np2; @@ -228,19 +223,17 @@ np_parent(np) /* Search the hash chain that np should be part of. */ for (np2 = htp->h_tab[np->n_hashval % htp->h_size]; np2 != NULL; - np2 = np2->n_next) { - + np2 = np2->n_next) + { if (np == np2) { /* found it! */ /* "" hashes into the first bucket */ - for (np = htp->h_tab[0]; np ; np=np->n_next) { + for (np = htp->h_tab[0]; np != NULL; np = np->n_next) { if (NAME(*np)[0] == '\0') /* found the root namebuf */ return (np); } - ns_debug(ns_log_db, 1, - "np_parent(0x%lx) couldn't find root entry", - (u_long) np); - return (NULL); /* XXX shouldn't happen */ + /* there are no RR's with a owner name of "." yet */ + return (NULL); } } /* Try the hints. */ @@ -248,7 +241,7 @@ np_parent(np) htp = fcachetab; goto try_again; } - ns_debug(ns_log_db, 1, "np_parent(0x%lx) couldn't namebuf", + ns_debug(ns_log_db, 1, "np_parent(0x%lx) couldn't find namebuf", (u_long)np); return (NULL); /* XXX shouldn't happen */ } @@ -263,7 +256,76 @@ int match(struct databuf *dp, int class, int type) { if (dp->d_class != class && class != C_ANY) return (0); - if (dp->d_type != type && type != T_ANY) + if (dp->d_type != type && dp->d_type != T_SIG && type != T_ANY) + return (0); + if (type != T_SIG && dp->d_type == T_SIG && SIG_COVERS(dp) != type) return (0); return (1); } + +/* static int + * nxtlower(name, dp) + * Is the NXT/SIG NXT record 'lower'? + * return value: + * boolean + */ +static int +nxtlower(const char *name, struct databuf *dp) { + /* An NXT is a lower NXT iff the SOA bit is set in the bitmap */ + if (dp->d_type == T_NXT) { + u_char *nxtbitmap = dp->d_data + strlen((char *)dp->d_data) + 1; + return (NS_NXT_BIT_ISSET(T_SOA, nxtbitmap) ? 1 : 0); + } + /* If it's not an NXT, it's a SIG NXT. An NXT record must be signed + * by the zone, so the signer name must be the same as the owner. + */ + return (ns_samename(name, (char *)dp->d_data + SIG_HDR_SIZE) != 1 ? 0 : 1); +} + +/* int + * nxtmatch(name, dp1, dp2) + * Do NXT/SIG NXT records `dp1' and `dp2' belong to the same NXT set? + * return value: + * boolean + */ +int +nxtmatch(const char *name, struct databuf *dp1, struct databuf *dp2) { + int dp1_lower, dp2_lower; + + if (dp1->d_type != ns_t_nxt || dp2->d_type != ns_t_nxt) + return (0); + dp1_lower = nxtlower(name, dp1); + dp2_lower = nxtlower(name, dp2); + return (dp1_lower == dp2_lower); +} + +/* int + * rrmatch(name, dp1, dp2) + * Do data records `dp1' and `dp2' match in class and type? + * If both are NXTs, do they belong in the same NXT set? + * If both are SIGs, do the covered types match? + * If both are SIG NXTs, do the covered NXTs belong in the same set? + * Why is DNSSEC so confusing? + * return value: + * boolean + */ +int +rrmatch(const char *name, struct databuf *dp1, struct databuf *dp2) { + if (dp1->d_class != dp2->d_class && + dp1->d_class != C_ANY && dp2->d_class != C_ANY) + return(0); + if (dp1->d_type != dp2->d_type && + dp1->d_type != T_ANY && dp2->d_type != T_ANY) + return(0); + if (dp1->d_type == T_NXT) + return(nxtmatch(name, dp1, dp2)); + if (dp1->d_type != T_SIG) + return(1); + if (SIG_COVERS(dp1) == SIG_COVERS(dp2)) { + if (SIG_COVERS(dp1) == ns_t_nxt) + return(nxtmatch(name, dp1, dp2)); + else + return(1); + } + return(0); +} diff --git a/contrib/bind/bin/named/db_save.c b/contrib/bind/bin/named/db_save.c index a05c40f..c4db46a 100644 --- a/contrib/bind/bin/named/db_save.c +++ b/contrib/bind/bin/named/db_save.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)db_save.c 4.16 (Berkeley) 3/21/91"; -static char rcsid[] = "$Id: db_save.c,v 8.15 1998/01/26 22:40:08 halley Exp $"; +static const char sccsid[] = "@(#)db_save.c 4.16 (Berkeley) 3/21/91"; +static const char rcsid[] = "$Id: db_save.c,v 8.26 1999/10/13 16:39:02 vixie Exp $"; #endif /* not lint */ /* @@ -57,7 +57,7 @@ static char rcsid[] = "$Id: db_save.c,v 8.15 1998/01/26 22:40:08 halley Exp $"; */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -82,6 +82,7 @@ static char rcsid[] = "$Id: db_save.c,v 8.15 1998/01/26 22:40:08 halley Exp $"; #include <sys/types.h> #include <sys/param.h> #include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -136,11 +137,13 @@ savedata(class, type, ttl, data, size) int size; { struct databuf *dp; - int bytes = (type == T_NS) ? DATASIZE(size)+INT32SZ : DATASIZE(size); + int bytes = DATASIZE(size); dp = (struct databuf *)memget(bytes); if (dp == NULL) panic("savedata: memget", NULL); + if (class > CLASS_MAX) + panic("savedata: bad class", NULL); memset(dp, 0, bytes); dp->d_next = NULL; dp->d_type = type; @@ -151,6 +154,7 @@ savedata(class, type, ttl, data, size) dp->d_flags = 0; dp->d_cred = 0; dp->d_clev = 0; + dp->d_secure = DB_S_INSECURE; dp->d_rcode = NOERROR; dp->d_ns = NULL; dp->d_nstime = 0; @@ -158,20 +162,6 @@ savedata(class, type, ttl, data, size) return (dp); } -int hashsizes[] = { /* hashtable sizes */ - 2, - 11, - 113, - 337, - 977, - 2053, - 4073, - 8011, - 16001, - 99887, - 0 -}; - /* * Allocate a data buffer & save data. */ diff --git a/contrib/bind/bin/named/db_sec.c b/contrib/bind/bin/named/db_sec.c new file mode 100644 index 0000000..bb31fae --- /dev/null +++ b/contrib/bind/bin/named/db_sec.c @@ -0,0 +1,1097 @@ + +#if !defined(lint) && !defined(SABER) +static const char rcsid[] = "$Id: db_sec.c,v 8.30 1999/10/15 21:06:49 vixie Exp $"; +#endif /* not lint */ + +/* + * Copyright (c) 1986, 1990 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that 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. + */ + +#include "port_before.h" + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> + +#include <ctype.h> +#include <resolv.h> +#include <stdio.h> +#include <string.h> +#include <syslog.h> +#include <time.h> + +#include <isc/eventlib.h> +#include <isc/logging.h> +#include <isc/memcluster.h> +#include <isc/tree.h> + +#include <isc/dst.h> + +#include "port_after.h" + +#include "named.h" + +struct zpubkey { + struct dst_key *zpk_key; /* Should be DST_KEY */ + char *zpk_name; + struct zpubkey *zpk_next; +}; + +typedef struct zpubkey *zpubkey_list; + +static int nxt_match_rrset(struct databuf *dp, struct db_rrset *rrset); + +/* + * A converted databuf is a stripped down databuf after converting the + * data to wire format. + */ +struct converted_databuf { + struct converted_databuf *cd_next; + u_char *cd_data; + int cd_size, cd_alloc; +}; + +/* All of the trusted keys and zone keys */ +static tree *trusted_keys = NULL; + +static int +compare_pubkey (struct zpubkey *zpk1, struct zpubkey *zpk2) { + char ta[NS_MAXDNAME], tb[NS_MAXDNAME]; + + if (ns_makecanon(zpk1->zpk_name, ta, sizeof ta) < 0 || + ns_makecanon(zpk2->zpk_name, tb, sizeof tb) < 0) + return (-1); + return (strcasecmp(ta, tb)); +} + +static struct zpubkey * +tree_srch_pubkey (const char *name) { + struct zpubkey tkey, *key; + + tkey.zpk_name = (char *) name; + if (trusted_keys == NULL) { + tree_init(&trusted_keys); + return (NULL); + } + key = (struct zpubkey *)tree_srch(&trusted_keys, compare_pubkey, + &tkey); + return (key); +} + +static DST_KEY * +find_public_key (const char *name, u_int16_t key_id) { + struct namebuf *knp; + struct hashbuf *htp; + struct databuf *dp; + const char *fname; + DST_KEY *key; + + ns_debug(ns_log_default, 5, "find_public_key(%s, %d)", name, key_id); + + htp = hashtab; + knp = nlookup (name, &htp, &fname, 0); + if (fname != name) + /* The name doesn't exist, so there's no key */ + return (NULL); + + for (dp = knp->n_data; dp != NULL; dp = dp->d_next) { + if (dp->d_type != ns_t_key || dp->d_secure < DB_S_SECURE) + continue; + key = dst_dnskey_to_key(name, dp->d_data, dp->d_size); + /* XXX what about multiple keys with same footprint? */ + if (key) { + if (key->dk_id == ntohs(key_id)) + return (key); + else + dst_free_key(key); + } + } + return (NULL); +} + + +static DST_KEY * +find_trusted_key (const char *name, u_int16_t key_id) { + struct zpubkey *zpk; + zpubkey_list keylist = tree_srch_pubkey (name); + + ns_debug(ns_log_default, 5, "find_trusted_key(%s, %d)", name, key_id); + + for (zpk = keylist; zpk; zpk = zpk->zpk_next) + if (zpk->zpk_key->dk_id == ntohs(key_id)) + return (zpk->zpk_key); + + return (NULL); +} + +int +add_trusted_key (const char *name, const int flags, const int proto, + const int alg, const char *str) +{ + zpubkey_list keylist; + struct zpubkey *zpk; + u_char buf[1024]; + int n; + + keylist = tree_srch_pubkey (name); + + zpk = (struct zpubkey *) memget (sizeof (struct zpubkey)); + if (zpk == NULL) + ns_panic(ns_log_default, 1, + "add_trusted_key: memget failed(%s)", name); + n = b64_pton(str, buf, sizeof(buf)); + if (n < 0) + goto failure; + zpk->zpk_key = dst_buffer_to_key(name, alg, flags, proto, buf, n); + if (zpk->zpk_key == NULL) { + ns_warning(ns_log_default, + "add_trusted_key: dst_buffer_to_key(%s) failed", + name); + goto failure; + } + zpk->zpk_name = zpk->zpk_key->dk_key_name; + zpk->zpk_next = NULL; + + if (keylist == NULL) { + if (tree_add (&trusted_keys, compare_pubkey, zpk, NULL) == NULL) + goto failure; + } + else { + struct zpubkey *tkey = keylist; + while (tkey->zpk_next) + tkey = tkey->zpk_next; + tkey->zpk_next = zpk; + } + + return (1); + failure: + memput(zpk, sizeof (struct zpubkey)); + return (0); +} + +/* Can the signer sign records for this name? This is a heuristic. */ +static int +can_sign(const char *name, const char *signer) { + return (ns_samedomain(name, signer) && + dn_count_labels(name) - dn_count_labels(signer) <= 2); +} + +static int +rrset_set_security(struct db_rrset *rrset, int slev) { + struct dnode *dnp; + + for (dnp = rrset->rr_list; dnp != NULL; dnp = dnp->dn_next) + dnp->dp->d_secure = slev; + for (dnp = rrset->rr_sigs; dnp != NULL; dnp = dnp->dn_next) + dnp->dp->d_secure = slev; + return (slev); +} + +static int +convert_databuf(struct databuf *dp, struct converted_databuf *cdp) { + u_char *bp = cdp->cd_data; + u_char *cp = dp->d_data; + u_char *eob = cdp->cd_data + cdp->cd_alloc; + int len; + u_char buf[MAXDNAME]; + + switch (dp->d_type) { + case ns_t_soa: + case ns_t_minfo: + case ns_t_rp: + if (eob - bp < strlen((char *)cp) + 1) + return (-1); + if (ns_name_pton((char *)cp, buf, sizeof buf) < 0) + return (-1); + len = ns_name_ntol(buf, bp, eob - bp); + if (len < 0) + return (-1); + bp += len; + cp += strlen((char *)cp) + 1; + + if (eob - bp < strlen((char *)cp) + 1) + return (-1); + if (ns_name_pton((char *)cp, buf, sizeof buf) < 0) + return (-1); + len = ns_name_ntol(buf, bp, eob - bp); + if (len < 0) + return (-1); + bp += len; + cp += strlen((char *)cp) + 1; + + if (dp->d_type == ns_t_soa) { + if (eob - bp < 5 * INT32SZ) + return (-1); + memcpy(bp, cp, 5 * INT32SZ); + bp += (5 * INT32SZ); + cp += (5 * INT32SZ); + } + + break; + + case ns_t_ns: + case ns_t_cname: + case ns_t_mb: + case ns_t_mg: + case ns_t_mr: + case ns_t_ptr: + case ns_t_nxt: + if (eob - bp < strlen((char *)cp) + 1) + return (-1); + if (ns_name_pton((char *)cp, buf, sizeof buf) < 0) + return (-1); + len = ns_name_ntol(buf, bp, eob - bp); + if (len < 0) + return (-1); + bp += len; + cp += (len = strlen((char *)cp) + 1); + + if (dp->d_type == ns_t_nxt) { + if (eob - bp < dp->d_size - len) + return (-1); + memcpy(bp, cp, dp->d_size - len); + bp += (dp->d_size - len); + cp += (dp->d_size - len); + } + break; + + case ns_t_srv: + if (eob - bp < 2 * INT16SZ) + return (-1); + memcpy(bp, cp, 2 * INT16SZ); + bp += (2 * INT16SZ); + cp += (2 * INT16SZ); + /* no break */ + case ns_t_rt: + case ns_t_mx: + case ns_t_afsdb: + case ns_t_px: + if (eob - bp < INT16SZ) + return (-1); + memcpy (bp, cp, INT16SZ); + bp += INT16SZ; + cp += INT16SZ; + + if (eob - bp < strlen((char *)cp) + 1) + return (-1); + if (ns_name_pton((char *)cp, buf, sizeof buf) < 0) + return (-1); + len = ns_name_ntol(buf, bp, eob - bp); + if (len < 0) + return (-1); + bp += len; + cp += strlen((char *)cp) + 1; + + if (dp->d_type == ns_t_px) { + if (eob - bp < strlen((char *)cp) + 1) + return (-1); + if (ns_name_pton((char *)cp, buf, sizeof buf) < 0) + return (-1); + len = ns_name_ntol(buf, bp, eob - bp); + if (len < 0) + return (-1); + bp += len; + cp += strlen((char *)cp) + 1; + } + break; + + default: + if (eob - bp < dp->d_size) + return (-1); + memcpy(bp, cp, dp->d_size); + bp += dp->d_size; + } + cdp->cd_size = bp - cdp->cd_data; + return (cdp->cd_size); +} + +static int +digest_rr(char *envelope, int elen, struct converted_databuf *cdp, + char *buffer, int blen) +{ + char *bp = buffer, *eob = buffer + blen; + + if (eob - bp < elen) + return (-1); + memcpy (bp, envelope, elen); + bp += elen; + + if (eob - bp < INT16SZ) + return (-1); + PUTSHORT(cdp->cd_size, bp); + + if (eob - bp < cdp->cd_size) + return (-1); + memcpy (bp, cdp->cd_data, cdp->cd_size); + bp += cdp->cd_size; + + return (bp - buffer); +} + +/* Sorts the converted databuf in the list */ +static void +insert_converted_databuf(struct converted_databuf *cdp, + struct converted_databuf **clist) +{ + struct converted_databuf *tcdp, *next; + int t; + +#define compare_cdatabuf(c1, c2, t) \ + (t = memcmp(c1->cd_data, c2->cd_data, MIN(c1->cd_size, c2->cd_size)), \ + t == 0 ? c1->cd_size - c2->cd_size : t) + + if (*clist == NULL) { + *clist = cdp; + return; + } + + tcdp = *clist; + if (compare_cdatabuf(cdp, tcdp, t) < 0) { + cdp->cd_next = tcdp; + *clist = cdp; + return; + } + + next = tcdp->cd_next; + while (next) { + if (compare_cdatabuf(cdp, next, t) < 0) { + cdp->cd_next = next; + tcdp->cd_next = cdp; + return; + } + tcdp = next; + next = next->cd_next; + } + tcdp->cd_next = cdp; +#undef compare_cdatabuf +} + +static void +free_clist(struct converted_databuf *clist) { + struct converted_databuf *cdp; + + while (clist != NULL) { + cdp = clist; + clist = clist->cd_next; + memput(cdp->cd_data, cdp->cd_alloc); + memput(cdp, sizeof(struct converted_databuf)); + } +} + +/* Removes all empty nodes from an rrset's SIG list. */ +static void +rrset_trim_sigs(struct db_rrset *rrset) { + struct dnode *dnp, *odnp, *ndnp; + + odnp = NULL; + dnp = rrset->rr_sigs; + while (dnp != NULL) { + if (dnp->dp != NULL) { + odnp = dnp; + dnp = dnp->dn_next; + } + else { + if (odnp != NULL) + odnp->dn_next = dnp->dn_next; + else + rrset->rr_sigs = dnp->dn_next; + ndnp = dnp->dn_next; + memput(dnp, sizeof(struct dnode)); + dnp = ndnp; + } + } +} + +int +verify_set(struct db_rrset *rrset) { + DST_KEY *key = NULL; + struct sig_record *sigdata; + struct dnode *sigdn; + struct databuf *sigdp; + time_t now; + char *signer; + u_char name_n[MAXDNAME]; + u_char *sig, *eom; + int trustedkey = 0, siglen, labels, len = 0, ret; + u_char *buffer = NULL, *bp; + u_char envelope[MAXDNAME+32], *ep; + struct dnode *dnp; + int bufsize = 2048; /* Large enough for MAXDNAME + SIG_HDR_SIZE */ + struct converted_databuf *clist = NULL, *cdp; + int dnssec_failed = 0, dnssec_succeeded = 0; + int return_value; + int i; + + if (rrset == NULL || rrset->rr_name == NULL) { + ns_warning (ns_log_default, "verify_set: missing rrset/name"); + return (rrset_set_security(rrset, DB_S_FAILED)); + } + + if (rrset->rr_sigs == NULL) + return (rrset_set_security(rrset, DB_S_INSECURE)); + + ns_debug(ns_log_default, 5, "verify_set(%s, %s, %s)", rrset->rr_name, + p_type(rrset->rr_type), p_class(rrset->rr_class)); + + now = time(NULL); + + for (sigdn = rrset->rr_sigs; sigdn != NULL; sigdn = sigdn->dn_next) { + u_int32_t namefield; + struct sig_record sigrec; + + sigdp = sigdn->dp; + + eom = sigdp->d_data + sigdp->d_size; + if (sigdp->d_size < SIG_HDR_SIZE) { + return_value = DB_S_FAILED; + goto end; + } + memcpy(&sigrec, sigdp->d_data, SIG_HDR_SIZE); + sigdata = &sigrec; + signer = (char *)sigdp->d_data + SIG_HDR_SIZE; + sig = (u_char *)signer + strlen(signer) + 1; + siglen = eom - sig; + + /* + * Don't verify a set if the SIG inception time is in + * the future. This should be fixed before 2038 (BEW) + */ + if (ntohl(sigdata->sig_time_n) > now) + continue; + + /* An expired set is dropped, but the data is not. */ + if (ntohl(sigdata->sig_exp_n) < now) { + db_freedata(sigdp); + sigdn->dp = NULL; + continue; + } + + /* Cleanup from the last iteration if we continue'd */ + if (trustedkey == 0 && key != NULL) + dst_free_key(key); + + key = find_trusted_key(signer, sigdata->sig_keyid_n); + + if (key == NULL) { + trustedkey = 0; + key = find_public_key(signer, sigdata->sig_keyid_n); + } + else + trustedkey = 1; + + /* if we don't have the key, either + * - the data should be considered insecure + * - the sig is not a dnssec signature + */ + if (key == NULL) + continue; + + /* Can a key with this name sign the data? */ + if (!can_sign(rrset->rr_name, signer)) + continue; + + /* Check the protocol and flags of the key */ + if (key->dk_proto != NS_KEY_PROT_DNSSEC && + key->dk_proto != NS_KEY_PROT_ANY) + continue; + if (key->dk_flags & NS_KEY_NO_AUTH) + continue; + namefield = key->dk_flags & NS_KEY_NAME_TYPE; + if (namefield == NS_KEY_NAME_USER || + namefield == NS_KEY_NAME_RESERVED) + continue; + if (namefield == NS_KEY_NAME_ENTITY && + (key->dk_flags & NS_KEY_SIGNATORYMASK == 0)) + continue; + + /* + * If we're still here, we have a non-null key that's either + * a zone key or an entity key with signing authority. + */ + + if (buffer == NULL) { + bp = buffer = memget(bufsize); + if (bp == NULL) { + return_value = DB_S_FAILED; + goto end; + } + } + else + bp = buffer; + + + /* Digest the fixed portion of the SIG record */ + memcpy(bp, (char *) sigdata, SIG_HDR_SIZE); + bp += SIG_HDR_SIZE; + + /* Digest the signer's name, canonicalized */ + if (ns_name_pton(signer, name_n, sizeof name_n) < 0) { + return_value = DB_S_FAILED; + goto end; + } + i = ns_name_ntol(name_n, (u_char *)bp, bufsize - SIG_HDR_SIZE); + if (i < 0) { + return_value = DB_S_FAILED; + goto end; + } + bp += i; + + /* create the dns record envelope: + * <name><type><class><Original TTL> + */ + if (ns_name_pton(rrset->rr_name, name_n, sizeof name_n) < 0 || + ns_name_ntol(name_n, (u_char *)envelope, sizeof envelope) < 0) { + return_value = DB_S_FAILED; + goto end; + } + + labels = dn_count_labels(rrset->rr_name); + if (labels > sigdata->sig_labels_n) { + ep = envelope; + for (i=0; i < (labels - 1 - sigdata->sig_labels_n); i++) + ep += (*ep+1); + i = dn_skipname(ep, envelope + sizeof envelope); + if (i < 0) { + return_value = DB_S_FAILED; + goto end; + } + envelope[0] = '\001'; + envelope[1] = '*'; + memmove(envelope + 2, ep, i); + } + i = dn_skipname(envelope, envelope + sizeof envelope); + if (i < 0) { + return_value = DB_S_FAILED; + goto end; + } + ep = envelope + i; + PUTSHORT (rrset->rr_type, ep); + PUTSHORT (rrset->rr_class, ep); + if (envelope + sizeof(envelope) - ep < INT32SZ) { + return_value = DB_S_FAILED; + goto end; + } + memcpy (ep, &sigdata->sig_ottl_n, INT32SZ); + ep += INT32SZ; + + if (clist == NULL) { + for (dnp = rrset->rr_list; + dnp != NULL; + dnp = dnp->dn_next) + { + struct databuf *dp = dnp->dp; + + cdp = memget(sizeof(struct converted_databuf)); + if (cdp == NULL) { + return_value = DB_S_FAILED; + goto end; + } + memset(cdp, 0, sizeof(*cdp)); + /* Should be large enough... */ + cdp->cd_alloc = dp->d_size + 8; + cdp->cd_data = memget(cdp->cd_alloc); + if (cdp->cd_data == NULL) { + memput(cdp, sizeof(*cdp)); + return_value = DB_S_FAILED; + goto end; + } + while (convert_databuf(dp, cdp) < 0) { + memput(cdp->cd_data, cdp->cd_alloc); + cdp->cd_alloc *= 2; + cdp->cd_data = memget(cdp->cd_alloc); + if (cdp->cd_data == NULL) { + memput(cdp, sizeof(*cdp)); + return_value = DB_S_FAILED; + goto end; + } + } + insert_converted_databuf(cdp, &clist); + } + } + + for (cdp = clist; cdp != NULL; cdp = cdp->cd_next) { + len = digest_rr((char *)envelope, ep-envelope, cdp, + (char *)bp, bufsize - (bp - buffer)); + while (len < 0) { + u_char *newbuf; + + /* Double the buffer size */ + newbuf = memget(bufsize*2); + if (newbuf == NULL) { + return_value = DB_S_FAILED; + goto end; + } + memcpy(newbuf, buffer, bp - buffer); + bp = (bp - buffer) + newbuf; + memput(buffer, bufsize); + buffer = newbuf; + bufsize *= 2; + + len = digest_rr((char *)envelope, ep-envelope, + cdp, (char *)bp, + bufsize - (bp - buffer)); + } + bp += len; + } + + if (len < 0) { + return_value = DB_S_FAILED; + goto end; + } + + ret = dst_verify_data(SIG_MODE_ALL, key, NULL, buffer, + bp - buffer, sig, siglen); + + if (ret < 0) { + dnssec_failed++; + db_freedata(sigdp); + sigdn->dp = NULL; + } + else + dnssec_succeeded++; + } + +end: + if (dnssec_failed > 0) + rrset_trim_sigs(rrset); + if (trustedkey == 0 && key != NULL) + dst_free_key(key); + + if (dnssec_failed > 0 && dnssec_succeeded == 0) { + ns_warning (ns_log_default, + "verify_set(%s, %s, %s) failed", + rrset->rr_name, p_type(rrset->rr_type), + p_class(rrset->rr_class)); + return_value = DB_S_FAILED; + } + else if (dnssec_succeeded > 0) + return_value = DB_S_SECURE; + else + return_value = DB_S_INSECURE; + free_clist(clist); + if (buffer != NULL) + memput(buffer, bufsize); + return (rrset_set_security(rrset, return_value)); +} + +static void +rrset_free_partial(struct db_rrset *rrset, int free_data, struct dnode *start) { + struct dnode *dnp; + int found_start = 0; + + ns_debug(ns_log_default, 5, "rrset_free(%s)", rrset->rr_name); + + if (start == NULL) + found_start = 1; + + while (rrset->rr_list) { + dnp = rrset->rr_list; + if (dnp == start) + found_start = 1; + rrset->rr_list = rrset->rr_list->dn_next; + if (dnp->dp != NULL && free_data == 1 && found_start == 1) + db_freedata(dnp->dp); + memput(dnp, sizeof(struct dnode)); + } + while (rrset->rr_sigs) { + dnp = rrset->rr_sigs; + if (dnp == start) + found_start = 1; + rrset->rr_sigs = rrset->rr_sigs->dn_next; + if (dnp->dp != NULL && free_data == 1 && found_start == 1) + db_freedata(dnp->dp); + memput(dnp, sizeof(struct dnode)); + } +} + +static void +rrset_free(struct db_rrset *rrset, int free_data) { + rrset_free_partial(rrset, free_data, NULL); +} + +/* + * This is called when we have an rrset with SIGs and no other data. + * Returns 1 if we either found the necessary data or if the SIG can be added + * with no other data. 0 indicates that the SIG cannot be added. + */ +static int +attach_data(struct db_rrset *rrset) { + int type, class; + struct databuf *dp, *newdp, *sigdp; + struct dnode *dnp; + struct namebuf *np; + struct hashbuf *htp; + char *signer; + const char *fname; + char *name = rrset->rr_name; + + sigdp = rrset->rr_sigs->dp; + + type = SIG_COVERS(sigdp); + class = sigdp->d_class; + signer = (char *)(sigdp + SIG_HDR_SIZE); + + /* First, see if the signer can sign data for the name. If not, + * it's not a DNSSEC signature, so we can insert it with no + * corresponding data. + */ + if (!can_sign(name, signer)) + return (1); + + htp = hashtab; + np = nlookup (name, &htp, &fname, 0); + if (fname != name) + return (0); + + for (dp = np->n_data; dp != NULL; dp = dp->d_next) { + if (dp->d_type == type && dp->d_class == class) { + newdp = savedata(class, type, dp->d_ttl, dp->d_data, + dp->d_size); + dnp = (struct dnode *) memget (sizeof (struct dnode)); + if (dnp == NULL) + ns_panic(ns_log_default, 1, + "attach_data: memget failed"); + dnp->dp = newdp; + dnp->dn_next = rrset->rr_list; + rrset->rr_list = dnp; + } + } + if (rrset->rr_list != NULL) + return (1); + else + return (0); +} + +static int +rrset_db_update(struct db_rrset *rrset, int flags, struct hashbuf **htpp, + struct sockaddr_in from, int *rrcount) +{ + struct dnode *dnp; + struct databuf *dp; + int ret; + + /* If we have any unattached SIG records that are DNSSEC signatures, + * don't cache them unless we already have the corresponding data. + * If we do cache unattached SIGs, we run into problems later if we + * have a SIG X and get a query for type X. + */ + if (rrset->rr_list == NULL) { + if (attach_data(rrset) == 0) { + rrset_free(rrset, 1); + return (OK); + } + + if (rrset->rr_list != NULL && + verify_set(rrset) == DB_S_FAILED) + { + rrset_free(rrset, 1); + return (OK); + } + } + + for (dnp = rrset->rr_list; dnp != NULL; dnp = dnp->dn_next) { + dp = dnp->dp; + ret = db_update(rrset->rr_name, dp, dp, NULL, + flags, (*htpp), from); + if (ret != OK) { + /* XXX Probably should do rollback. */ + db_err(ret, rrset->rr_name, dp->d_type, + dnp->file, dnp->line); + if (ret != DATAEXISTS) { + rrset_free_partial(rrset, 1, dnp); + return (ret); + } + db_freedata(dp); + } + if (rrcount != NULL) + (*rrcount)++; + dnp->dp = NULL; + } + for (dnp = rrset->rr_sigs; dnp != NULL; dnp = dnp->dn_next) { + dp = dnp->dp; + if (dp == NULL) /* verifyset() can remove sigs */ + continue; + ret = db_update(rrset->rr_name, dp, dp, NULL, + flags, (*htpp), from); + if (ret != OK) { + /* XXX Probably should do rollback. */ + db_err(ret, rrset->rr_name, dp->d_type, + dnp->file, dnp->line); + if (ret != DATAEXISTS) { + rrset_free_partial(rrset, 1, dnp); + return (ret); + } + db_freedata(dp); + } + if (rrcount != NULL) + (*rrcount)++; + dnp->dp = NULL; + } + rrset_free(rrset, 0); + return (OK); +} + +static int +rr_in_set(struct databuf *rr, struct dnode *set) { + struct dnode *dnp; + + if (set == NULL) + return (0); + + for(dnp = set; dnp != NULL; dnp = dnp->dn_next) { + if (dnp->dp->d_size == rr->d_size && + memcmp(dnp->dp->d_data, rr->d_data, dnp->dp->d_size) == 0) + return (1); + } + return (0); +} + +static int +add_to_rrset_list(struct db_rrset **rrsets, char *name, struct databuf *dp, + int line, const char *file) +{ + struct db_rrset *rrset = *rrsets; + struct dnode *dnp; + + while (rrset != NULL) { + if (rrset->rr_type != ns_t_nxt || dp->d_type != ns_t_nxt) { + if (dp->d_type == ns_t_sig) { + if (SIG_COVERS(dp) == rrset->rr_type) + break; + } else { + if (dp->d_type == rrset->rr_type) + break; + } + } + else if (nxt_match_rrset(dp, rrset)) + break; + rrset = rrset->rr_next; + } + + if (rrset != NULL) { + if ((dp->d_type == ns_t_sig && rr_in_set(dp, rrset->rr_sigs)) || + (dp->d_type != ns_t_sig && rr_in_set(dp, rrset->rr_list))) + { + db_freedata(dp); + return (DATAEXISTS); + } + } else { + rrset = (struct db_rrset *) memget(sizeof(struct db_rrset)); + if (rrset == NULL) + ns_panic(ns_log_default, 1, + "add_to_rrset_list: memget failed(%s)", name); + memset(rrset, 0, sizeof(struct db_rrset)); + rrset->rr_name = savestr(name, 1); + rrset->rr_class = dp->d_class; + if (dp->d_type == ns_t_sig) + rrset->rr_type = SIG_COVERS(dp); + else + rrset->rr_type = dp->d_type; + rrset->rr_next = *rrsets; + *rrsets = rrset; + } + + dnp = (struct dnode *) memget(sizeof(struct dnode)); + if (dnp == NULL) + ns_panic(ns_log_default, 1, + "add_to_rrset_list: memget failed(%s)", name); + memset(dnp, 0, sizeof(struct dnode)); + dnp->dp = dp; + if (dp->d_type == ns_t_sig) { + if (rrset->rr_sigs != NULL) { + struct dnode *fdnp; + + /* Preserve the order of the RRs */ + /* Add this one to the end of the list */ + for (fdnp = rrset->rr_sigs; + fdnp->dn_next != NULL; + fdnp = fdnp->dn_next) + /* NULL */ ; + fdnp->dn_next = dnp; + } else + rrset->rr_sigs = dnp; + } else { + if (rrset->rr_list != NULL) { + struct dnode *fdnp; + + /* Preserve the order of the RRs */ + /* Add this one to the end of the list */ + for (fdnp = rrset->rr_list; + fdnp->dn_next != NULL; + fdnp = fdnp->dn_next) + /* NULL */ ; + fdnp->dn_next = dnp; + } else + rrset->rr_list = dnp; + } + dnp->file = (char *) file; + dnp->line = line; + return (0); +} + +static int +update_rrset_list(struct db_rrset **rrsets, int flags, struct hashbuf **htpp, + struct sockaddr_in from, int *rrcount) +{ + struct db_rrset *rrset = *rrsets, *next = NULL, *last = NULL; + int result = 0, tresult, cnameandother = 0; + + while (rrset != NULL) { + if (rrset->rr_type == ns_t_key) + break; + last = rrset; + rrset = rrset->rr_next; + } + + if (rrset != NULL && last != NULL) { + last->rr_next = rrset->rr_next; + rrset->rr_next = *rrsets; + *rrsets = rrset; + } + + rrset = *rrsets; + + while (rrset != NULL) { + if (verify_set(rrset) > DB_S_FAILED) { + ns_debug(ns_log_default, 10, + "update_rrset_list(%s, %s): set verified", + rrset->rr_name, p_type(rrset->rr_type)); + tresult = rrset_db_update(rrset, flags, htpp, + from, rrcount); + if (tresult == CNAMEANDOTHER) + cnameandother++; + if (tresult != OK) + result = tresult; + } + else { + rrset_free(rrset, 1); + result = DNSSECFAIL; + } + freestr(rrset->rr_name); + next = rrset->rr_next; + memput(rrset, sizeof(struct db_rrset)); + rrset = next; + } + *rrsets = NULL; + if (cnameandother != 0) + return (CNAMEANDOTHER); + return (result); +} + +int +db_set_update(char *name, struct databuf *dp, void **state, + int flags, struct hashbuf **htpp, struct sockaddr_in from, + int *rrcount, int line, const char *file) +{ + struct db_rrset **rrsets; + struct db_rrset *rrset; + int result = 0; + + ns_debug(ns_log_default, 5, "db_set_update(%s)", + (name == NULL) ? "<NULL>" : (*name == 0) ? "." : name); + + if (state == NULL) + ns_panic(ns_log_default, 1, + "Called db_set_update with state == NULL"); + + rrsets = (struct db_rrset **) state; + + if (*rrsets != NULL) { + rrset = *rrsets; + if (rrset->rr_name != NULL && dp != NULL && + name != NULL && ns_samename(name, rrset->rr_name) == 1 && + dp->d_class == rrset->rr_class) + return (add_to_rrset_list(rrsets, name, dp, + line, file)); + } + + if (*rrsets != NULL) + result = update_rrset_list(rrsets, flags, htpp, from, rrcount); + + if (dp != NULL) { + ns_debug(ns_log_default, 10, + "db_set_update(%s), creating new list", name); + + (void) add_to_rrset_list(rrsets, name, dp, line, file); + } + return (result); +} + +static int +nxt_match_rrset(struct databuf *dp, struct db_rrset *rrset) { + if (rrset->rr_list != NULL) + return (nxtmatch(rrset->rr_name, dp, rrset->rr_list->dp)); + else + return (nxtmatch(rrset->rr_name, dp, rrset->rr_sigs->dp)); +} diff --git a/contrib/bind/bin/named/db_tsig.c b/contrib/bind/bin/named/db_tsig.c new file mode 100644 index 0000000..d95031d --- /dev/null +++ b/contrib/bind/bin/named/db_tsig.c @@ -0,0 +1,158 @@ + +#if !defined(lint) && !defined(SABER) +static const char rcsid[] = "$Id: db_tsig.c,v 8.5 1999/10/15 19:48:59 vixie Exp $"; +#endif /* not lint */ + +/* + * Copyright (c) 1986, 1990 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that 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. + */ + +#include "port_before.h" + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> + +#include <ctype.h> +#include <resolv.h> +#include <stdio.h> +#include <string.h> +#include <syslog.h> +#include <time.h> + +#include <isc/eventlib.h> +#include <isc/logging.h> +#include <isc/memcluster.h> +#include <isc/tree.h> + +#include <isc/dst.h> + +#include "port_after.h" + +#include "named.h" + +typedef struct { + DST_KEY *key; + void *ctx; +} tsig_axfr_state; + +#define TSIG_ALG_MD5 "HMAC-MD5.SIG-ALG.REG.INT" +#define TSIG_ALG_MD5_SHORT "hmac-md5" + +char * +tsig_alg_name(int value) { + if (value == KEY_HMAC_MD5) + return(TSIG_ALG_MD5); + else + return(NULL); +} + +int +tsig_alg_value(char *name) { + if (ns_samename(name, TSIG_ALG_MD5) == 1 || + strcasecmp(name, TSIG_ALG_MD5_SHORT) == 0) + return (KEY_HMAC_MD5); + else + return (-1); +} + +DST_KEY * +tsig_key_from_addr(struct in_addr addr) { + server_info si = si = find_server(addr); + if (si == NULL || si->key_list == NULL || si->key_list->first == NULL) + return(NULL); + return(si->key_list->first->key); +} + +struct tsig_record * +new_tsig(DST_KEY *key, u_char *sig, int siglen) { + struct tsig_record *tsig; + + if (siglen > TSIG_SIG_SIZE) + return(NULL); + tsig = memget(sizeof(struct tsig_record)); + if (tsig == NULL) + return(NULL); + tsig->key = key; + tsig->siglen = siglen; + memcpy(tsig->sig, sig, siglen); + return(tsig); +} + +void +free_tsig(struct tsig_record *tsig) { + if (tsig == NULL) + return; + memput(tsig, sizeof(struct tsig_record)); +} diff --git a/contrib/bind/bin/named/db_update.c b/contrib/bind/bin/named/db_update.c index ab70663..ea0176e 100644 --- a/contrib/bind/bin/named/db_update.c +++ b/contrib/bind/bin/named/db_update.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)db_update.c 4.28 (Berkeley) 3/21/91"; -static char rcsid[] = "$Id: db_update.c,v 8.23 1998/02/13 20:01:38 halley Exp $"; +static const char sccsid[] = "@(#)db_update.c 4.28 (Berkeley) 3/21/91"; +static const char rcsid[] = "$Id: db_update.c,v 8.39 1999/10/15 19:48:59 vixie Exp $"; #endif /* not lint */ /* @@ -57,7 +57,7 @@ static char rcsid[] = "$Id: db_update.c,v 8.23 1998/02/13 20:01:38 halley Exp $" */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -78,6 +78,7 @@ static char rcsid[] = "$Id: db_update.c,v 8.23 1998/02/13 20:01:38 halley Exp $" #include <sys/types.h> #include <sys/param.h> #include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/inet.h> @@ -116,7 +117,7 @@ isRefByNS(const char *name, struct hashbuf *htp) { dp->d_class == C_HS) && dp->d_type == T_NS && !dp->d_rcode && - !strcasecmp(name, (char *)dp->d_data)) { + ns_samename(name, (char *)dp->d_data) == 1) { return (1); } } @@ -153,21 +154,18 @@ findMyZone(struct namebuf *np, int class) { * the cache or an authoritative zone, depending). */ for (dp = np->n_data; dp; dp = dp->d_next) - if (match(dp, class, T_SOA)) + if (match(dp, class, T_SOA) && dp->d_type == T_SOA) return (dp->d_zone); /* if we find an NS at some node without having seen an SOA * (above), then we're out in the cache somewhere. */ for (dp = np->n_data; dp; dp = dp->d_next) - if (match(dp, class, T_NS)) + if (match(dp, class, T_NS) && dp->d_type == T_NS) return (DB_Z_CACHE); } - /* getting all the way to the root without finding an NS or SOA - * probably means that we are in deep dip, but we'll treat it as - * being in the cache. (XXX?) - */ + /* The cache has not yet been primed. */ return (DB_Z_CACHE); } @@ -226,12 +224,11 @@ db_update(const char *name, struct namebuf *np; int zn, isHintNS; int check_ttl = 0; + int deleted_something = 0; const char *fname; #ifdef BIND_UPDATE - int i, found_other_ns = 0; + int found_other_ns = 0; struct databuf *tmpdp; - u_char *cp1, *cp2; - u_int32_t dp_serial, newdp_serial; #endif ns_debug(ns_log_db, 3, "db_update(%s, %#x, %#x, %#x, 0%o, %#x)%s", @@ -320,6 +317,7 @@ db_update(const char *name, dp->d_zone = DB_Z_CACHE; dp->d_flags = DB_F_HINT; dp->d_cred = DB_C_CACHE; + dp->d_secure = odp->d_secure; /* BEW - this should be ok */ dp->d_clev = 0; if (db_update(name, dp, dp, NULL, @@ -337,7 +335,7 @@ db_update(const char *name, pdp = NULL; for (dp = np->n_data; dp != NULL; ) { - if (!match(dp, odp->d_class, odp->d_type)) { + if (!rrmatch(name, dp, odp)) { /* {class,type} doesn't match. these are * the aggregation cases. */ @@ -368,6 +366,9 @@ db_update(const char *name, ns_info(ns_log_db, "%s has CNAME and other data (invalid)", name); + if (zones[odp->d_zone].z_type == + Z_PRIMARY) + return (CNAMEANDOTHER); goto skip; } if (!newdp || newdp->d_class != dp->d_class) @@ -394,7 +395,7 @@ db_update(const char *name, return (AUTH); #endif - /* if the new data is authoritative but + /* if the new data is authoritative * but isn't as credible, reject it. */ if (newdp->d_cred == DB_C_ZONE && @@ -406,6 +407,11 @@ db_update(const char *name, * upper zone's file and is therefore * glue. */ + + /* BEW/OG: we see no reason to override + * these rules with new security based + * rules. + */ if (newdp->d_clev < dp->d_clev) { if (!ISVALIDGLUE(newdp)) { ns_info(ns_log_db, @@ -431,7 +437,8 @@ db_update(const char *name, /* process NXDOMAIN */ /* policy */ if (newdp->d_rcode == NXDOMAIN) { - if (dp->d_cred < DB_C_AUTH) + if (dp->d_cred < DB_C_AUTH && + newdp->d_secure >= dp->d_secure) goto delete; else return (DATAEXISTS); @@ -455,24 +462,37 @@ db_update(const char *name, db_cmp(dp, odp)); if (newdp) { ns_debug(ns_log_db, 4, - "credibility for %s is %d(%d) from [%s].%d, is %d(%d) in cache", +"credibility for %s is %d(%d)(sec %d) from [%s].%d, is %d(%d)(sec %d) in cache", *name ? name : ".", newdp->d_cred, newdp->d_clev, + newdp->d_secure, inet_ntoa(from.sin_addr), ntohs(from.sin_port), dp->d_cred, + dp->d_secure, dp->d_clev); - if (newdp->d_cred > dp->d_cred) { - /* better credibility. + if ((newdp->d_secure > dp->d_secure) || + (newdp->d_secure == dp->d_secure && + (newdp->d_cred > dp->d_cred))) + { + /* better credibility / security. * remove the old datum. */ goto delete; } - if (newdp->d_cred < dp->d_cred) { - /* credibility is worse. ignore it. */ + if ((newdp->d_secure < dp->d_secure) || + (newdp->d_secure == dp->d_secure && + (newdp->d_cred < dp->d_cred))) + { + /* credibility / security is worse. + * ignore it. + */ return (AUTH); } + /* BEW/OG: from above, we know the security + * levels are the same. + */ if (newdp->d_cred == DB_C_ZONE && dp->d_cred == DB_C_ZONE ) { /* Both records are from a zone file. @@ -566,8 +586,19 @@ db_update(const char *name, INT32SZ + sizeof(u_char))) goto delete; if (dp->d_type == T_CNAME && - !NS_OPTION_P(OPTION_MULTIPLE_CNAMES)) - goto delete; + !NS_OPTION_P(OPTION_MULTIPLE_CNAMES) && + db_cmp(dp, odp) != 0) + if ((flags & DB_REPLACE) == 0 && + zones[dp->d_zone].z_type == + Z_PRIMARY) { + ns_info(ns_log_db, + "%s has multiple CNAMES", + name); + return (CNAMEANDOTHER); + } else + goto delete; +#if 0 +/* BEW - this _seriously_ breaks DNSSEC. Is it necessary for dynamic update? */ #ifdef BIND_UPDATE if (dp->d_type == T_SIG) /* @@ -576,6 +607,20 @@ db_update(const char *name, */ goto delete; #endif +#endif + if (dp->d_type == T_NXT) { + goto delete; + } + if (dp->d_type == T_SIG && + SIG_COVERS(dp) == T_NXT) { + struct sig_record *sr1, *sr2; + + sr1 = (struct sig_record *) dp->d_data; + sr2 = (struct sig_record *) + newdp->d_data; + if (sr1->sig_alg_n == sr2->sig_alg_n) + goto delete; + } if (check_ttl) { if (newdp->d_ttl != dp->d_ttl) ns_warning(ns_log_db, @@ -621,11 +666,13 @@ db_update(const char *name, goto skip; if (odp->d_clev < dp->d_clev) goto skip; - if (odp->d_cred < dp->d_cred) + if ((odp->d_secure < dp->d_secure) || + ((odp->d_secure == dp->d_secure) && + (odp->d_cred < dp->d_cred))) goto skip; #ifdef BIND_UPDATE - if (!strcasecmp(name, zones[dp->d_zone].z_origin) && - !newdp) { + if (ns_samename(name, zones[dp->d_zone].z_origin) == 1 + && newdp == NULL) { /* do not delete SOA or NS records as a set */ /* XXXRTH isn't testing d_size unnecessary? */ if ((odp->d_size == 0) && @@ -677,6 +724,7 @@ db_update(const char *name, if (savedpp != NULL) foundRR = 1; #endif + deleted_something = 1; dp = rm_datum(dp, np, pdp, savedpp); } else { skip: pdp = dp; @@ -690,10 +738,16 @@ db_update(const char *name, return (NODATA); } } - /* XXX: delete a terminal namebuf also if all databuf's - * underneath of it have been deleted) */ - if (newdp == NULL) + if (newdp == NULL) { + if (deleted_something) { + while (np->n_data == NULL && np->n_hash == NULL) { + np = purge_node(htp, np); + if (np == NULL) + break; + } + } return (OK); + } /* XXX: empty nodes bypass credibility checks above; should check * response source address here if flags&NOTAUTH. */ @@ -790,7 +844,10 @@ db_cmp(const struct databuf *dp1, const struct databuf *dp2) { case T_MG: case T_MR: /* Only a domain name */ - return (strcasecmp((char *)dp1->d_data, (char *)dp2->d_data)); + if (ns_samename((char *)dp1->d_data, (char *)dp2->d_data) == 1) + return (0); + else + return (1); case T_SIG: /* Binary data, a domain name, more binary data */ @@ -800,8 +857,8 @@ db_cmp(const struct databuf *dp1, const struct databuf *dp2) { return (1); len = NS_SIG_SIGNER + strlen((char *)dp1->d_data + NS_SIG_SIGNER); - if (strcasecmp((char *)dp1->d_data + NS_SIG_SIGNER, - (char *)dp2->d_data + NS_SIG_SIGNER)) + if (ns_samename((char *)dp1->d_data + NS_SIG_SIGNER, + (char *)dp2->d_data + NS_SIG_SIGNER) != 1) return (1); return (memcmp(dp1->d_data + len, dp2->d_data + len, @@ -809,7 +866,7 @@ db_cmp(const struct databuf *dp1, const struct databuf *dp2) { case T_NXT: /* First a domain name, then binary data */ - if (strcasecmp((char *)dp1->d_data, (char *)dp2->d_data)) + if (ns_samename((char *)dp1->d_data, (char *)dp2->d_data) != 1) return (1); len = strlen((char *)dp1->d_data)+1; return (memcmp(dp1->d_data + len, @@ -837,14 +894,14 @@ db_cmp(const struct databuf *dp1, const struct databuf *dp2) { case T_SOA: case T_MINFO: case T_RP: - if (strcasecmp((char *)dp1->d_data, (char *)dp2->d_data)) + if (ns_samename((char *)dp1->d_data, (char *)dp2->d_data) != 1) return (1); cp1 = dp1->d_data + strlen((char *)dp1->d_data) + 1; cp2 = dp2->d_data + strlen((char *)dp2->d_data) + 1; - if (dp1->d_type != T_SOA) - return (strcasecmp((char *)cp1, (char *)cp2)); - if (strcasecmp((char *)cp1, (char *)cp2)) + if (ns_samename((char *)cp1, (char *)cp2) != 1) return (1); + if (dp1->d_type != T_SOA) + return (0); cp1 += strlen((char *)cp1) + 1; cp2 += strlen((char *)cp2) + 1; return (memcmp(cp1, cp2, INT32SZ * 5)); @@ -907,18 +964,22 @@ db_cmp(const struct databuf *dp1, const struct databuf *dp2) { if (*cp1++ != *cp2++ || *cp1++ != *cp2++) /* port */ return (1); } - return (strcasecmp((char *)cp1, (char *)cp2)); + if (ns_samename((char *)cp1, (char *)cp2) != 1) + return (1); + return (0); case T_PX: cp1 = dp1->d_data; cp2 = dp2->d_data; if (*cp1++ != *cp2++ || *cp1++ != *cp2++) /* cmp prio */ return (1); - if (strcasecmp((char *)cp1, (char *)cp2)) + if (ns_samename((char *)cp1, (char *)cp2) != 1) return (1); cp1 += strlen((char *)cp1) + 1; cp2 += strlen((char *)cp2) + 1; - return (strcasecmp((char *)cp1, (char *)cp2)); + if (ns_samename((char *)cp1, (char *)cp2) != 1) + return (1); + return (0); case T_TXT: case T_X25: diff --git a/contrib/bind/bin/named/named.conf b/contrib/bind/bin/named/named.conf index ab96666..d423b34 100644 --- a/contrib/bind/bin/named/named.conf +++ b/contrib/bind/bin/named/named.conf @@ -42,6 +42,9 @@ options { // notify on a zone-by-zone // basis in the "zone" statement // see (below) + max-serial-queries 4; // number of parallel SOA queries + // we can have outstanding for master + // zone change testing purposes auth-nxdomain yes; // always set AA on NXDOMAIN. // don't set this to 'no' unless // you know what you're doing -- older @@ -153,6 +156,20 @@ options { // every 'interface-interval' minutes statistics-interval 60; // log statistics every // 'statistics-interval' minutes + /* + * IXFR options + */ + maintain-ixfr-base no; // If yes, keep transaction log file for IXFR + max-ixfr-log-size 20; // Not implemented, maximum size the + // IXFR transaction log file to grow +}; + +/* + * Control listeners, for "ndc". Every nameserver needs at least one. + */ +controls { + inet * port 52 allow { any; }; // a bad idea + unix "/var/run/ndc" perm 0600 owner 0 group 0; // the default }; zone "master.demo.zone" { @@ -174,6 +191,7 @@ zone "master.demo.zone" { zone "slave.demo.zone" { type slave; // what used to be called "secondary" file "slave.demo.zone"; + ixfr-base "slave.demo.zone.ixfr"; // File name for IXFR transaction log file masters { 1.2.3.4; // where to zone transfer from 5.6.7.8; @@ -208,8 +226,14 @@ zone "stub.demo.zone" { zone "." { type hint; // used to be specified w/ "cache" file "cache.db"; + pubkey 257 255 1 "AQP2fHpZ4VMpKo/jc9Fod821uyfY5p8j5h/Am0V/KpBTMZjdXmp9QJe6yFRoIIzkaNCgTIftASdpXGgCwFB2j2KXP/rick6gvEer5VcDEkLR5Q=="; }; +trusted-keys { + . 257 255 1 "AQP2fHpZ4VMpKo/jc9Fod821uyfY5p8j5h/Am0V/KpBTMZjdXmp9QJe6yFRoIIzkaNCgTIftASdpXGgCwFB2j2KXP/rick6gvEer5VcDEkLR5Q=="; +}; + + acl can_query { !1.2.3/24; any; }; // network 1.2.3.0 mask 255.255.255.0 // is disallowed; rest are OK acl can_axfr { 1.2.3.4; can_query; }; // host 1.2.3.4 and any host allowed @@ -226,16 +250,18 @@ zone "non-default-acl.demo.zone" { }; }; -key sample_key { // for TSIG; supported by parser - algorithm hmac-md5; // but not yet implemented in the - secret "your secret here"; // rest of the server +key sample_key { // for TSIG + algorithm hmac-md5; // hmac-md5 is the supported algorithm + secret "abcdefgh"; // base 64 encoded secret }; key key2 { algorithm hmac-md5; - secret "ereh terces rouy"; + secret "87654321"; }; +acl key_acl { key sample_key; }; // a request signed with sample_key + server 1.2.3.4 { bogus no; // if yes, we won't query or listen // to this server @@ -245,9 +271,10 @@ server 1.2.3.4 { // if not specified, the global option // will be used transfers 0; // not implemented - keys { sample_key; key2; }; // for TSIG; supported by the parser - // but not yet implemented in the - // rest of the server + keys { sample_key; key2; }; // for TSIG; sign requests to this + // server with this key + support-ixfr yes; // for IXFR supported by server + // if yes, the listed server talks IXFR }; logging { diff --git a/contrib/bind/bin/named/named.h b/contrib/bind/bin/named/named.h index 57e787b..18f4ac4 100644 --- a/contrib/bind/bin/named/named.h +++ b/contrib/bind/bin/named/named.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -16,10 +16,10 @@ */ /* - * $Id: named.h,v 8.12 1997/12/04 06:52:27 halley Exp $ + * $Id: named.h,v 8.25 1999/10/13 18:00:19 vixie Exp $ */ -/* Options. Leave these on. */ +/* Options. Change them at your peril. */ #define DEBUG #define ADDAUTH #define STUBS @@ -30,31 +30,27 @@ #define QRYLOG #define YPKLUDGE #define RENICE -#define FORCED_RELOAD #define SLAVE_FORWARD -#define BIND_UPDATE +#define BIND_IXFR #define BIND_NOTIFY +#define BIND_UPDATE #define WANT_PIDFILE #define FWD_LOOP #define DOTTED_SERIAL #define SENSIBLE_DOTS #define ROUND_ROBIN -#define SORT_RESPONSE #define DNS_SECURITY #undef RSAREF #undef BSAFE #define ALLOW_LONG_TXT_RDATA - -#if 0 -#define strdup PLEASE_USE_SAVESTR -#define malloc PLEASE_USE_DB_MEMGET -#define calloc PLEASE_USE_DB_MEMGET -#define realloc PLEASE_USE_DB_MEMGET -#define free PLEASE_USE_DB_MEMPUT -#endif +#define STRICT_RFC2308 +#undef BIND_ZXFR #include <isc/assertions.h> #include <isc/list.h> +#include <isc/ctl.h> + +#include <res_update.h> #include "pathnames.h" diff --git a/contrib/bind/bin/named/ns_config.c b/contrib/bind/bin/named/ns_config.c index 4f95410..67bffbd 100644 --- a/contrib/bind/bin/named/ns_config.c +++ b/contrib/bind/bin/named/ns_config.c @@ -1,9 +1,9 @@ #if !defined(lint) && !defined(SABER) -static char rcsid[] = "$Id: ns_config.c,v 8.35 1998/05/05 19:44:48 halley Exp $"; +static const char rcsid[] = "$Id: ns_config.c,v 8.104 1999/11/08 23:09:42 vixie Exp $"; #endif /* not lint */ /* - * Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -19,12 +19,33 @@ static char rcsid[] = "$Id: ns_config.c,v 8.35 1998/05/05 19:44:48 halley Exp $" * SOFTWARE. */ +/* + * Portions Copyright (c) 1999 by Check Point Software Technologies, 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, and that + * the name of Check Point Software Technologies Incorporated 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 CHECK POINT SOFTWARE TECHNOLOGIES + * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED + * 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/param.h> #include <sys/socket.h> #include <sys/stat.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -46,6 +67,8 @@ static char rcsid[] = "$Id: ns_config.c,v 8.35 1998/05/05 19:44:48 halley Exp $" #include <isc/logging.h> #include <isc/memcluster.h> +#include <isc/dst.h> + #include "port_after.h" #ifdef HAVE_GETRUSAGE /* XXX */ @@ -55,6 +78,8 @@ static char rcsid[] = "$Id: ns_config.c,v 8.35 1998/05/05 19:44:48 halley Exp $" #include "named.h" #include "ns_parseutil.h" +/* Private. */ + static int tmpnum = 0; static int config_initialized = 0; @@ -90,8 +115,7 @@ free_zone_contents(struct zoneinfo *zp, int undefine_sym) { INSIST(zp != NULL); if (undefine_sym) - undefine_symbol(zone_symbol_table, zp->z_origin, - (zp->z_type << 16) | zp->z_class); + undefine_symbol(zone_symbol_table, zp->z_origin, zp->z_class); if (zp->z_flags & Z_TIMER_SET) { free_zone_timerinfo(zp); if (evClearTimer(ev, zp->z_timer) < 0) @@ -102,22 +126,44 @@ free_zone_contents(struct zoneinfo *zp, int undefine_sym) { } if (zp->z_origin != NULL) freestr(zp->z_origin); + zp->z_origin = NULL; if (zp->z_source != NULL) freestr(zp->z_source); + zp->z_source = NULL; + if (zp->z_ixfr_base != NULL) + freestr(zp->z_ixfr_base); + zp->z_ixfr_base = NULL; + if (zp->z_ixfr_tmp != NULL) + freestr(zp->z_ixfr_tmp); + zp->z_ixfr_tmp = NULL; if (zp->z_update_acl != NULL) free_ip_match_list(zp->z_update_acl); + zp->z_update_acl = NULL; if (zp->z_query_acl != NULL) free_ip_match_list(zp->z_query_acl); + zp->z_query_acl = NULL; if (zp->z_transfer_acl != NULL) free_ip_match_list(zp->z_transfer_acl); + zp->z_transfer_acl = NULL; #ifdef BIND_UPDATE if (zp->z_updatelog != NULL) freestr(zp->z_updatelog); + zp->z_updatelog = NULL; #endif /* BIND_UPDATE */ +#ifdef BIND_NOTIFY + if (zp->z_also_notify != NULL) + memput(zp->z_also_notify, + zp->z_notify_count * sizeof *zp->z_also_notify); + zp->z_also_notify = NULL; +#endif + block_signals(); + if (LINKED(zp, z_reloadlink)) + UNLINK(reloadingzones, zp, z_reloadlink); + unblock_signals(); } static void -free_zone(struct zoneinfo *zp) { +release_zone(struct zoneinfo *zp) { INSIST(zp != NULL); free_zone_contents(zp, 0); @@ -125,16 +171,16 @@ free_zone(struct zoneinfo *zp) { } struct zoneinfo * -find_zone(const char *name, int type, int class) { +find_zone(const char *name, int class) { struct zoneinfo *zp; symbol_value value; - ns_debug(ns_log_config, 3, "find_zone(%s,%d,%d)", name, type, class); - if (lookup_symbol(zone_symbol_table, name, - (type<<16) | class, &value)) { + ns_debug(ns_log_config, 3, "find_zone(%s, %d)", + *name ? name : ".", class); + if (lookup_symbol(zone_symbol_table, name, class, &value)) { INSIST(value.integer >= 0 && value.integer < nzones); - ns_debug(ns_log_config, 3, - "find_zone: existing zone %d", value.integer); + ns_debug(ns_log_config, 3, "find_zone: existing zone %d", + value.integer); zp = &zones[value.integer]; return (zp); } @@ -146,33 +192,11 @@ static struct zoneinfo * new_zone(int class, int type) { struct zoneinfo *zp; - if (zones != NULL) { - if (type == z_hint) { - zp = &zones[0]; - return (zp); - } - - for (zp = &zones[1]; zp < &zones[nzones]; zp++) - if (zp->z_type == z_nil) - return (zp); - } - - /* - * This code assumes that nzones never decreases. - */ - if (nzones % 64 == 0) { - ns_debug(ns_log_config, 1, "Reallocating zones structure"); - zp = (struct zoneinfo *) - memget((64 + nzones) * sizeof(struct zoneinfo)); - if (zp == NULL) - panic("no memory for more zones", NULL); - memcpy(zp, zones, nzones * sizeof(struct zoneinfo)); - memset(&zp[nzones], 0, 64 * sizeof(struct zoneinfo)); - memput(zones, nzones * sizeof(struct zoneinfo)); - zones = zp; - } - zp = &zones[nzones++]; + if (EMPTY(freezones)) + make_new_zones(); + zp = HEAD(freezones); + UNLINK(freezones, zp, z_freelink); return (zp); } @@ -181,7 +205,6 @@ new_zone(int class, int type) { */ static int validate_zone(struct zoneinfo *zp) { - int warnings = 0; char filename[MAXPATHLEN+1]; /* Check name */ @@ -204,7 +227,13 @@ validate_zone(struct zoneinfo *zp) { zp->z_origin); return (0); } - if (zp->z_type == z_hint && strcasecmp(zp->z_origin, "") != 0) { + if (zp->z_type == z_cache && ns_samename(zp->z_origin, "") != 1) { + ns_error(ns_log_config, + "only the root zone may be a cache zone (zone '%s')", + zp->z_origin); + return (0); + } + if (zp->z_type == z_hint && ns_samename(zp->z_origin, "") != 1) { ns_error(ns_log_config, "only the root zone may be a hint zone (zone '%s')", zp->z_origin); @@ -229,12 +258,25 @@ validate_zone(struct zoneinfo *zp) { return (0); } + if (zp->z_ixfr_base != NULL && strlen(zp->z_ixfr_base) > MAXPATHLEN) { + ns_error(ns_log_config, "ixfr filename too long for zone '%s'", + zp->z_origin); + return (0); + } + if (zp->z_ixfr_tmp != NULL && strlen(zp->z_ixfr_tmp) > MAXPATHLEN) { + ns_error(ns_log_config, "tmp ixfr filename too long for zone '%s'", + zp->z_origin); + return (0); + } + /* Check masters */ if (zp->z_addrcnt != 0) { - if (zp->z_type != z_slave && zp->z_type != z_stub) { + if (zp->z_type == z_master || zp->z_type == z_hint || + zp->z_type == z_cache) { ns_error(ns_log_config, "'masters' statement present for %s zone '%s'", - (zp->z_type == z_master) ? "master" : "hint", + (zp->z_type == z_master) ? "master" : + (zp->z_type == z_hint) ? "hint" : "cache", zp->z_origin); return (0); } @@ -247,6 +289,39 @@ validate_zone(struct zoneinfo *zp) { } } + /* Check allow-update and allow-transfer. */ + if (zp->z_update_acl || zp->z_transfer_acl) { + if (zp->z_type != z_master && zp->z_type != z_slave) { + ns_error(ns_log_config, + "'allow-{update,transfer}' option for non-{master,slave} zone '%s'", + zp->z_origin); + return (0); + } + } + + /* Check allow-query. */ + if (zp->z_query_acl) { + if (zp->z_type != z_master && + zp->z_type != z_slave && + zp->z_type != z_stub) { + ns_error(ns_log_config, + "'allow-query' option for non-{master,slave,stub} zone '%s'", + zp->z_origin); + return (0); + } + } + +#ifdef BIND_NOTIFY + /* Check notify */ + if (zp->z_notify != znotify_use_default) { + if (zp->z_type != z_master && zp->z_type != z_slave) { + ns_error(ns_log_config, + "'notify' given for non-master, non-slave zone '%s'", + zp->z_origin); + return (0); + } + } + /* Check also-notify */ if (zp->z_notify_count != 0) { if (zp->z_type != z_master && zp->z_type != z_slave) { @@ -256,9 +331,43 @@ validate_zone(struct zoneinfo *zp) { return (0); } } +#endif #ifdef BIND_UPDATE /* XXX need more checking here */ + if (!zp->z_updatelog && zp->z_source) { + /* XXX OS-specific filename validation here */ + if ((strlen(zp->z_source) + (sizeof ".log" - 1)) > + MAXPATHLEN) { + ns_error(ns_log_config, + "filename too long for dynamic zone '%s'", + zp->z_origin); + return (0); + } + /* this sprintf() is now safe */ + sprintf(filename, "%s.log", zp->z_source); + zp->z_updatelog = savestr(filename, 1); + } + + /* Check forward */ + if (zp->z_optset & OPTION_FORWARD_ONLY) { + if (zp->z_type == z_hint) { + ns_error(ns_log_config, + "'forward' given for hint zone '%s'", + zp->z_origin); + return (0); + } + } + /* Check forwarders */ + if (zp->z_fwdtab) { + if (zp->z_type == z_hint) { + ns_error(ns_log_config, + "'forwarders' given for hint zone '%s'", + zp->z_origin); + return (0); + } + } + if (zp->z_type == z_master) { if (!zp->z_soaincrintvl) zp->z_soaincrintvl = SOAINCRINTVL; @@ -266,22 +375,36 @@ validate_zone(struct zoneinfo *zp) { zp->z_dumpintvl = DUMPINTVL; if (!zp->z_deferupdcnt) zp->z_deferupdcnt = DEFERUPDCNT; - if (!zp->z_updatelog) { - /* XXX OS-specific filename validation here */ - if ((strlen(zp->z_source) + (sizeof ".log" - 1)) > - MAXPATHLEN) { - ns_error(ns_log_config, - "filename too long for dynamic zone '%s'", - zp->z_origin); - return (0); - } - /* this sprintf() is now safe */ - sprintf(filename, "%s.log", zp->z_source); - zp->z_updatelog = savestr(filename, 1); - } } #endif /* BIND_UPDATE */ + if (!zp->z_ixfr_base && zp->z_source) { + /* XXX OS-specific filename validation here */ + if ((strlen(zp->z_source) + (sizeof ".ixfr" - 1)) > + MAXPATHLEN) { + ns_error(ns_log_config, + "filename too long for dynamic zone '%s'", + zp->z_origin); + return (0); + } + /* this sprintf() is now safe */ + sprintf(filename, "%s.ixfr", zp->z_source); + zp->z_ixfr_base = savestr(filename, 1); + } + if (!zp->z_ixfr_tmp && zp->z_source) { + /* XXX OS-specific filename validation here */ + if ((strlen(zp->z_source) + (sizeof ".ixfr.tmp" - 1)) > + MAXPATHLEN) { + ns_error(ns_log_config, + "filename too long for dynamic zone '%s'", + zp->z_origin); + return (0); + } + /* this sprintf() is now safe */ + sprintf(filename, "%s.ixfr.tmp", zp->z_source); + zp->z_ixfr_tmp = savestr(filename, 1); + } + return (1); } @@ -308,6 +431,12 @@ begin_zone(char *name, int class) { zp->z_origin = name; zp->z_class = class; zp->z_checknames = not_set; + zp->z_log_size_ixfr = 0; + if (server_options->flags & OPTION_MAINTAIN_IXFR_BASE) + zp->z_maintain_ixfr_base = 1; + else + zp->z_maintain_ixfr_base = 0; + zp->z_max_log_size_ixfr = server_options->max_log_size_ixfr; zh.opaque = zp; return (zh); } @@ -318,7 +447,6 @@ begin_zone(char *name, int class) { */ static void update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) { - struct stat f_time; char buf[MAXPATHLEN+1]; int i; @@ -337,7 +465,7 @@ update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) { if ((zp->z_flags & Z_DYNAMIC) && !(new_zp->z_flags & Z_DYNAMIC) && ((zp->z_flags & Z_NEED_SOAUPDATE) || (zp->z_flags & Z_NEED_DUMP))) - (void)zonedump(zp); + (void) zonedump(zp, ISNOTIXFR); #endif /* @@ -348,6 +476,9 @@ update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) { freestr(zp->z_origin); zp->z_origin = new_zp->z_origin; new_zp->z_origin = NULL; + zp->z_maintain_ixfr_base = new_zp->z_maintain_ixfr_base; + zp->z_max_log_size_ixfr = new_zp->z_max_log_size_ixfr; + zp->z_log_size_ixfr = new_zp->z_log_size_ixfr; zp->z_class = new_zp->z_class; zp->z_type = new_zp->z_type; zp->z_checknames = new_zp->z_checknames; @@ -368,11 +499,28 @@ update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) { zp->z_transfer_acl = new_zp->z_transfer_acl; new_zp->z_transfer_acl = NULL; zp->z_max_transfer_time_in = new_zp->z_max_transfer_time_in; - +#ifdef BIND_NOTIFY zp->z_notify = new_zp->z_notify; - for (i = 0; i < new_zp->z_notify_count; i++) - zp->z_also_notify[i] = new_zp->z_also_notify[i]; + if (zp->z_also_notify) + memput(zp->z_also_notify, + zp->z_notify_count * sizeof *zp->z_also_notify); + zp->z_also_notify = new_zp->z_also_notify; zp->z_notify_count = new_zp->z_notify_count; + new_zp->z_also_notify = NULL; + new_zp->z_notify_count = 0; +#endif + if ((new_zp->z_flags & Z_FORWARD_SET) != 0) + zp->z_flags |= Z_FORWARD_SET; + else + zp->z_flags &= ~Z_FORWARD_SET; + if (zp->z_fwdtab != NULL) + free_forwarders(zp->z_fwdtab); + zp->z_fwdtab = new_zp->z_fwdtab; + new_zp->z_fwdtab = NULL; + + zp->z_dialup = new_zp->z_dialup; + zp->z_options = new_zp->z_options; + zp->z_optset = new_zp->z_optset; #ifdef BIND_UPDATE if (new_zp->z_flags & Z_DYNAMIC) @@ -387,24 +535,21 @@ update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) { zp->z_updatelog = new_zp->z_updatelog; new_zp->z_updatelog = NULL; #endif /* BIND_UPDATE */ + zp->z_port = new_zp->z_port; /* - * now deal with files + * Now deal with files. */ switch (zp->z_type) { + case z_cache: + ns_panic(ns_log_config, 1, "impossible condition"); + break; case z_hint: ns_debug(ns_log_config, 1, "source = %s", new_zp->z_source); zp->z_refresh = 0; /* No dumping. */ - /* - * If we've loaded this file, and the file has - * not been modified and contains no $include, - * then there's no need to reload. - */ - if (zp->z_source && - !strcmp(new_zp->z_source, zp->z_source) && - !(zp->z_flags & Z_INCLUDE) && - stat(zp->z_source, &f_time) != -1 && - zp->z_ftime == f_time.st_mtime) { + if (zp->z_source != NULL && + strcmp(new_zp->z_source, zp->z_source) == 0 && + (reconfiging || !zonefile_changed_p(zp))) { ns_debug(ns_log_config, 1, "cache is up to date"); break; } @@ -412,28 +557,37 @@ update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) { /* File has changed, or hasn't been loaded yet. */ if (zp->z_source) { freestr(zp->z_source); - clean_cache(fcachetab, 1); + purge_zone(zp->z_origin, fcachetab, zp->z_class); } zp->z_source = new_zp->z_source; new_zp->z_source = NULL; - ns_debug(ns_log_config, 1, "reloading zone"); - (void) db_load(zp->z_source, zp->z_origin, zp, NULL); + + if (zp->z_ixfr_base) + freestr(zp->z_ixfr_base); + zp->z_ixfr_base = new_zp->z_ixfr_base; + new_zp->z_ixfr_base = NULL; + + if (zp->z_ixfr_tmp) + freestr(zp->z_ixfr_tmp); + zp->z_ixfr_tmp = new_zp->z_ixfr_tmp; + new_zp->z_ixfr_tmp = NULL; + + ns_debug(ns_log_config, 1, "reloading hint zone"); + (void) db_load(zp->z_source, zp->z_origin, zp, NULL, + ISNOTIXFR); break; case z_master: ns_debug(ns_log_config, 1, "source = %s", new_zp->z_source); /* - * If we've loaded this file, and the file has - * not been modified and contains no $include, + * If we've loaded this file, and the file hasn't changed * then there's no need to reload. */ - if (zp->z_source && - !strcmp(new_zp->z_source, zp->z_source) && - !(zp->z_flags & Z_INCLUDE) && - stat(zp->z_source, &f_time) != -1 && - zp->z_ftime == f_time.st_mtime) { + if (zp->z_source != NULL && + strcmp(new_zp->z_source, zp->z_source) == 0 && + (reconfiging || !zonefile_changed_p(zp))) { ns_debug(ns_log_config, 1, "zone is up to date"); - break; /* zone is already up to date */ + break; } #ifdef BIND_UPDATE if (zp->z_source && (zp->z_flags & Z_DYNAMIC)) @@ -447,41 +601,27 @@ update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) { freestr(zp->z_source); zp->z_source = new_zp->z_source; new_zp->z_source = NULL; - zp->z_flags &= ~Z_AUTH; - ns_stopxfrs(zp); - purge_zone(zp->z_origin, hashtab, zp->z_class); - ns_debug(ns_log_config, 1, "reloading zone"); -#ifdef BIND_UPDATE - if (zp->z_flags & Z_DYNAMIC) { - struct stat sb; - if (stat(zp->z_source, &sb) < 0) - ns_error(ns_log_config, "stat(%s) failed: %s", - zp->z_source, strerror(errno)); - else { - if (sb.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) - ns_warning(ns_log_config, - "dynamic zone file '%s' is writable", - zp->z_source); - } - } -#endif - if (!db_load(zp->z_source, zp->z_origin, zp, NULL)) - zp->z_flags |= Z_AUTH; - zp->z_refresh = 0; /* no maintenance needed */ - zp->z_time = 0; -#ifdef BIND_UPDATE - zp->z_lastupdate = 0; - if (zp->z_flags & Z_DYNAMIC) + if (zp->z_ixfr_base != NULL) + freestr(zp->z_ixfr_base); + zp->z_ixfr_base = new_zp->z_ixfr_base; + new_zp->z_ixfr_base = NULL; + + if (zp->z_ixfr_tmp != NULL) + freestr(zp->z_ixfr_tmp); + zp->z_ixfr_tmp = new_zp->z_ixfr_tmp; + new_zp->z_ixfr_tmp = NULL; + + if (reload_master(zp) == 1) { /* * Note that going to primary_reload * unconditionally reloads the zone. */ - if (merge_logs(zp) == 1) { - new_zp->z_source = savestr(zp->z_source, 1); - goto primary_reload; - } -#endif + new_zp->z_source = savestr(zp->z_source, 1); + new_zp->z_ixfr_base = savestr(zp->z_ixfr_base, 1); + new_zp->z_ixfr_tmp = savestr(zp->z_ixfr_tmp, 1); + goto primary_reload; + } break; case z_slave: @@ -505,10 +645,9 @@ update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) { * current zone contents, try again now in case * we have a new server on the list. */ - if (zp->z_source && - (strcmp(new_zp->z_source, zp->z_source) || - (stat(zp->z_source, &f_time) == -1 || - (zp->z_ftime != f_time.st_mtime)))) { + if (zp->z_source != NULL && + (strcmp(new_zp->z_source, zp->z_source) != 0 || + ((!reconfiging) && zonefile_changed_p(zp)))) { ns_debug(ns_log_config, 1, "backup file changed or missing"); freestr(zp->z_source); @@ -516,42 +655,60 @@ update_zone_info(struct zoneinfo *zp, struct zoneinfo *new_zp) { zp->z_serial = 0; /* force xfer */ ns_stopxfrs(zp); /* - * We only need to do_reload if we have + * We only need to reload if we have ever * successfully transferred the zone. */ - if (zp->z_flags & Z_AUTH) { + if ((zp->z_flags & Z_AUTH) != 0) { zp->z_flags &= ~Z_AUTH; /* - * Purge old data and reload parent so that - * NS records are present during the zone - * transfer. + * Purge old data and mark the parent for + * reloading so that NS records are present + * during the zone transfer. */ do_reload(zp->z_origin, zp->z_type, - zp->z_class); + zp->z_class, 1); } } if (zp->z_source == NULL) { zp->z_source = new_zp->z_source; new_zp->z_source = NULL; } - if (!(zp->z_flags & Z_AUTH)) + + if (zp->z_ixfr_base != NULL) + freestr(zp->z_ixfr_base); + zp->z_ixfr_base = new_zp->z_ixfr_base; + new_zp->z_ixfr_base = NULL; + + if (zp->z_ixfr_tmp != NULL) + freestr(zp->z_ixfr_tmp); + zp->z_ixfr_tmp = new_zp->z_ixfr_tmp; + new_zp->z_ixfr_tmp = NULL; + + if ((zp->z_flags & Z_AUTH) == 0) zoneinit(zp); -#ifdef FORCED_RELOAD else { /* ** Force secondary to try transfer soon ** after SIGHUP. */ - if (!(zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING)) - && reloading) { + if ((zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING)) == 0 && + reloading && !reconfiging) { qserial_retrytime(zp, tt.tv_sec); sched_zone_maint(zp); } } -#endif /* FORCED_RELOAD */ + break; + case z_forward: + /* + * We don't know if the forwarder's list has changed + * so just purge the cache. In the future we may want + * see if the forwarders list has changed and only + * do this then. + */ + clean_cache_from(zp->z_origin, hashtab); break; } - if ((zp->z_flags & Z_FOUND) && /* already found? */ + if ((zp->z_flags & Z_FOUND) != 0 && /* already found? */ (zp - zones) != DB_Z_CACHE) /* cache never sets Z_FOUND */ ns_error(ns_log_config, "Zone \"%s\" declared more than once", zp->z_origin); @@ -582,40 +739,43 @@ end_zone(zone_config zh, int should_install) { should_install); if (!should_install) { - free_zone(new_zp); + release_zone(new_zp); return; } if (!validate_zone(new_zp)) { ns_error(ns_log_config, "zone '%s' did not validate, skipping", zname); - free_zone(new_zp); + release_zone(new_zp); return; } - zp = find_zone(new_zp->z_origin, new_zp->z_type, new_zp->z_class); + zp = find_zone(new_zp->z_origin, new_zp->z_class); + if (zp != NULL && zp->z_type != new_zp->z_type) { + remove_zone(zp, "redefined"); + zp = NULL; + } if (zp == NULL) { zp = new_zone(new_zp->z_class, new_zp->z_type); INSIST(zp != NULL); value.integer = (zp - zones); define_symbol(zone_symbol_table, savestr(new_zp->z_origin, 1), - (new_zp->z_type << 16) | new_zp->z_class, - value, SYMBOL_FREE_KEY); + new_zp->z_class, value, SYMBOL_FREE_KEY); } ns_debug(ns_log_config, 5, "zone '%s', type = %d, class = %d", zname, new_zp->z_type, new_zp->z_class); if (new_zp->z_source != NULL) ns_debug(ns_log_config, 5, " file = %s", new_zp->z_source); ns_debug(ns_log_config, 5, " checknames = %d", new_zp->z_checknames); - if (new_zp->z_addrcnt) { + if (new_zp->z_addrcnt != 0) { int i; ns_debug(ns_log_config, 5, " masters:"); - for (i=0; i<new_zp->z_addrcnt; i++) + for (i = 0; i < new_zp->z_addrcnt; i++) ns_debug(ns_log_config, 5, " %s", inet_ntoa(new_zp->z_addr[i])); } update_zone_info(zp, new_zp); - free_zone(new_zp); + release_zone(new_zp); zh.opaque = NULL; } @@ -662,7 +822,63 @@ set_zone_checknames(zone_config zh, enum severity s) { } int +set_zone_ixfr_file(zone_config zh, char *filename) { + struct zoneinfo *zp; + + zp = zh.opaque; + INSIST(zp != NULL); + + /* Fail if filename already set for this zone */ + if (zp->z_ixfr_base != NULL) + return (0); + zp->z_ixfr_base = filename; + if (zp->z_ixfr_tmp == NULL) { + int len = strlen(zp->z_ixfr_base) + (sizeof ".tmp" - 1); + char *str = (char *) memget(len); + + sprintf(str, "%s.tmp", zp->z_ixfr_base); + zp->z_ixfr_tmp = savestr(str, 1); + memput(str, len); + } + + return (1); +} + +int +set_zone_ixfr_tmp(zone_config zh, char *filename) { + struct zoneinfo *zp; + + zp = zh.opaque; + INSIST(zp != NULL); + + /* Fail if filename already set for this zone */ + if (zp->z_ixfr_tmp != NULL) + return (0); + zp->z_ixfr_tmp = filename; + return (1); +} + +int +set_zone_dialup(zone_config zh, int value) { + struct zoneinfo *zp; + + zp = zh.opaque; + INSIST(zp != NULL); + + if (value) { + zp->z_dialup = zdialup_yes; +#ifdef BIND_NOTIFY + zp->z_notify = znotify_yes; +#endif + } else + zp->z_dialup = zdialup_no; + + return (1); +} + +int set_zone_notify(zone_config zh, int value) { +#ifdef BIND_NOTIFY struct zoneinfo *zp; zp = zh.opaque; @@ -672,6 +888,17 @@ set_zone_notify(zone_config zh, int value) { zp->z_notify = znotify_yes; else zp->z_notify = znotify_no; +#endif + return (1); +} + +int +set_zone_maintain_ixfr_base(zone_config zh, int value) { + struct zoneinfo *zp; + + zp = zh.opaque; + INSIST(zp != NULL); + zp->z_maintain_ixfr_base = value; return (1); } @@ -683,7 +910,7 @@ set_zone_update_acl(zone_config zh, ip_match_list iml) { zp = zh.opaque; INSIST(zp != NULL); - /* Fail if checknames already set for this zone */ + /* Fail if update_acl already set for this zone */ if (zp->z_update_acl != NULL) return (0); zp->z_update_acl = iml; @@ -712,6 +939,14 @@ set_zone_query_acl(zone_config zh, ip_match_list iml) { } int +set_zone_master_port(zone_config zh, u_short port) { + struct zoneinfo *zp = zh.opaque; + + zp->z_port = port; + return (1); +} + +int set_zone_transfer_source(zone_config zh, struct in_addr ina) { struct zoneinfo *zp = zh.opaque; @@ -748,6 +983,37 @@ set_zone_transfer_time_in(zone_config zh, long max_time) { } int +set_zone_max_log_size_ixfr(zone_config zh, int size) { + struct zoneinfo *zp; + + zp = zh.opaque; + INSIST(zp != NULL); + + zp->z_max_log_size_ixfr = size; + return (0); +} + +int +set_zone_pubkey(zone_config zh, const int flags, const int proto, + const int alg, const char *str) +{ + struct zoneinfo *zp; + + zp = zh.opaque; + INSIST(zp != NULL); + + INSIST(zp != NULL && zp->z_origin != NULL); + return (add_trusted_key(zp->z_origin, flags, proto, alg, str)); +} + +int +set_trusted_key(const char *name, const int flags, const int proto, + const int alg, const char *str) { + INSIST(name != NULL); + return (add_trusted_key(name, flags, proto, alg, str)); +} + +int add_zone_master(zone_config zh, struct in_addr address) { struct zoneinfo *zp; @@ -766,18 +1032,51 @@ add_zone_master(zone_config zh, struct in_addr address) { int add_zone_notify(zone_config zh, struct in_addr address) { +#ifdef BIND_NOTIFY struct zoneinfo *zp; + int i; zp = zh.opaque; INSIST(zp != NULL); - zp->z_also_notify[zp->z_notify_count] = address; - zp->z_notify_count++; - if (zp->z_notify_count >= NSMAX) { - ns_warning(ns_log_config, "also-notify set full for zone '%s'", - zp->z_origin); - zp->z_notify_count = NSMAX - 1; + /* Check for duplicates. */ + + for (i = 0; i < zp->z_notify_count; i++) { + if (memcmp(zp->z_also_notify + i, + &address, sizeof address) == 0) { + ns_warning(ns_log_config, + "duplicate also-notify address ignored [%s] for zone '%s'", + inet_ntoa(address), zp->z_origin); + return (1); + } } + i = 0; + + if (zp->z_also_notify == NULL) { + zp->z_also_notify = memget(sizeof *zp->z_also_notify); + if (zp->z_also_notify == NULL) + i = 1; + } else { + register size_t size; + register struct in_addr *an_tmp; + size = zp->z_notify_count * sizeof *zp->z_also_notify; + an_tmp = memget(size + sizeof *zp->z_also_notify); + if (an_tmp == NULL) { + i = 1; + } else { + memcpy(an_tmp, zp->z_also_notify, size); + memput(zp->z_also_notify, size); + zp->z_also_notify = an_tmp; + } + } + if (i == 0) { + zp->z_also_notify[zp->z_notify_count] = address; + zp->z_notify_count++; + } else { + ns_warning(ns_log_config, "also-notify add failed (memget) [%s] for zone '%s'", + inet_ntoa(address), zp->z_origin); + } +#endif return (1); } @@ -786,13 +1085,12 @@ add_zone_notify(zone_config zh, struct in_addr address) { options new_options() { options op; - ip_match_list iml; - ip_match_element ime; op = (options)memget(sizeof (struct options)); if (op == NULL) panic("memget failed in new_options()", NULL); + op->version = savestr(ShortVersion, 1); op->directory = savestr(".", 1); op->pid_filename = savestr(_PATH_PIDFILE, 1); op->named_xfer = savestr(_PATH_XFER, 1); @@ -803,21 +1101,24 @@ new_options() { op->transfers_in = DEFAULT_XFERS_RUNNING; op->transfers_per_ns = DEFAULT_XFERS_PER_NS; op->transfers_out = 0; + op->serial_queries = MAXQSERIAL; op->transfer_format = axfr_one_answer; op->max_transfer_time_in = MAX_XFER_TIME; memset(&op->query_source, 0, sizeof op->query_source); op->query_source.sin_family = AF_INET; op->query_source.sin_addr.s_addr = htonl(INADDR_ANY); op->query_source.sin_port = htons(0); /* INPORT_ANY */ + op->axfr_src.s_addr = 0; +#ifdef BIND_NOTIFY + op->notify_count = 0; + op->also_notify = NULL; +#endif + op->blackhole_acl = NULL; op->query_acl = NULL; op->transfer_acl = NULL; - /* default topology is { localhost; localnets; } */ - iml = new_ip_match_list(); - ime = new_ip_match_localhost(); - add_to_ip_match_list(iml, ime); - ime = new_ip_match_localnets(); - add_to_ip_match_list(iml, ime); - op->topology = iml; + op->recursion_acl = NULL; + op->sortlist = NULL; + op->topology = NULL; op->data_size = 0UL; /* use system default */ op->stack_size = 0UL; /* use system default */ op->core_size = 0UL; /* use system default */ @@ -831,6 +1132,12 @@ new_options() { op->clean_interval = 3600; op->interface_interval = 3600; op->stats_interval = 3600; + op->ordering = NULL; + op->max_ncache_ttl = DEFAULT_MAX_NCACHE_TTL; + op->lame_ttl = NTTL; + op->heartbeat_interval = 3600; + op->max_log_size_ixfr = 20; + op->minroots = MINROOTS; return (op); } @@ -838,6 +1145,8 @@ void free_options(options op) { INSIST(op != NULL); + if (op->version) + freestr(op->version); if (op->directory) freestr(op->directory); if (op->pid_filename) @@ -850,10 +1159,22 @@ free_options(options op) { freestr(op->stats_filename); if (op->memstats_filename) freestr(op->memstats_filename); +#ifdef BIND_NOTIFY + if (op->also_notify) + free_also_notify(op); +#endif + if (op->blackhole_acl) + free_ip_match_list(op->blackhole_acl); if (op->query_acl) free_ip_match_list(op->query_acl); + if (op->recursion_acl) + free_ip_match_list(op->recursion_acl); if (op->transfer_acl) free_ip_match_list(op->transfer_acl); + if (op->sortlist) + free_ip_match_list(op->sortlist); + if (op->ordering) + free_rrset_order_list(op->ordering); if (op->topology) free_ip_match_list(op->topology); if (op->listen_list) @@ -863,9 +1184,9 @@ free_options(options op) { memput(op, sizeof *op); } -void -set_boolean_option(options op, int bool_opt, int value) { - INSIST(op != NULL); +static void +set_boolean_option(u_int *op_flags, int bool_opt, int value) { + INSIST(op_flags != NULL); switch (bool_opt) { case OPTION_NORECURSE: @@ -875,18 +1196,45 @@ set_boolean_option(options op, int bool_opt, int value) { case OPTION_NONOTIFY: case OPTION_NONAUTH_NXDOMAIN: case OPTION_MULTIPLE_CNAMES: + case OPTION_USE_IXFR: + case OPTION_MAINTAIN_IXFR_BASE: case OPTION_HOSTSTATS: case OPTION_DEALLOC_ON_EXIT: + case OPTION_USE_ID_POOL: + case OPTION_NORFC2308_TYPE1: + case OPTION_NODIALUP: + case OPTION_TREAT_CR_AS_SPACE: if (value) - op->flags |= bool_opt; + *op_flags |= bool_opt; else - op->flags &= ~bool_opt; + *op_flags &= ~bool_opt; break; default: panic("unexpected option in set_boolean_option", NULL); } } +void +set_global_boolean_option(options op, int bool_opt, int value) { + + INSIST(op != NULL); + + set_boolean_option(&op->flags, bool_opt, value); +} + +void +set_zone_boolean_option(zone_config zh, int bool_opt, int value) { + struct zoneinfo *zp; + + zp = zh.opaque; + INSIST(zp != NULL); + + set_boolean_option(&zp->z_options, bool_opt, value); + + /* Flag that zone option overrides corresponding global option */ + zp->z_optset |= bool_opt; +} + #ifdef HAVE_GETRUSAGE enum limit { Datasize, Stacksize, Coresize, Files }; @@ -897,6 +1245,8 @@ static struct rlimit initial_num_files; static void get_initial_limits() { + int fdlimit = evHighestFD(ev) + 1; + # ifdef RLIMIT_DATA if (getrlimit(RLIMIT_DATA, &initial_data_size) < 0) ns_warning(ns_log_config, "getrlimit(DATA): %s", @@ -916,6 +1266,19 @@ get_initial_limits() { if (getrlimit(RLIMIT_NOFILE, &initial_num_files) < 0) ns_warning(ns_log_config, "getrlimit(NOFILE): %s", strerror(errno)); + else if (initial_num_files.rlim_cur > fdlimit) { + initial_num_files.rlim_cur = fdlimit; + if (initial_num_files.rlim_cur > initial_num_files.rlim_max) + initial_num_files.rlim_max = fdlimit; + if (setrlimit(RLIMIT_NOFILE, &initial_num_files) < 0) { + ns_warning(ns_log_config, "setrlimit(files): %s", + strerror(errno)); + } else { + ns_warning(ns_log_config, + "limit files set to fdlimit (%d)", + fdlimit); + } + } # endif } @@ -923,13 +1286,14 @@ static void ns_rlimit(enum limit limit, u_long limit_value) { struct rlimit limits, old_limits; int rlimit = -1; + int fdlimit = evHighestFD(ev) + 1; char *name; rlimit_type value; if (limit_value == ULONG_MAX) { #ifndef RLIMIT_FILE_INFINITY if (limit == Files) - value = MAX((rlimit_type)sysconf(_SC_OPEN_MAX), + value = MIN((rlimit_type)evHighestFD(ev) + 1, initial_num_files.rlim_max); else #endif @@ -970,7 +1334,8 @@ ns_rlimit(enum limit limit, u_long limit_value) { name = "max number of open files"; if (value == 0) limits = initial_num_files; - /* XXX check < FD_SETSIZE? */ + if (value > fdlimit) + limits.rlim_cur = limits.rlim_max = value = fdlimit; break; default: name = NULL; /* Make gcc happy. */ @@ -994,8 +1359,7 @@ ns_rlimit(enum limit limit, u_long limit_value) { return; } else { if (value == 0) - ns_debug(ns_log_config, 3, "%s is default", - name); + ns_debug(ns_log_config, 3, "%s is default", name); else if (value == RLIM_INFINITY) ns_debug(ns_log_config, 3, "%s is unlimited", name); else @@ -1155,7 +1519,7 @@ periodic_getnetconf(evContext ctx, void *uap, struct timespec due, { getnetconf(1); } - + static void set_interval_timer(int which_timer, int interval) { evTimerID *tid = NULL; @@ -1174,6 +1538,10 @@ set_interval_timer(int which_timer, int interval) { tid = &stats_timer; func = ns_logstats; break; + case HEARTBEAT_TIMER: + tid = &heartbeat_timer; + func = ns_heartbeat; + break; default: ns_panic(ns_log_config, 1, "set_interval_timer: unknown timer %d", which_timer); @@ -1215,7 +1583,6 @@ set_interval_timer(int which_timer, int interval) { */ void set_options(options op, int is_default) { - listen_info li; INSIST(op != NULL); if (op->listen_list == NULL) { @@ -1231,6 +1598,18 @@ set_options(options op, int is_default) { add_to_ip_match_list(iml, ime); add_listen_on(op, htons(NS_DEFAULTPORT), iml); } + if (op->topology == NULL) { + ip_match_list iml; + ip_match_element ime; + + /* default topology is { localhost; localnets; } */ + iml = new_ip_match_list(); + ime = new_ip_match_localhost(); + add_to_ip_match_list(iml, ime); + ime = new_ip_match_localnets(); + add_to_ip_match_list(iml, ime); + op->topology = iml; + } if (server_options != NULL) free_options(server_options); server_options = op; @@ -1263,6 +1642,14 @@ set_options(options op, int is_default) { /* XXX currently transfers_out is not used */ + if (!op->max_ncache_ttl) + op->max_ncache_ttl = DEFAULT_MAX_NCACHE_TTL; + else if (op->max_ncache_ttl > max_cache_ttl) + op->max_ncache_ttl = max_cache_ttl; + + if (op->lame_ttl > (3 * NTTL)) + op->lame_ttl = 3 * NTTL; + /* * Limits */ @@ -1276,7 +1663,6 @@ set_options(options op, int is_default) { ns_info(ns_log_config, "cannot set resource limits on this system"); #endif - /* * Timers */ @@ -1284,6 +1670,8 @@ set_options(options op, int is_default) { set_interval_timer(INTERFACE_TIMER, server_options->interface_interval); set_interval_timer(STATS_TIMER, server_options->stats_interval); + set_interval_timer(HEARTBEAT_TIMER, + server_options->heartbeat_interval); options_installed = 1; default_options_installed = is_default; @@ -1295,6 +1683,129 @@ use_default_options() { } /* + * rrset order types + */ +static struct res_sym order_table [] = { + { unknown_order, " unknown " }, /* can't match */ + { fixed_order, "fixed" }, + { cyclic_order, "cyclic" }, + { random_order, "random" }, + { unknown_order, NULL } +}; + +/* + * Return the print name of the ordering value. + */ +const char * +p_order(int order) { + return (__sym_ntos(order_table, order, (int *)0)); +} + +/* + * Lookup the ordering by name and return the matching enum value. + */ +enum ordering +lookup_ordering(const char *name) { + int i; + + for (i = 0; order_table[i].name != NULL; i++) + if (strcasecmp(name,order_table[i].name) == 0) + return ((enum ordering)order_table[i].number); + return (unknown_order); +} + +/* + * rrset-order Lists + */ +rrset_order_list +new_rrset_order_list() { + rrset_order_list rol ; + + rol = (rrset_order_list)memget(sizeof (struct rrset_order_list)); + if (rol == NULL) + panic("memget failed in new_rrset_order_list", NULL); + rol->first = NULL; + rol->last = NULL; + + return (rol); +} + +void +free_rrset_order_list(rrset_order_list rol) { + rrset_order_element roe, next_element; + + for (roe = rol->first; roe != NULL; roe = next_element) { + next_element = roe->next; + freestr(roe->name); + memput(roe, sizeof (*roe)); + } + memput(rol, sizeof (*rol)); +} + + +void +add_to_rrset_order_list(rrset_order_list rol, rrset_order_element roe) { + INSIST(rol != NULL); + INSIST(roe != NULL); + + if (rol->last != NULL) + rol->last->next = roe; + roe->next = NULL; + rol->last = roe; + if (rol->first == NULL) + rol->first = roe; +} + +/* XXX this isn't being used yet, but it probably should be. Where? */ +void +dprint_rrset_order_list(int category, rrset_order_list rol, int indent, + char *allow, char *deny) { + rrset_order_element roe ; + char spaces[40+1]; + + INSIST(rol != NULL); + + if (indent > 40) + indent = 40; + if (indent) + memset(spaces, ' ', indent); + spaces[indent] = '\0'; + + for (roe = rol->first; roe != NULL; roe = roe->next) { + ns_debug(category, 7, "%sclass %s type %s name %s order %s", + spaces, p_class(roe->class), p_type(roe->type), + roe->name, p_order(roe->order)); + } +} + + +rrset_order_element +new_rrset_order_element(int class, int type, char *name, enum ordering order) +{ + rrset_order_element roe; + int i ; + + roe = (rrset_order_element)memget(sizeof (struct rrset_order_element)); + if (roe == NULL) + panic("memget failed in new_rrset_order_element", NULL); + roe->class = class ; + roe->type = type ; + roe->name = name; + roe->order = order; + + i = strlen(roe->name) - 1; + INSIST (i >= 0); + if (roe->name[i - 1] == '.') { + /* We compare from right to left so we don't need a dot on + the end. */ + roe->name[i - 1] = '\0' ; + } + + return roe ; +} + + +/* * IP Matching Lists */ @@ -1390,6 +1901,19 @@ new_ip_match_indirect(ip_match_list iml) { } ip_match_element +new_ip_match_key(DST_KEY *dst_key) { + ip_match_element ime; + + ime = (ip_match_element)memget(sizeof (struct ip_match_element)); + if (ime == NULL) + panic("memget failed in new_ip_match_key", NULL); + ime->type = ip_match_key; + ime->flags = 0; + ime->u.key.key = dst_key; + return (ime); +} + +ip_match_element new_ip_match_localhost() { ip_match_element ime; @@ -1445,7 +1969,6 @@ dprint_ip_match_list(int category, ip_match_list iml, int indent, char spaces[40+1]; char addr_text[sizeof "255.255.255.255"]; char mask_text[sizeof "255.255.255.255"]; - char *tmp; INSIST(iml != NULL); @@ -1488,6 +2011,11 @@ dprint_ip_match_list(int category, ip_match_list iml, int indent, ime->u.indirect.list, indent+2, allow, deny); break; + case ip_match_key: + ns_debug(category, 7, "%s%skey %s", spaces, + (ime->flags & IP_MATCH_NEGATE) ? deny : allow, + ime->u.key.key->dk_key_name); + break; default: panic("unexpected ime type in dprint_ip_match_list()", NULL); @@ -1496,7 +2024,9 @@ dprint_ip_match_list(int category, ip_match_list iml, int indent, } int -ip_match_address(ip_match_list iml, struct in_addr address) { +ip_match_addr_or_key(ip_match_list iml, struct in_addr address, + DST_KEY *key) +{ ip_match_element ime; int ret; int indirect; @@ -1518,13 +2048,25 @@ ip_match_address(ip_match_list iml, struct in_addr address) { ime->u.indirect.list = local_networks; indirect = 1; break; + case ip_match_key: + if (key == NULL) { + indirect = 0; + break; + } + else { + if (ns_samename(ime->u.key.key->dk_key_name, + key->dk_key_name) == 1) + return (1); + else + continue; + } default: - indirect = 0; /* Make gcc happy. */ - panic("unexpected ime type in ip_match_address()", + panic("unexpected ime type in ip_match_addr_or_key()", NULL); } if (indirect) { - ret = ip_match_address(ime->u.indirect.list, address); + ret = ip_match_addr_or_key(ime->u.indirect.list, + address, key); if (ret >= 0) { if (ime->flags & IP_MATCH_NEGATE) ret = (ret) ? 0 : 1; @@ -1544,18 +2086,30 @@ ip_match_address(ip_match_list iml, struct in_addr address) { } int -ip_address_allowed(ip_match_list iml, struct in_addr address) { +ip_match_address(ip_match_list iml, struct in_addr address) { + return ip_match_addr_or_key(iml, address, NULL); +} + +int +ip_addr_or_key_allowed(ip_match_list iml, struct in_addr address, + DST_KEY *key) +{ int ret; if (iml == NULL) return (0); - ret = ip_match_address(iml, address); + ret = ip_match_addr_or_key(iml, address, key); if (ret < 0) ret = 0; return (ret); } int +ip_address_allowed(ip_match_list iml, struct in_addr address) { + return(ip_addr_or_key_allowed(iml, address, NULL)); +} + +int ip_match_network(ip_match_list iml, struct in_addr address, struct in_addr mask) { ip_match_element ime; @@ -1579,6 +2133,9 @@ ip_match_network(ip_match_list iml, struct in_addr address, ime->u.indirect.list = local_networks; indirect = 1; break; + case ip_match_key: + indirect = 0; + break; default: indirect = 0; /* Make gcc happy. */ panic("unexpected ime type in ip_match_network()", @@ -1630,6 +2187,9 @@ distance_of_address(ip_match_list iml, struct in_addr address) { ime->u.indirect.list = local_networks; indirect = 1; break; + case ip_match_key: + indirect = 0; + return (-1); default: indirect = 0; /* Make gcc happy. */ panic("unexpected ime type in distance_of_address()", @@ -1666,14 +2226,14 @@ int ip_match_is_none(ip_match_list iml) { ip_match_element ime; - if (iml == NULL) + if ((iml == NULL) || (iml->first == NULL)) return (1); ime = iml->first; if (ime->type == ip_match_indirect) { if (ime->flags & IP_MATCH_NEGATE) return (0); iml = ime->u.indirect.list; - if (iml == NULL) + if ((iml == NULL) || (iml->first == NULL)) return (0); ime = iml->first; } @@ -1694,30 +2254,13 @@ ip_match_is_none(ip_match_list iml) { * forward zones. */ -void -add_forwarder(options op, struct in_addr address) { - struct fwdinfo *fip = NULL, *ftp = NULL; - -#ifdef SLAVE_FORWARD - int forward_count = 0; -#endif - - INSIST(op != NULL); +static void +add_forwarder(struct fwdinfo **fipp, struct in_addr address) { + struct fwdinfo *fip = *fipp, *ftp = NULL; /* On multiple forwarder lines, move to end of the list. */ -#ifdef SLAVE_FORWARD - if (op->fwdtab != NULL) { - forward_count++; - for (fip = op->fwdtab; fip->next != NULL; fip = fip->next) - forward_count++; - } -#else - if (op->fwdtab != NULL) { - for (fip = op->fwdtab; fip->next != NULL; fip = fip->next) { - ; - } - } -#endif /* SLAVE_FORWARD */ + while (fip != NULL && fip->next != NULL) + fip = fip->next; ftp = (struct fwdinfo *)memget(sizeof(struct fwdinfo)); if (!ftp) @@ -1733,19 +2276,95 @@ add_forwarder(options op, struct in_addr address) { return; } #endif /* FWD_LOOP */ - ns_debug(ns_log_config, 2, "added forwarder %s", inet_ntoa(address)); ftp->next = NULL; - if (op->fwdtab == NULL) - op->fwdtab = ftp; /* First time only */ + if (fip == NULL) + *fipp = ftp; /* First time only */ else fip->next = ftp; +} + +void +free_also_notify(options op) { +#ifdef BIND_NOTIFY + memput(op->also_notify, op->notify_count * sizeof *op->also_notify); + op->also_notify = NULL; + op->notify_count = 0; +#endif +} + +int +add_global_also_notify(options op, struct in_addr address) { +#ifdef BIND_NOTIFY + int i; + + INSIST(op != NULL); + + ns_debug(ns_log_config, 2, "adding global notify %s", + inet_ntoa(address)); + + /* Check for duplicates. */ + + for (i = 0; i < op->notify_count; i++) { + if (memcmp(op->also_notify + i, + &address, sizeof address) == 0) { + ns_warning(ns_log_config, + "duplicate global also-notify address ignored [%s]", + inet_ntoa(address)); + return (1); + } + } + i = 0; + + if (op->also_notify == NULL) { + op->also_notify = memget(sizeof *op->also_notify); + if (op->also_notify == NULL) + i = 1; + } else { + register size_t size; + register struct in_addr *an_tmp; + size = op->notify_count * sizeof *op->also_notify; + an_tmp = memget(size + sizeof *op->also_notify); + if (an_tmp == NULL) { + i = 1; + } else { + memcpy(an_tmp, op->also_notify, size); + memput(op->also_notify, size); + op->also_notify = an_tmp; + } + } + if (i == 0) { + op->also_notify[op->notify_count] = address; + op->notify_count++; + } else { + ns_warning(ns_log_config, + "global also-notify add failed (memget) [%s]", + inet_ntoa(address)); + } +#endif + return (1); +} + +void +add_global_forwarder(options op, struct in_addr address) { #ifdef SLAVE_FORWARD - forward_count++; + struct fwdinfo *fip; + int forward_count; +#endif + + INSIST(op != NULL); + + ns_debug(ns_log_config, 2, "adding default forwarder %s", + inet_ntoa(address)); + add_forwarder(&op->fwdtab, address); + +#ifdef SLAVE_FORWARD /* ** Set the slave retry time to 60 seconds total divided ** between each forwarder */ + for (forward_count = 0, fip = op->fwdtab; fip != NULL; fip = fip->next) + forward_count++; if (forward_count != 0) { slave_retry = (int) (60 / forward_count); if(slave_retry <= 0) @@ -1755,6 +2374,32 @@ add_forwarder(options op, struct in_addr address) { } void +set_zone_forward(zone_config zh) { + struct zoneinfo *zp; + zp = zh.opaque; + + zp->z_flags |= Z_FORWARD_SET; + set_zone_boolean_option(zh, OPTION_FORWARD_ONLY, 0); +} + +void +add_zone_forwarder(zone_config zh, struct in_addr address) { + struct zoneinfo *zp; + char *zname; + + zp = zh.opaque; + INSIST(zp != NULL); + + zname = (zp->z_origin[0] == '\0') ? "." : zp->z_origin; + ns_debug(ns_log_config, 2, "adding forwarder %s for zone zone '%s'", + inet_ntoa(address), zname); + + zp->z_flags |= Z_FORWARD_SET; + + add_forwarder(&zp->z_fwdtab, address); +} + +void free_forwarders(struct fwdinfo *fwdtab) { struct fwdinfo *ftp, *fnext; @@ -1762,13 +2407,13 @@ free_forwarders(struct fwdinfo *fwdtab) { fnext = ftp->next; memput(ftp, sizeof *ftp); } + fwdtab = NULL; } /* * Servers */ - static server_info new_server(struct in_addr address) { server_info si; @@ -1782,7 +2427,11 @@ new_server(struct in_addr address) { si->transfer_format = axfr_use_default; si->key_list = NULL; si->next = NULL; - return si; + if (server_options->flags & OPTION_MAINTAIN_IXFR_BASE) + si->flags |= SERVER_INFO_SUPPORT_IXFR; + else + si->flags &= ~SERVER_INFO_SUPPORT_IXFR; + return (si); } static void @@ -1839,6 +2488,14 @@ free_nameserver_info() { } } +static void +free_secretkey_info() { + if (secretkey_info != NULL) { + free_key_info_list(secretkey_info); + secretkey_info = NULL; + } +} + server_config begin_server(struct in_addr address) { server_config sc; @@ -1872,6 +2529,7 @@ set_server_option(server_config sc, int bool_opt, int value) { switch (bool_opt) { case SERVER_INFO_BOGUS: + case SERVER_INFO_SUPPORT_IXFR: if (value) si->flags |= bool_opt; else @@ -1908,7 +2566,7 @@ set_server_transfer_format(server_config sc, } void -add_server_key_info(server_config sc, key_info ki) { +add_server_key_info(server_config sc, DST_KEY *dst_key) { server_info si; si = sc.opaque; @@ -1917,44 +2575,75 @@ add_server_key_info(server_config sc, key_info ki) { if (si->key_list == NULL) si->key_list = new_key_info_list(); - add_to_key_info_list(si->key_list, ki); + add_to_key_info_list(si->key_list, dst_key); } /* * Keys */ -key_info +DST_KEY * new_key_info(char *name, char *algorithm, char *secret) { - key_info ki; + DST_KEY *dst_key; + int alg, blen; + u_char buffer[1024]; INSIST(name != NULL); INSIST(algorithm != NULL); INSIST(secret != NULL); - ki = (key_info)memget(sizeof (struct key_info)); - if (ki == NULL) - panic("memget failed in new_key_info", NULL); - ki->name = name; - ki->algorithm = algorithm; - ki->secret = secret; - return (ki); + alg = tsig_alg_value(algorithm); + if (alg == -1) { + ns_warning(ns_log_config, "Unsupported TSIG algorithm %s", + algorithm); + return (NULL); + } + + blen = b64_pton(secret, buffer, sizeof(buffer)); + if (blen < 0) { + ns_warning(ns_log_config, "Invalid TSIG secret \"%s\"", secret); + return (NULL); + } + dst_key = dst_buffer_to_key(name, alg, + NS_KEY_TYPE_AUTH_ONLY|NS_KEY_NAME_ENTITY, + NS_KEY_PROT_ANY, buffer, blen); + if (dst_key == NULL) + ns_warning(ns_log_config, + "dst_buffer_to_key failed in new_key_info"); + return (dst_key); } void -free_key_info(key_info ki) { - INSIST(ki != NULL); - freestr(ki->name); - freestr(ki->algorithm); - freestr(ki->secret); - memput(ki, sizeof *ki); +free_key_info(DST_KEY *dst_key) { + INSIST(dst_key != NULL); + dst_free_key(dst_key); +} + +DST_KEY * +find_key(char *name, char *algorithm) { + key_list_element ke; + + if (secretkey_info == NULL) + return (NULL); + + for (ke = secretkey_info->first; ke != NULL; ke = ke->next) { + DST_KEY *dst_key = ke->key; + + if (ns_samename(name, dst_key->dk_key_name) != 1) + continue; + if (algorithm == NULL || + dst_key->dk_alg == tsig_alg_value(algorithm)) + break; + } + if (ke == NULL) + return (NULL); + return (ke->key); } void -dprint_key_info(key_info ki) { - INSIST(ki != NULL); - ns_debug(ns_log_config, 7, "key %s", ki->name); - ns_debug(ns_log_config, 7, " algorithm %s", ki->algorithm); - ns_debug(ns_log_config, 7, " secret %s", ki->secret); +dprint_key_info(DST_KEY *dst_key) { + INSIST(dst_key != NULL); + ns_debug(ns_log_config, 7, "key %s", dst_key->dk_key_name); + ns_debug(ns_log_config, 7, " algorithm %d", dst_key->dk_alg); } key_info_list @@ -1983,16 +2672,16 @@ free_key_info_list(key_info_list kil) { } void -add_to_key_info_list(key_info_list kil, key_info ki) { +add_to_key_info_list(key_info_list kil, DST_KEY *dst_key) { key_list_element kle; INSIST(kil != NULL); - INSIST(ki != NULL); + INSIST(dst_key != NULL); kle = (key_list_element)memget(sizeof (struct key_list_element)); if (kle == NULL) panic("memget failed in add_to_key_info_list()", NULL); - kle->info = ki; + kle->key = dst_key; if (kil->last != NULL) kil->last->next = kle; kle->next = NULL; @@ -2008,7 +2697,7 @@ dprint_key_info_list(key_info_list kil) { INSIST(kil != NULL); for (kle = kil->first; kle != NULL; kle = kle->next) - dprint_key_info(kle->info); + dprint_key_info(kle->key); } /* @@ -2098,7 +2787,6 @@ open_special_channels() { void set_logging(log_config log_cfg, int is_default) { log_context lc; - int skip_debug = 0; INSIST(log_cfg != NULL); lc = log_cfg->log_ctx; @@ -2203,7 +2891,6 @@ use_default_logging() { static void init_default_log_channels() { - FILE *null_stream; u_int flags; char *name; FILE *stream; @@ -2244,9 +2931,8 @@ shutdown_default_log_channels() { log_free_channel(null_channel); } -void +void init_logging() { - int i; int size; const struct ns_sym *s; char category_name[256]; @@ -2266,7 +2952,7 @@ init_logging() { use_default_logging(); } -void +void shutdown_logging() { int size; const struct ns_sym *s; @@ -2279,6 +2965,7 @@ shutdown_logging() { freestr(logging_categories[s->number]); size = ns_log_max_category * (sizeof (char *)); memput(logging_categories, size); + logging_categories = NULL; } /* @@ -2297,6 +2984,7 @@ init_configuration() { zone_symbol_table = new_symbol_table(ZONE_SYM_TABLE_SIZE, NULL); use_default_options(); parser_initialize(); + ns_ctl_initialize(); config_initialized = 1; } @@ -2304,6 +2992,7 @@ void shutdown_configuration() { REQUIRE(config_initialized); + ns_ctl_shutdown(); if (server_options != NULL) { free_options(server_options); server_options = NULL; @@ -2311,6 +3000,7 @@ shutdown_configuration() { if (current_pid_filename != NULL) freestr(current_pid_filename); free_nameserver_info(); + free_secretkey_info(); free_symbol_table(zone_symbol_table); parser_shutdown(); config_initialized = 0; @@ -2329,6 +3019,7 @@ load_configuration(const char *filename) { * global data structures we'll be updating. */ free_nameserver_info(); + free_secretkey_info(); bogus_nameservers = new_ip_match_list(); options_installed = 0; diff --git a/contrib/bind/bin/named/ns_ctl.c b/contrib/bind/bin/named/ns_ctl.c new file mode 100644 index 0000000..259093b --- /dev/null +++ b/contrib/bind/bin/named/ns_ctl.c @@ -0,0 +1,866 @@ +#if !defined(lint) && !defined(SABER) +static const char rcsid[] = "$Id: ns_ctl.c,v 8.28 1999/10/13 16:39:04 vixie Exp $"; +#endif /* not lint */ + +/* + * 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. + */ + +/* Extern. */ + +#include "port_before.h" + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/stat.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 <limits.h> +#include <resolv.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <time.h> +#include <unistd.h> +#include <fcntl.h> + +#include <isc/eventlib.h> +#include <isc/logging.h> +#include <isc/memcluster.h> + +#include "port_after.h" + +#include "named.h" + +/* Defs. */ + +#define CONTROL_FOUND 0x0001 /* for mark and sweep. */ +#define MAX_STR_LEN 500 + +struct control { + LINK(struct control) link; + enum { t_dead, t_inet, t_unix } type; + struct ctl_sctx *sctx; + u_int flags; + union { + struct { + struct sockaddr_in in; + ip_match_list allow; + } v_inet; + struct { + struct sockaddr_un un; + mode_t mode; + uid_t owner; + gid_t group; + } v_unix; + } var; +}; + +/* Forward. */ + +static struct ctl_sctx *mksrvr(control, const struct sockaddr *, size_t); +static control new_control(void); +static void free_control(controls *, control); +static void free_controls(controls *); +static int match_control(control, control); +static control find_control(controls, control); +static void propagate_changes(const control, control); +static void install(control); +static void install_inet(control); +static void install_unix(control); +static void logger(enum ctl_severity, const char *fmt, ...); +static void verb_connect(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); +static void verb_getpid(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); +static void getpid_closure(struct ctl_sctx *, struct ctl_sess *, + void *); +static void verb_status(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); +static void status_closure(struct ctl_sctx *, struct ctl_sess *, + void *); +static void verb_stop(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); +static void verb_exec(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); +static void verb_reload(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); +static void verb_reconfig(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); +static void verb_dumpdb(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); +static void verb_stats(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); +static void verb_trace(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); +static void trace_closure(struct ctl_sctx *, struct ctl_sess *, + void *); +static void verb_notrace(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); +static void verb_querylog(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); +static void verb_help(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); +static void verb_quit(struct ctl_sctx *, struct ctl_sess *, + const struct ctl_verb *, + const char *, u_int, void *, void *); + +/* Private data. */ + +static controls server_controls; + +static struct ctl_verb verbs[] = { + { "", verb_connect, ""}, + { "getpid", verb_getpid, "getpid"}, + { "status", verb_status, "status"}, + { "stop", verb_stop, "stop"}, + { "exec", verb_exec, "exec"}, + { "reload", verb_reload, "reload [zone] ..."}, + { "reconfig", verb_reconfig, "reconfig (just sees new/gone zones)"}, + { "dumpdb", verb_dumpdb, "dumpdb"}, + { "stats", verb_stats, "stats"}, + { "trace", verb_trace, "trace [level]"}, + { "notrace", verb_notrace, "notrace"}, + { "querylog", verb_querylog, "querylog"}, + { "qrylog", verb_querylog, "qrylog"}, + { "help", verb_help, "help"}, + { "quit", verb_quit, "quit"}, + { NULL, NULL, NULL} +}; + +/* Public functions. */ + +void +ns_ctl_initialize(void) { + INIT_LIST(server_controls); +} + +void +ns_ctl_shutdown(void) { + if (!EMPTY(server_controls)) + free_controls(&server_controls); +} + +void +ns_ctl_defaults(controls *list) { + ns_ctl_add(list, ns_ctl_new_unix(_PATH_NDCSOCK, 0600, 0, 0)); +} + +void +ns_ctl_add(controls *list, control new) { + if (!find_control(*list, new)) + APPEND(*list, new, link); +} + +control +ns_ctl_new_inet(struct in_addr saddr, u_int sport, ip_match_list allow) { + control new = new_control(); + + INIT_LINK(new, link); + new->type = t_inet; + memset(&new->var.v_inet.in, 0, sizeof new->var.v_inet.in); + new->var.v_inet.in.sin_family = AF_INET; + new->var.v_inet.in.sin_addr = saddr; + new->var.v_inet.in.sin_port = sport; + new->var.v_inet.allow = allow; + return (new); +} + +control +ns_ctl_new_unix(char *path, mode_t mode, uid_t owner, gid_t group) { + control new = new_control(); + + INIT_LINK(new, link); + new->type = t_unix; + memset(&new->var.v_unix.un, 0, sizeof new->var.v_unix.un); + new->var.v_unix.un.sun_family = AF_UNIX; + strncpy(new->var.v_unix.un.sun_path, path, + sizeof new->var.v_unix.un.sun_path - 1); + new->var.v_unix.mode = mode; + new->var.v_unix.owner = owner; + new->var.v_unix.group = group; + return (new); +} + +void +ns_ctl_install(controls *new) { + control ctl, old, next; + + /* Find all the controls which aren't new or deleted. */ + for (ctl = HEAD(server_controls); ctl != NULL; ctl = NEXT(ctl, link)) + ctl->flags &= ~CONTROL_FOUND; + for (ctl = HEAD(*new); ctl != NULL; ctl = next) { + next = NEXT(ctl, link); + old = find_control(server_controls, ctl); + if (old != NULL) { + old->flags |= CONTROL_FOUND; + propagate_changes(ctl, old); + if (old->sctx == NULL) + free_control(&server_controls, old); + free_control(new, ctl); + } + } + + /* Destroy any old controls which weren't found. */ + for (ctl = HEAD(server_controls); ctl != NULL; ctl = next) { + next = NEXT(ctl, link); + if ((ctl->flags & CONTROL_FOUND) == 0) + free_control(&server_controls, ctl); + } + + /* Add any new controls which were found. */ + for (ctl = HEAD(*new); ctl != NULL; ctl = next) { + next = NEXT(ctl, link); + APPEND(server_controls, ctl, link); + install(ctl); + if (ctl->sctx == NULL) + free_control(&server_controls, ctl); + } +} + +/* Private functions. */ + +static struct ctl_sctx * +mksrvr(control ctl, const struct sockaddr *sa, size_t salen) { + return (ctl_server(ev, sa, salen, verbs, 500, 222, + 600, 5, 10, logger, ctl)); +} + +static control +new_control(void) { + control new = memget(sizeof *new); + + if (new == NULL) + panic("memget failed in new_control()", NULL); + new->type = t_dead; + new->sctx = NULL; + return (new); +} + +static void +free_control(controls *list, control this) { + int was_live = 0; + struct stat sb; + + if (this->sctx != NULL) { + ctl_endserver(this->sctx); + this->sctx = NULL; + was_live = 1; + } + switch (this->type) { + case t_inet: + if (this->var.v_inet.allow != NULL) { + free_ip_match_list(this->var.v_inet.allow); + this->var.v_inet.allow = NULL; + } + break; + case t_unix: + /* XXX Race condition. */ + if (was_live && + stat(this->var.v_unix.un.sun_path, &sb) == 0 && + (S_ISSOCK(sb.st_mode) || S_ISFIFO(sb.st_mode))) { + /* XXX Race condition. */ + unlink(this->var.v_unix.un.sun_path); + } + break; + default: + panic("impossible type in free_control", NULL); + /* NOTREACHED */ + } + UNLINK(*list, this, link); + memput(this, sizeof *this); +} + +static void +free_controls(controls *list) { + control ctl, next; + + for (ctl = HEAD(*list); ctl != NULL; ctl = next) { + next = NEXT(ctl, link); + free_control(list, ctl); + } + INIT_LIST(*list); +} + +static int +match_control(control l, control r) { + int match = 1; + + if (l->type != r->type) + match = 0; + else + switch (l->type) { + case t_inet: + if (l->var.v_inet.in.sin_family != + r->var.v_inet.in.sin_family || + l->var.v_inet.in.sin_port != + r->var.v_inet.in.sin_port || + l->var.v_inet.in.sin_addr.s_addr != + r->var.v_inet.in.sin_addr.s_addr) + match = 0; + break; + case t_unix: + if (l->var.v_unix.un.sun_family != + r->var.v_unix.un.sun_family || + strcmp(l->var.v_unix.un.sun_path, + r->var.v_unix.un.sun_path) != 0) + match = 0; + break; + default: + panic("impossible type in match_control", NULL); + /* NOTREACHED */ + } + ns_debug(ns_log_config, 20, "match_control(): %d", match); + return (match); +} + +static control +find_control(controls list, control new) { + control ctl; + + for (ctl = HEAD(list); ctl != NULL; ctl = NEXT(ctl, link)) + if (match_control(ctl, new)) + return (ctl); + return (NULL); +} + +static void +propagate_changes(const control diff, control base) { + int need_install = 0; + + switch (base->type) { + case t_inet: + if (base->var.v_inet.allow != NULL) + free_ip_match_list(base->var.v_inet.allow); + base->var.v_inet.allow = diff->var.v_inet.allow; + diff->var.v_inet.allow = NULL; + need_install++; + break; + case t_unix: + if (base->var.v_unix.mode != diff->var.v_unix.mode) { + base->var.v_unix.mode = diff->var.v_unix.mode; + need_install++; + } + if (base->var.v_unix.owner != diff->var.v_unix.owner) { + base->var.v_unix.owner = diff->var.v_unix.owner; + need_install++; + } + if (base->var.v_unix.group != diff->var.v_unix.group) { + base->var.v_unix.group = diff->var.v_unix.group; + need_install++; + } + break; + default: + panic("impossible type in ns_ctl::propagate_changes", NULL); + /* NOTREACHED */ + } + if (need_install) + install(base); +} + +static void +install(control ctl) { + switch (ctl->type) { + case t_inet: + install_inet(ctl); + break; + case t_unix: + install_unix(ctl); + break; + default: + panic("impossible type in ns_ctl::install", NULL); + /* NOTREACHED */ + } +} + +static void +install_inet(control ctl) { + if (ctl->sctx == NULL) { + ctl->sctx = mksrvr(ctl, + (struct sockaddr *)&ctl->var.v_inet.in, + sizeof ctl->var.v_inet.in); + } +} + +/* + * Unattach an old unix domain socket if it exists. + */ +static void +unattach(control ctl) { + int s; + struct stat sb; + + s = socket(AF_UNIX, SOCK_STREAM, 0); + if (s < 0) { + ns_warning(ns_log_config, + "unix control \"%s\" socket failed: %s", + ctl->var.v_unix.un.sun_path, + strerror(errno)); + return; + } + + if (stat(ctl->var.v_unix.un.sun_path, &sb) < 0) { + switch (errno) { + case ENOENT: /* We exited cleanly last time */ + break; + default: + ns_warning(ns_log_config, + "unix control \"%s\" stat failed: %s", + ctl->var.v_unix.un.sun_path, + strerror(errno)); + break; + } + goto cleanup; + } + + if (!(S_ISSOCK(sb.st_mode) || S_ISFIFO(sb.st_mode))) { + ns_warning(ns_log_config, "unix control \"%s\" not socket", + ctl->var.v_unix.un.sun_path); + goto cleanup; + } + + if (connect(s, (struct sockaddr *)&ctl->var.v_unix.un, + sizeof ctl->var.v_unix.un) < 0) { + switch (errno) { + case ECONNREFUSED: + case ECONNRESET: + if (unlink(ctl->var.v_unix.un.sun_path) < 0) + ns_warning(ns_log_config, + "unix control \"%s\" unlink failed: %s", + ctl->var.v_unix.un.sun_path, + strerror(errno)); + break; + default: + ns_warning(ns_log_config, + "unix control \"%s\" connect failed: %s", + ctl->var.v_unix.un.sun_path, + strerror(errno)); + break; + } + } + cleanup: + close(s); +} + +static void +install_unix(control ctl) { + if (ctl->sctx == NULL) { + unattach(ctl); + ctl->sctx = mksrvr(ctl, + (struct sockaddr *)&ctl->var.v_unix.un, + sizeof ctl->var.v_unix.un); + } + if (ctl->sctx != NULL) { + /* XXX Race condition. */ + if (chmod(ctl->var.v_unix.un.sun_path, + ctl->var.v_unix.mode) < 0) { + ns_warning(ns_log_config, "chmod(\"%s\", 0%03o): %s", + ctl->var.v_unix.un.sun_path, + ctl->var.v_unix.mode, + strerror(errno)); + } + if (chown(ctl->var.v_unix.un.sun_path, + ctl->var.v_unix.owner, + ctl->var.v_unix.group) < 0) { + ns_warning(ns_log_config, "chown(\"%s\", %d, %d): %s", + ctl->var.v_unix.un.sun_path, + ctl->var.v_unix.owner, + ctl->var.v_unix.group, + strerror(errno)); + } + } +} + +static void +logger(enum ctl_severity ctlsev, const char *format, ...) { + va_list args; + int logsev; + + switch (ctlsev) { + case ctl_debug: logsev = log_debug(5); break; + case ctl_warning: logsev = log_warning; break; + case ctl_error: logsev = log_error; break; + default: panic("invalid ctlsev in logger", NULL); + } + if (!log_ctx_valid) + return; + va_start(args, format); + log_vwrite(log_ctx, ns_log_control, logsev, format, args); + va_end(args); +} + +static void +verb_connect(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + const struct sockaddr *sa = (struct sockaddr *)respctx; + control nsctl = (control)uctx; + + if (sa->sa_family == AF_INET) { + const struct sockaddr_in *in = (struct sockaddr_in *)sa; + const ip_match_list acl = nsctl->var.v_inet.allow; + + if (!ip_address_allowed(acl, in->sin_addr)) { + ctl_response(sess, 502, "Permission denied.", + CTL_EXIT, NULL, NULL, NULL, NULL, 0); + return; + } + } + ctl_response(sess, 220, server_options->version, 0, NULL, NULL, NULL, + NULL, 0); +} + +static void +verb_getpid(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + char *msg = memget(MAX_STR_LEN); + + if (msg == NULL) { + ctl_response(sess, 503, "(out of memory)", 0, + NULL, NULL, NULL, NULL, 0); + return; + } + sprintf(msg, "my pid is <%ld>", (long)getpid()); + ctl_response(sess, 250, msg, 0, NULL, getpid_closure, msg, NULL, 0); +} + +static void +getpid_closure(struct ctl_sctx *sctx, struct ctl_sess *sess, void *uap) { + char *msg = uap; + + memput(msg, MAX_STR_LEN); +} + +enum state { + e_version = 0, + e_nzones, + e_debug, + e_xfersrun, + e_xfersdfr, + e_qserials, + e_qrylog, + e_priming, + e_loading, + e_finito +}; + +struct pvt_status { + enum state state; + char text[MAX_STR_LEN]; +}; + +static void +verb_status(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct pvt_status *pvt = ctl_getcsctx(sess); + + if (pvt == NULL) { + pvt = memget(sizeof *pvt); + if (pvt == NULL) { + ctl_response(sess, 505, "(out of memory)", + 0, NULL, NULL, NULL, NULL, 0); + return; + } + pvt->state = e_version; + (void)ctl_setcsctx(sess, pvt); + } + switch (pvt->state++) { + case e_version: + strncpy(pvt->text, Version, sizeof pvt->text); + pvt->text[sizeof pvt->text - 1] = '\0'; + break; + case e_nzones: + sprintf(pvt->text, "number of zones allocated: %d", nzones); + break; + case e_debug: + sprintf(pvt->text, "debug level: %d", debug); + break; + case e_xfersrun: + sprintf(pvt->text, "xfers running: %d", xfers_running); + break; + case e_xfersdfr: + sprintf(pvt->text, "xfers deferred: %d", xfers_deferred); + break; + case e_qserials: + sprintf(pvt->text, "soa queries in progress: %d", + qserials_running); + break; + case e_qrylog: + sprintf(pvt->text, "query logging is %s", + qrylog ? "ON" : "OFF"); + break; + case e_priming: + sprintf(pvt->text, "server is %s priming", + priming ? "STILL" : "DONE"); + break; + case e_loading: + sprintf(pvt->text, "server %s loading its configuration", + loading ? "IS" : "IS NOT"); + break; + case e_finito: + return; + } + ctl_response(sess, 250, pvt->text, + (pvt->state == e_finito) ? 0 : CTL_MORE, + NULL, status_closure, NULL, NULL, 0); +} + +static void +status_closure(struct ctl_sctx *sctx, struct ctl_sess *sess, void *uap) { + struct pvt_status *pvt = ctl_getcsctx(sess); + + memput(pvt, sizeof *pvt); + ctl_setcsctx(sess, NULL); +} + +static void +verb_stop(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + ns_need(main_need_exit); + ctl_response(sess, 250, "Shutdown initiated.", 0, NULL, NULL, NULL, + NULL, 0); +} + +static void +verb_exec(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + struct stat sb; + + if (rest != NULL && *rest != '\0') { + if (stat(rest, &sb) < 0) { + ctl_response(sess, 503, strerror(errno), + 0, NULL, NULL, NULL, NULL, 0); + return; + } + saved_argv[0] = savestr(rest, 1); /* Never strfreed. */ + } + + if (stat(saved_argv[0], &sb) < 0) { + const char *save = strerror(errno); + + ns_warning(ns_log_default, "can't exec, %s: %s", + saved_argv[0], save); + ctl_response(sess, 502, save, 0, NULL, NULL, NULL, + NULL, 0); + } else { + ns_need(main_need_restart); + ctl_response(sess, 250, "Restart initiated.", 0, NULL, + NULL, NULL, NULL, 0); + } +} + +static void +verb_reload(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + static const char spaces[] = " \t"; + struct zoneinfo *zp; + char *tmp = NULL, *x; + const char *msg; + int class, code, success; + + /* If there are no args, this is a classic reload of the config. */ + if (rest == NULL || *rest == '\0') { + ns_need(main_need_reload); + code = 250; + msg = "Reload initiated."; + goto respond; + } + + /* Look for optional zclass argument. Default is "in". */ + tmp = savestr(rest, 1); + x = tmp + strcspn(tmp, spaces); + if (*x != '\0') { + *x++ = '\0'; + x += strspn(x, spaces); + } + if (x == NULL || *x == '\0') + x = "in"; + class = sym_ston(__p_class_syms, x, &success); + if (!success) { + code = 507; + msg = "unrecognized class"; + goto respond; + } + + /* Look for the zone, and do the right thing to it. */ + zp = find_zone(tmp, class); + if (zp == NULL) { + code = 506; + msg = "Zone not found."; + goto respond; + } + switch (zp->z_type) { + case z_master: + ns_stopxfrs(zp); + /*FALLTHROUGH*/ + case z_hint: + block_signals(); + code = 251; + msg = deferred_reload_unsafe(zp); + unblock_signals(); + break; + case z_slave: + case z_stub: + ns_stopxfrs(zp); + addxfer(zp); + code = 251; + msg = "Slave transfer queued."; + goto respond; + case z_forward: + case z_cache: + default: + msg = "Non reloadable zone."; + code = 507; + break; + } + + respond: + ctl_response(sess, code, msg, 0, NULL, NULL, NULL, NULL, 0); + if (tmp != NULL) + freestr(tmp); +} + +static void +verb_reconfig(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + ns_need(main_need_reconfig); + ctl_response(sess, 250, "Reconfig initiated.", + 0, NULL, NULL, NULL, NULL, 0); +} + +static void +verb_dumpdb(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + ns_need(main_need_dump); + ctl_response(sess, 250, "Database dump initiated.", 0, NULL, + NULL, NULL, NULL, 0); +} + +static void +verb_stats(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + ns_need(main_need_statsdump); + ctl_response(sess, 250, "Statistics dump initiated.", + 0, NULL, NULL, NULL, NULL, 0); +} + +static void +verb_trace(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + int i = atoi(rest); + char *msg = memget(MAX_STR_LEN); + + if (msg == NULL) { + ctl_response(sess, 503, "(out of memory)", 0, + NULL, NULL, NULL, NULL, 0); + return; + } + if (i > 0) + desired_debug = i; + else + desired_debug++; + ns_need(main_need_debug); + sprintf(msg, "Debug level: %d", desired_debug); + ctl_response(sess, 250, msg, 0, NULL, trace_closure, msg, NULL, 0); +} + +static void +trace_closure(struct ctl_sctx *sctx, struct ctl_sess *sess, void *uap) { + char *msg = uap; + + memput(msg, MAX_STR_LEN); +} + +static void +verb_notrace(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + desired_debug = 0; + ns_need(main_need_debug); + ctl_response(sess, 250, "Debugging turned off.", + 0, NULL, NULL, NULL, NULL, 0); +} + +static void +verb_querylog(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + static const char on[] = "Query logging is now on.", + off[] = "Query logging is now off."; + + toggle_qrylog(); + ctl_response(sess, 250, qrylog ? on : off, + 0, NULL, NULL, NULL, NULL, 0); +} + +static void +verb_help(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + ctl_sendhelp(sess, 214); +} + +static void +verb_quit(struct ctl_sctx *ctl, struct ctl_sess *sess, + const struct ctl_verb *verb, const char *rest, + u_int respflags, void *respctx, void *uctx) +{ + ctl_response(sess, 221, "End of control session.", CTL_EXIT, NULL, + NULL, NULL, NULL, 0); +} diff --git a/contrib/bind/bin/named/ns_defs.h b/contrib/bind/bin/named/ns_defs.h index 8d4bba7..801e5a9 100644 --- a/contrib/bind/bin/named/ns_defs.h +++ b/contrib/bind/bin/named/ns_defs.h @@ -1,6 +1,6 @@ /* * from ns.h 4.33 (Berkeley) 8/23/90 - * $Id: ns_defs.h,v 8.39 1998/04/14 00:35:09 halley Exp $ + * $Id: ns_defs.h,v 8.89 1999/10/07 08:24:08 vixie Exp $ */ /* @@ -36,7 +36,8 @@ * SUCH DAMAGE. */ -/* Portions Copyright (c) 1993 by Digital Equipment Corporation. +/* + * 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 @@ -56,7 +57,7 @@ */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -73,6 +74,26 @@ */ /* + * Portions Copyright (c) 1999 by Check Point Software Technologies, 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, and that + * the name of Check Point Software Technologies Incorporated 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 CHECK POINT SOFTWARE TECHNOLOGIES + * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED + * 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. + */ + +/* * Global definitions for the name server. */ @@ -92,6 +113,7 @@ * dies out in a little more than a minute. * (sequence RETRYBASE, 2*RETRYBASE, 4*RETRYBASE... for MAXRETRY) */ +#define NEWZONES 64 /* must be a power of two. */ #define MINROOTS 2 /* min number of root hints */ #define NSMAX 16 /* max number of NS addrs to try ([0..255]) */ #define RETRYBASE 4 /* base time between retries */ @@ -107,6 +129,11 @@ /* every MIN_REFRESH seconds */ #define MIN_RETRY 1 /* never retry more frequently than once */ /* every MIN_RETRY seconds */ +#define MAX_REFRESH 2419200 /* perform a refresh query at least */ + /* every 4 weeks*/ +#define MAX_RETRY 1209600 /* perform a retry after no more than 2 weeks */ +#define MAX_EXPIRE 31536000 /* expire a zone if we have not talked to */ + /* the primary in 1 year */ #define NADDRECS 20 /* max addt'l rr's per resp */ #define XFER_TIMER 120 /* named-xfer's connect timeout */ @@ -117,35 +144,53 @@ #define DEFAULT_XFERS_PER_NS 2 /* default # of xfers per peer nameserver */ #define XFER_BUFSIZE (16*1024) /* arbitrary but bigger than most MTU's */ + /* maximum time to cache negative answers */ +#define DEFAULT_MAX_NCACHE_TTL (3*60*60) + #define ALPHA 0.7 /* How much to preserve of old response time */ #define BETA 1.2 /* How much to penalize response time on failure */ #define GAMMA 0.98 /* How much to decay unused response times */ /* What maintainance operations need to be performed sometime soon? */ -#define MAIN_NEED_RELOAD 0x0001 /* db_reload() needed. */ -#define MAIN_NEED_MAINT 0x0002 /* ns_maint() needed. */ -#define MAIN_NEED_ENDXFER 0x0004 /* endxfer() needed. */ -#define MAIN_NEED_ZONELOAD 0x0008 /* loadxfer() needed. */ -#define MAIN_NEED_DUMP 0x0010 /* doadump() needed. */ -#define MAIN_NEED_STATSDUMP 0x0020 /* ns_stats() needed. */ -#define MAIN_NEED_EXIT 0x0040 /* exit() needed. */ -#define MAIN_NEED_QRYLOG 0x0080 /* toggle_qrylog() needed. */ -#define MAIN_NEED_DEBUG 0x0100 /* use_desired_debug() needed. */ -#define MAIN_NEED_NOTIFY 0x0200 /* do_notify_after_load() needed */ +typedef enum need { + main_need_zreload = 0, /* ns_zreload() needed. */ + main_need_reload, /* ns_reload() needed. */ + main_need_reconfig, /* ns_reconfig() needed. */ + main_need_endxfer, /* endxfer() needed. */ + main_need_zoneload, /* loadxfer() needed. */ + main_need_dump, /* doadump() needed. */ + main_need_statsdump, /* ns_stats() needed. */ + main_need_exit, /* exit() needed. */ + main_need_qrylog, /* toggle_qrylog() needed. */ + main_need_debug, /* use_desired_debug() needed. */ + main_need_restart, /* exec() needed. */ + main_need_reap, /* need to reap dead children */ + main_need_num /* number of needs, used for array bound. */ +} main_need; /* What global options are set? */ #define OPTION_NORECURSE 0x0001 /* Don't recurse even if asked. */ #define OPTION_NOFETCHGLUE 0x0002 /* Don't fetch missing glue. */ #define OPTION_FORWARD_ONLY 0x0004 /* Don't use NS RR's, just forward. */ #define OPTION_FAKE_IQUERY 0x0008 /* Fake up bogus response to IQUERY. */ +#ifdef BIND_NOTIFY #define OPTION_NONOTIFY 0x0010 /* Turn off notify */ +#endif #define OPTION_NONAUTH_NXDOMAIN 0x0020 /* Generate non-auth NXDOMAINs? */ #define OPTION_MULTIPLE_CNAMES 0x0040 /* Allow a name to have multiple * CNAME RRs */ #define OPTION_HOSTSTATS 0x0080 /* Maintain per-host statistics? */ #define OPTION_DEALLOC_ON_EXIT 0x0100 /* Deallocate everything on exit? */ +#define OPTION_USE_IXFR 0x0110 /* Use by delault ixfr in zone transfer */ +#define OPTION_MAINTAIN_IXFR_BASE 0x0120 +#define OPTION_NODIALUP 0x0200 /* Turn off dialup support */ +#define OPTION_NORFC2308_TYPE1 0x0400 /* Prevent type1 respones (RFC 2308) + * to cached negative respones */ +#define OPTION_USE_ID_POOL 0x0800 /* Use the memory hogging query ID */ +#define OPTION_TREAT_CR_AS_SPACE 0x1000 /* Treat CR in zone files as space */ -#define DEFAULT_OPTION_FLAGS 0 +#define DEFAULT_OPTION_FLAGS (OPTION_NODIALUP|OPTION_NONAUTH_NXDOMAIN|\ + OPTION_USE_ID_POOL|OPTION_NORFC2308_TYPE1) #ifdef BIND_UPDATE #define SOAINCRINTVL 300 /* default value for the time after which @@ -165,6 +210,7 @@ #define CLEAN_TIMER 0x01 #define INTERFACE_TIMER 0x02 #define STATS_TIMER 0x04 +#define HEARTBEAT_TIMER 0x08 /* IP address accessor, network byte order. */ #define ina_ulong(ina) (ina.s_addr) @@ -186,6 +232,13 @@ (panic(panic_msg_no_options, NULL), 0) : \ ((server_options->flags & option) != 0)) +#define NS_ZOPTION_P(zp, option) \ + (((zp) != NULL && (((zp)->z_optset & option) != 0)) ? \ + (((zp)->z_options & option) != 0) : NS_OPTION_P(option)) + +#define NS_ZFWDTAB(zp) (((zp) == NULL) ? \ + server_options->fwdtab : (zp)->z_fwdtab) + #define NS_INCRSTAT(addr, which) \ do { \ if ((int)which >= (int)nssLast) \ @@ -204,7 +257,11 @@ enum severity { ignore, warn, fail, not_set }; +#ifdef BIND_NOTIFY enum znotify { znotify_use_default=0, znotify_yes, znotify_no }; +#endif + +enum zdialup { zdialup_use_default=0, zdialup_yes, zdialup_no }; enum axfr_format { axfr_use_default=0, axfr_one_answer, axfr_many_answers }; @@ -217,8 +274,12 @@ struct ip_match_indirect { struct ip_match_list *list; }; +struct ip_match_key { + struct dst_key *key; +}; + typedef enum { ip_match_pattern, ip_match_indirect, ip_match_localhost, - ip_match_localnets } ip_match_type; + ip_match_localnets, ip_match_key } ip_match_type; typedef struct ip_match_element { ip_match_type type; @@ -226,6 +287,7 @@ typedef struct ip_match_element { union { struct ip_match_direct direct; struct ip_match_indirect indirect; + struct ip_match_key key; } u; struct ip_match_element *next; } *ip_match_element; @@ -259,12 +321,15 @@ struct zoneinfo { char *z_source; /* source location of data */ time_t z_ftime; /* modification time of source file */ struct in_addr z_axfr_src; /* bind() the axfr socket to this */ - struct in_addr z_xaddr; /* override server for next xfer */ struct in_addr z_addr[NSMAX]; /* list of master servers for zone */ u_char z_addrcnt; /* number of entries in z_addr[] */ + struct in_addr z_xaddr[NSMAX]; /* list of master servers for xfer */ + u_char z_xaddrcnt; /* number of entries in z_xaddr[] */ u_char z_type; /* type of zone; see below */ - u_int16_t z_flags; /* state bits; see below */ + u_int32_t z_flags; /* state bits; see below */ pid_t z_xferpid; /* xfer child pid */ + u_int z_options; /* options set specific to this zone */ + u_int z_optset; /* which opts override global opts */ int z_class; /* class of zone */ int z_numxfrs; /* Ref count of concurrent xfrs. */ enum severity z_checknames; /* How to handle non-RFC-compliant names */ @@ -286,60 +351,87 @@ struct zoneinfo { ip_match_list z_transfer_acl; /* sites that may get a zone transfer from us */ long z_max_transfer_time_in; /* max num seconds for AXFR */ +#ifdef BIND_NOTIFY enum znotify z_notify; /* Notify mode */ - struct in_addr z_also_notify[NSMAX]; /* More nameservers to notify */ + struct in_addr *z_also_notify; /* More nameservers to notify */ int z_notify_count; +#endif + enum zdialup z_dialup; /* secondaries over a dialup link */ + char *z_ixfr_base; /* where to find the history of the zone */ + char *z_ixfr_tmp; /* tmp file for the ixfr */ + int z_maintain_ixfr_base; + int z_log_size_ixfr; + int z_max_log_size_ixfr; evTimerID z_timer; /* maintenance timer */ ztimer_info z_timerinfo; /* UAP associated with timer */ time_t z_nextmaint; /* time of next maintenance */ + u_int16_t z_port; /* perform AXFR to this port */ + struct fwdinfo *z_fwdtab; /* zone-specific forwarders */ + LINK(struct zoneinfo) z_freelink; /* if it's on the free list. */ + LINK(struct zoneinfo) z_reloadlink; /* if it's on the reload list. */ }; /* zone types (z_type) */ -enum zonetype { z_nil, z_master, z_slave, z_hint, z_stub, z_any }; +enum zonetype { z_nil, z_master, z_slave, z_hint, z_stub, z_forward, + z_cache, z_any }; #define Z_NIL z_nil /* XXX */ #define Z_MASTER z_master /* XXX */ #define Z_PRIMARY z_master /* XXX */ #define Z_SLAVE z_slave /* XXX */ #define Z_SECONDARY z_slave /* XXX */ #define Z_HINT z_hint /* XXX */ -#define Z_CACHE z_hint /* XXX */ +#define Z_CACHE z_cache /* XXX */ #define Z_STUB z_stub /* XXX */ +#define Z_FORWARD z_forward /* XXX */ #define Z_ANY z_any /* XXX*2 */ - /* zone state bits (16 bits) */ -#define Z_AUTH 0x0001 /* zone is authoritative */ -#define Z_NEED_XFER 0x0002 /* waiting to do xfer */ -#define Z_XFER_RUNNING 0x0004 /* asynch. xfer is running */ -#define Z_NEED_RELOAD 0x0008 /* waiting to do reload */ -#define Z_SYSLOGGED 0x0010 /* have logged timeout */ -#define Z_QSERIAL 0x0020 /* sysquery()'ing for serial number */ -#define Z_FOUND 0x0040 /* found in boot file when reloading */ -#define Z_INCLUDE 0x0080 /* set if include used in file */ -#define Z_DB_BAD 0x0100 /* errors when loading file */ -#define Z_TMP_FILE 0x0200 /* backup file for xfer is temporary */ + /* zone state bits (32 bits) */ +#define Z_AUTH 0x00000001 /* zone is authoritative */ +#define Z_NEED_XFER 0x00000002 /* waiting to do xfer */ +#define Z_XFER_RUNNING 0x00000004 /* asynch. xfer is running */ +#define Z_NEED_RELOAD 0x00000008 /* waiting to do reload */ +#define Z_SYSLOGGED 0x00000010 /* have logged timeout */ +#define Z_QSERIAL 0x00000020 /* sysquery()'ing for serial number */ +#define Z_FOUND 0x00000040 /* found in boot file when reloading */ +#define Z_INCLUDE 0x00000080 /* set if include used in file */ +#define Z_DB_BAD 0x00000100 /* errors when loading file */ +#define Z_TMP_FILE 0x00000200 /* backup file for xfer is temporary */ #ifdef BIND_UPDATE -#define Z_DYNAMIC 0x0400 /* allow dynamic updates */ -#define Z_NEED_DUMP 0x0800 /* zone has changed, needs a dump */ -#define Z_NEED_SOAUPDATE 0x1000 /* soa serial number needs increment */ +#define Z_DYNAMIC 0x00000400 /* allow dynamic updates */ +#define Z_NEED_DUMP 0x00000800 /* zone has changed, needs a dump */ +#define Z_NEED_SOAUPDATE 0x00001000 /* soa serial number needs increment */ #endif /* BIND_UPDATE */ -#define Z_XFER_ABORTED 0x2000 /* zone transfer has been aborted */ -#define Z_XFER_GONE 0x4000 /* zone transfer process is gone */ -#define Z_TIMER_SET 0x8000 /* z_timer contains a valid id */ +#define Z_XFER_ABORTED 0x00002000 /* zone transfer has been aborted */ +#define Z_XFER_GONE 0x00004000 /* zone transfer process is gone */ +#define Z_TIMER_SET 0x00008000 /* z_timer contains a valid id */ +#ifdef BIND_NOTIFY +#define Z_NOTIFY 0x00010000 /* has an outbound notify executing */ +#endif +#define Z_NEED_QSERIAL 0x00020000 /* we need to re-call qserial() */ +#define Z_PARENT_RELOAD 0x00040000 /* we need to reload this as parent */ +#define Z_FORWARD_SET 0x00080000 /* has forwarders been set */ /* named_xfer exit codes */ #define XFER_UPTODATE 0 /* zone is up-to-date */ #define XFER_SUCCESS 1 /* performed transfer successfully */ #define XFER_TIMEOUT 2 /* no server reachable/xfer timeout */ #define XFER_FAIL 3 /* other failure, has been logged */ +#define XFER_SUCCESSAXFR 4 /* named-xfr recived a xfr */ +#define XFER_SUCCESSIXFR 5 /* named-xfr recived a ixfr */ +#define XFER_SUCCESSAXFRIXFRFILE 6 /* named-xfr received AXFR for IXFR */ +#define XFER_ISAXFR -1 /* the last XFR is AXFR */ +#define XFER_ISIXFR -2 /* the last XFR is IXFR */ +#define XFER_ISAXFRIXFR -3 /* the last XFR is AXFR but we must create IXFR base */ -/* XXX - "struct qserv" is deprecated in favor of "struct nameser" */ struct qserv { struct sockaddr_in ns_addr; /* address of NS */ struct databuf *ns; /* databuf for NS record */ struct databuf *nsdata; /* databuf for server address */ struct timeval stime; /* time first query started */ - int nretry; /* # of times addr retried */ + unsigned int forwarder:1; /* this entry is for a forwarder */ + unsigned int nretry:31; /* # of times addr retried */ + u_int32_t serial; /* valid if Q_ZSERIAL */ }; /* @@ -357,7 +449,6 @@ struct qinfo { q_cmsglen, /* len of cname message */ q_cmsgsize; /* allocated size of cname message */ int16_t q_dfd; /* UDP file descriptor */ - struct fwdinfo *q_fwd; /* last forwarder used */ time_t q_time; /* time to retry */ time_t q_expire; /* time to expire */ struct qinfo *q_next; /* rexmit list (sorted by time) */ @@ -375,15 +466,18 @@ struct qinfo { int16_t q_nqueries; /* # of queries required */ struct qstream *q_stream; /* TCP stream, null if UDP */ struct zoneinfo *q_zquery; /* Zone query is about (Q_ZSERIAL) */ + struct zoneinfo *q_fzone; /* Forwarding zone, if any */ char *q_domain; /* domain of most enclosing zone cut */ char *q_name; /* domain of query */ u_int16_t q_class; /* class of query */ u_int16_t q_type; /* type of query */ #ifdef BIND_NOTIFY - int q_notifyzone; /* zone which needs a sysnotify() + int q_notifyzone; /* zone which needs another znotify() * when the reply to this comes in. */ #endif + struct tsig_record *q_tsig; /* forwarded query's TSIG record */ + struct tsig_record *q_nstsig; /* forwarded query's TSIG record */ }; /* q_flags bits (8 bits) */ @@ -392,9 +486,7 @@ struct qinfo { #define Q_ZSERIAL 0x04 /* getting zone serial for xfer test */ #define Q_USEVC 0x08 /* forward using tcp not udp */ -#define Q_NEXTADDR(qp,n) \ - (((qp)->q_fwd == (struct fwdinfo *)0) ? \ - &(qp)->q_addr[n].ns_addr : &(qp)->q_fwd->fwdaddr) +#define Q_NEXTADDR(qp,n) (&(qp)->q_addr[n].ns_addr) #define RETRY_TIMEOUT 45 @@ -464,17 +556,27 @@ struct qstream { u_int flags; /* see below */ struct qstream_xfr { enum { s_x_base, s_x_firstsoa, s_x_zone, - s_x_lastsoa, s_x_done } + s_x_lastsoa, s_x_done, s_x_adding, + s_x_deleting, s_x_addsoa, s_x_deletesoa } state; /* state of transfer. */ u_char *msg, /* current assembly message. */ *cp, /* where are we in msg? */ *eom, /* end of msg. */ *ptrs[128]; /* ptrs for dn_comp(). */ int class, /* class of an XFR. */ + type, /* type of XFR. */ id, /* id of an XFR. */ opcode; /* opcode of an XFR. */ u_int zone; /* zone being XFR'd. */ - struct namebuf *top; /* top np of an XFR. */ + union { + struct namebuf *axfr; /* top np of an AXFR. */ + struct ns_updrec *ixfr; /* top udp of an IXFR. */ + } top; + int ixfr_zone; + u_int32_t serial; /* serial number requested in IXFR */ + ns_tcp_tsig_state *tsig_state; /* used by ns_sign_tcp */ + int tsig_skip; /* skip calling ns_sign_tcp + * during the next flush */ struct qs_x_lev { /* decompose the recursion. */ enum {sxl_ns, sxl_all, sxl_sub} state; /* what's this level doing? */ @@ -500,6 +602,7 @@ struct qstream { #define STREAM_CONNECT_EV 0x08 #define STREAM_DONE_CLOSE 0x10 #define STREAM_AXFR 0x20 +#define STREAM_AXFRIXFR 0x22 #define ALLOW_NETS 0x0001 #define ALLOW_HOSTS 0x0002 @@ -549,7 +652,8 @@ struct nameser { u_int8_t xfers; /* #/xfers running right now */ }; -enum transport { primary_trans, secondary_trans, response_trans, num_trans }; +enum transport { primary_trans, secondary_trans, response_trans, update_trans, + num_trans }; /* types used by the parser or config routines */ @@ -573,8 +677,31 @@ typedef struct listen_info_list { #endif typedef RLIMIT_TYPE rlimit_type; +struct control; +typedef struct control *control; +typedef LIST(struct control) controls; + +enum ordering { unknown_order, fixed_order, cyclic_order, random_order }; + +#define DEFAULT_ORDERING cyclic_order + +typedef struct rrset_order_element { + int class; + int type; + char *name; + enum ordering order; + struct rrset_order_element *next; +} *rrset_order_element ; + +typedef struct rrset_order_list { + rrset_order_element first; + rrset_order_element last; +} *rrset_order_list; + + typedef struct options { u_int flags; + char *version; char *directory; char *dump_filename; char *pid_filename; @@ -584,12 +711,22 @@ typedef struct options { int transfers_in; int transfers_per_ns; int transfers_out; + int serial_queries; + int max_log_size_ixfr; enum axfr_format transfer_format; long max_transfer_time_in; struct sockaddr_in query_source; + struct in_addr axfr_src; +#ifdef BIND_NOTIFY + int notify_count; + struct in_addr *also_notify; +#endif ip_match_list query_acl; + ip_match_list recursion_acl; ip_match_list transfer_acl; + ip_match_list blackhole_acl; ip_match_list topology; + ip_match_list sortlist; enum severity check_names[num_trans]; u_long data_size; u_long stack_size; @@ -601,16 +738,15 @@ typedef struct options { int clean_interval; int interface_interval; int stats_interval; + rrset_order_list ordering; + int heartbeat_interval; + u_int max_ncache_ttl; + u_int lame_ttl; + int minroots; } *options; -typedef struct key_info { - char *name; - char *algorithm; - char *secret; /* XXX should be u_char? */ -} *key_info; - typedef struct key_list_element { - key_info info; + struct dst_key *key; struct key_list_element *next; } *key_list_element; @@ -647,6 +783,7 @@ typedef struct server_config { } server_config; #define SERVER_INFO_BOGUS 0x01 +#define SERVER_INFO_SUPPORT_IXFR 0x02 typedef struct server_info { struct in_addr address; @@ -686,7 +823,9 @@ typedef enum ns_logging_categories { ns_log_db, ns_log_eventlib, ns_log_packet, +#ifdef BIND_NOTIFY ns_log_notify, +#endif ns_log_cname, ns_log_security, ns_log_os, @@ -694,6 +833,7 @@ typedef enum ns_logging_categories { ns_log_maint, ns_log_load, ns_log_resp_checks, + ns_log_control, ns_log_max_category } ns_logging_categories; @@ -709,9 +849,9 @@ struct map { int val; }; -#define NOERROR_NODATA 6 /* only used internally by the server, used for - * -ve $ing non-existence of records. 6 is not - * a code used as yet anyway. anant@isi.edu +#define NOERROR_NODATA 15 /* only used internally by the server, used for + * -ve $ing non-existence of records. 15 is not + * a code used as yet anyway. */ #define NTTL 600 /* ttl for negative data: 10 minutes? */ @@ -722,24 +862,6 @@ struct map { enum req_action { Finish, Refuse, Return }; #endif -#ifdef BIND_NOTIFY -typedef enum { - notify_info_waitfor, notify_info_delay, notify_info_error, - notify_info_done -} notify_info_state; - -typedef struct notify_info { - char *name; - int class; - notify_info_state state; - evWaitID wait_id; - evTimerID timer_id; - LINK(struct notify_info) link; -} *notify_info; - -typedef LIST(struct notify_info) notify_info_list; -#endif /* BIND_NOTIFY */ - #ifdef INIT error "INIT already defined, check system include files" #endif diff --git a/contrib/bind/bin/named/ns_forw.c b/contrib/bind/bin/named/ns_forw.c index 9c72825..3a4e488 100644 --- a/contrib/bind/bin/named/ns_forw.c +++ b/contrib/bind/bin/named/ns_forw.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)ns_forw.c 4.32 (Berkeley) 3/3/91"; -static char rcsid[] = "$Id: ns_forw.c,v 8.34 1998/02/24 01:02:40 halley Exp $"; +static const char sccsid[] = "@(#)ns_forw.c 4.32 (Berkeley) 3/3/91"; +static const char rcsid[] = "$Id: ns_forw.c,v 8.68 1999/10/13 16:39:07 vixie Exp $"; #endif /* not lint */ /* @@ -57,7 +57,7 @@ static char rcsid[] = "$Id: ns_forw.c,v 8.34 1998/02/24 01:02:40 halley Exp $"; */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -78,6 +78,7 @@ static char rcsid[] = "$Id: ns_forw.c,v 8.34 1998/02/24 01:02:40 halley Exp $"; #include <sys/types.h> #include <sys/param.h> #include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/inet.h> @@ -95,6 +96,8 @@ static char rcsid[] = "$Id: ns_forw.c,v 8.34 1998/02/24 01:02:40 halley Exp $"; #include <isc/logging.h> #include <isc/memcluster.h> +#include <isc/dst.h> + #include "port_after.h" #include "named.h" @@ -122,14 +125,20 @@ int ns_forw(struct databuf *nsp[], u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp, int dfd, struct qinfo **qpp, const char *dname, int class, int type, - struct namebuf *np, int use_tcp) + struct namebuf *np, int use_tcp, struct tsig_record *in_tsig) { struct qinfo *qp; char tmpdomain[MAXDNAME]; struct sockaddr_in *nsa; HEADER *hp; u_int16_t id; - int n; + int sendto_errno = 0; + int n, has_tsig, oldqlen; + u_char *oldqbuf; + u_char *smsg; + int smsglen, smsgsize, siglen; + u_char sig[TSIG_SIG_SIZE]; + DST_KEY *key; ns_debug(ns_log_default, 3, "ns_forw()"); @@ -155,23 +164,32 @@ ns_forw(struct databuf *nsp[], u_char *msg, int msglen, getname(np, tmpdomain, sizeof tmpdomain); qp->q_domain = savestr(tmpdomain, 1); qp->q_from = from; /* nslookup wants to know this */ - n = nslookup(nsp, qp, dname, "ns_forw"); + if (NS_ZFWDTAB(qp->q_fzone)) + nsfwdadd(qp, NS_ZFWDTAB(qp->q_fzone)); + if (NS_ZOPTION_P(qp->q_fzone, OPTION_FORWARD_ONLY)) + n = 0; + else + n = nslookup(nsp, qp, dname, "ns_forw"); if (n < 0) { - ns_debug(ns_log_default, 2, "forw: nslookup reports danger"); + if (n == -1) + ns_debug(ns_log_default, 2, + "forw: nslookup reports danger"); ns_freeqry(qp); return (FW_SERVFAIL); } - if (n == 0 && !server_options->fwdtab) { + if (n == 0 && !NS_ZFWDTAB(qp->q_fzone)) { ns_debug(ns_log_default, 2, "forw: no nameservers found"); ns_freeqry(qp); return (FW_NOSERVER); } qp->q_stream = qsp; qp->q_curaddr = 0; - qp->q_fwd = server_options->fwdtab; qp->q_dfd = dfd; qp->q_id = id; qp->q_expire = tt.tv_sec + RETRY_TIMEOUT*2; + if (in_tsig != NULL) + qp->q_tsig = new_tsig(in_tsig->key, in_tsig->sig, + in_tsig->siglen); if (use_tcp) qp->q_flags |= Q_USEVC; hp->id = qp->q_nsid = htons(nsid_next()); @@ -186,17 +204,16 @@ ns_forw(struct databuf *nsp[], u_char *msg, int msglen, } qp->q_msgsize = msglen; memcpy(qp->q_msg, msg, qp->q_msglen = msglen); - if (!qp->q_fwd) { - hp->rd = 0; - qp->q_addr[0].stime = tt; - } + hp = (HEADER *) qp->q_msg; + hp->rd = (qp->q_addr[0].forwarder ? 1 : 0); + qp->q_addr[0].stime = tt; #ifdef SLAVE_FORWARD - if (NS_OPTION_P(OPTION_FORWARD_ONLY)) + if (NS_ZOPTION_P(qp->q_fzone, OPTION_FORWARD_ONLY)) schedretry(qp, (time_t)slave_retry); else #endif /* SLAVE_FORWARD */ - schedretry(qp, qp->q_fwd ?(2*RETRYBASE) :retrytime(qp)); + schedretry(qp, retrytime(qp)); nsa = Q_NEXTADDR(qp, 0); ns_debug(ns_log_default, 1, @@ -208,10 +225,44 @@ ns_forw(struct databuf *nsp[], u_char *msg, int msglen, ? qp->q_addr[0].nsdata->d_nstime : -1, (int)(qp->q_time - tt.tv_sec)); + #ifdef DEBUG if (debug >= 10) - fp_nquery(msg, msglen, log_get_stream(packet_channel)); + res_pquery(&res, msg, msglen, log_get_stream(packet_channel)); #endif + key = tsig_key_from_addr(nsa->sin_addr); + if (key != NULL) { + smsgsize = qp->q_msglen + TSIG_BUF_SIZE; + smsg = memget(smsgsize); + if (smsg == NULL) + ns_panic(ns_log_default, 1, "ns_forw: memget failed"); + smsglen = qp->q_msglen; + siglen = sizeof(sig); + memcpy(smsg, qp->q_msg, qp->q_msglen); + n = ns_sign(smsg, &smsglen, smsgsize, NOERROR, key, NULL, 0, + sig, &siglen, 0); + if (n == 0) { + oldqbuf = qp->q_msg; + oldqlen = qp->q_msglen; + qp->q_msglen = smsglen; + qp->q_msg = smsg; + hp = (HEADER *) qp->q_msg; + has_tsig = 1; + qp->q_nstsig = new_tsig(key, sig, siglen); + } + else { + has_tsig = 0; + free_tsig(qp->q_nstsig); + qp->q_nstsig = NULL; + INSIST(0); + } + } + else { + has_tsig = 0; + free_tsig(qp->q_nstsig); + qp->q_nstsig = NULL; + } + if (qp->q_flags & Q_USEVC) { if (tcp_send(qp) != NOERROR) { if (!haveComplained(ina_ulong(nsa->sin_addr), @@ -220,20 +271,37 @@ ns_forw(struct databuf *nsp[], u_char *msg, int msglen, "ns_forw: tcp_send(%s) failed: %s", sin_ntoa(*nsa), strerror(errno)); } - } else if (sendto(ds, (char *)msg, msglen, 0, (struct sockaddr *)nsa, + } else if (sendto(ds, (char *)qp->q_msg, qp->q_msglen, 0, + (struct sockaddr *)nsa, sizeof(struct sockaddr_in)) < 0) { + sendto_errno = errno; if (!haveComplained(ina_ulong(nsa->sin_addr), (u_long)sendtoStr)) ns_info(ns_log_default, "ns_forw: sendto(%s): %s", sin_ntoa(*nsa), strerror(errno)); nameserIncr(nsa->sin_addr, nssSendtoErr); } + if (has_tsig == 1) { + memput(qp->q_msg, smsgsize); + qp->q_msg = oldqbuf; + qp->q_msglen = oldqlen; + hp = (HEADER *) qp->q_msg; + } + if (NS_OPTION_P(OPTION_HOSTSTATS)) nameserIncr(from.sin_addr, nssRcvdFwdQ); nameserIncr(nsa->sin_addr, nssSentFwdQ); if (qpp) *qpp = qp; hp->rd = 1; + switch (sendto_errno) { + case ENETDOWN: + case ENETUNREACH: + case EHOSTDOWN: + case EHOSTUNREACH: + unsched(qp); + schedretry(qp, (time_t) 0); + } return (0); } @@ -313,8 +381,6 @@ nslookupComplain(const char *sysloginfo, const char *queryname, ns_debug(ns_log_default, 2, "NS '%s' %s", dname, complaint); if (sysloginfo && queryname && !haveComplained((u_long)queryname, (u_long)complaint)) { - char buf[999]; - a = ns = (char *)NULL; print_a = (a_rr->d_type == T_A); a_type = p_type(a_rr->d_type); @@ -395,13 +461,13 @@ nslookup(struct databuf *nsp[], struct qinfo *qp, struct hashbuf *tmphtp; char *dname; const char *fname; - int oldn, naddr, class, found_arr, potential_ns; + int oldn, naddr, class, found_arr, potential_ns, lame_ns; time_t curtime; ns_debug(ns_log_default, 3, "nslookup(nsp=%#x, qp=%#x, \"%s\")", nsp, qp, syslogdname); - potential_ns = 0; + lame_ns = potential_ns = 0; naddr = n = qp->q_naddr; curtime = (u_long) tt.tv_sec; while ((nsdp = *nsp++) != NULL) { @@ -421,8 +487,20 @@ nslookup(struct databuf *nsp[], struct qinfo *qp, } } + /* skip lame servers */ + if ((nsdp->d_flags & DB_F_LAME) != 0) { + time_t when; + when = db_lame_find(qp->q_domain, nsdp); + if (when != 0 && when > tt.tv_sec) { + ns_debug(ns_log_default, 3, + "skipping lame NS"); + lame_ns++; + goto skipserver; + } + } + tmphtp = ((nsdp->d_flags & DB_F_HINT) ?fcachetab :hashtab); - np = nlookup(dname, &tmphtp, &fname, 1); + np = nlookup(dname, &tmphtp, &fname, 0); if (np == NULL) { ns_debug(ns_log_default, 3, "%s: not found %s %#x", dname, fname, np); @@ -430,45 +508,14 @@ nslookup(struct databuf *nsp[], struct qinfo *qp, goto need_sysquery; } if (fname != dname) { - if (findMyZone(np, class) == DB_Z_CACHE) { - /* - * lifted from findMyZone() - * We really need to know if the NS - * is the bottom of one of our zones - * to see if we've got missing glue - */ - for (; np; np = np_parent(np)) - for (dp = np->n_data; dp; dp = dp->d_next) - if (match(dp, class, T_NS)) { - if (dp->d_rcode) - break; - if (dp->d_zone) { - static char *complaint = - "Glue A RR missing"; - nslookupComplain(sysloginfo, - syslogdname, - complaint, - dname, dp, - nsdp); - goto skipserver; - } else { - found_arr = 0; - goto need_sysquery; - } - } - /* shouldn't happen, but ... */ - found_arr = 0; - goto need_sysquery; - } else { - /* Authoritative A RR missing. */ - continue; - } + found_arr = 0; + goto need_sysquery; } found_arr = 0; oldn = n; /* look for name server addresses */ - delete_stale(np); + (void)delete_stale(np); for (dp = np->n_data; dp != NULL; dp = dp->d_next) { struct in_addr nsa; @@ -484,10 +531,7 @@ nslookup(struct databuf *nsp[], struct qinfo *qp, if (dp->d_type != T_A || dp->d_class != class) continue; if (dp->d_rcode) { - static const char *complaint = - "A RR negative cache entry"; - nslookupComplain(sysloginfo, syslogdname, - complaint, dname, dp, nsdp); + /* Negative caching element. */ goto skipserver; } if (ina_hlong(ina_get(dp->d_data)) == INADDR_ANY) { @@ -553,6 +597,7 @@ nslookup(struct databuf *nsp[], struct qinfo *qp, qs->ns_addr.sin_addr = nsa; qs->ns = nsdp; qs->nsdata = dp; + qs->forwarder = 0; qs->nretry = 0; /* * If this A RR has no RTT, initialize its RTT to a @@ -616,6 +661,10 @@ nslookup(struct databuf *nsp[], struct qinfo *qp, if (ip_match_address(bogus_nameservers, nsa) > 0) goto skipserver; #endif + if (server_options->blackhole_acl != NULL && + ip_match_address(server_options->blackhole_acl, + nsa) == 1) + continue; n++; if (n >= NSMAX) @@ -629,7 +678,7 @@ nslookup(struct databuf *nsp[], struct qinfo *qp, potential_ns++; if (!(qp->q_flags & Q_SYSTEM)) (void) sysquery(dname, class, T_A, NULL, 0, - QUERY); + ns_port, QUERY); } skipserver: (void)NULL; @@ -637,15 +686,17 @@ nslookup(struct databuf *nsp[], struct qinfo *qp, out: ns_debug(ns_log_default, 3, "nslookup: %d ns addrs total", n); qp->q_naddr = n; - if (n == 0 && potential_ns == 0 && !server_options->fwdtab) { + if (n == 0 && potential_ns == 0 && !NS_ZFWDTAB(qp->q_fzone)) { static char *complaint = "No possible A RRs"; + if (lame_ns != 0) + complaint = "All possible A RR's lame"; if (sysloginfo && syslogdname && !haveComplained((u_long)syslogdname, (u_long)complaint)) { ns_info(ns_log_default, "%s: query(%s) %s", sysloginfo, syslogdname, complaint); } - return(-1); + return ((lame_ns == 0) ? -1 : -2); } /* Update the refcounts before the sort. */ for (i = naddr; i < (u_int)n; i++) { @@ -846,14 +897,20 @@ retrytimer(evContext ctx, void *uap, struct timespec due, */ void retry(struct qinfo *qp) { - int n; + int n, has_tsig, oldqlen; HEADER *hp; struct sockaddr_in *nsa; + int sendto_errno = 0; + u_char *oldqbuf; + u_char *smsg; + int smsglen, smsgsize, siglen; + u_char sig[TSIG_SIG_SIZE]; + DST_KEY *key; ns_debug(ns_log_default, 3, "retry(%#lx) id=%d", (u_long)qp, ntohs(qp->q_id)); - if (qp->q_msg == NULL) { /* XXX - why? */ + if (qp->q_msg == NULL) { qremove(qp); return; } @@ -864,29 +921,25 @@ retry(struct qinfo *qp) { (u_long)qp, (u_long)qp->q_expire, (int)(tt.tv_sec - qp->q_expire), (u_long)tt.tv_sec); - if (qp->q_stream || (qp->q_flags & Q_PRIMING)) - goto fail; - qremove(qp); - return; + goto fail; } - /* try next address */ + /* Try next address. */ n = qp->q_curaddr; - if (qp->q_fwd != NULL) { - qp->q_fwd = qp->q_fwd->next; - if (qp->q_fwd != NULL) - goto found; - /* Out of forwarders, try direct queries. */ - } if (qp->q_naddr > 0) { ++qp->q_addr[n].nretry; - if (!NS_OPTION_P(OPTION_FORWARD_ONLY)) { - do { - if (++n >= (int)qp->q_naddr) - n = 0; - if (qp->q_addr[n].nretry < MAXRETRY) - goto found; - } while (n != qp->q_curaddr); + do { + if (++n >= (int)qp->q_naddr) + n = 0; + if ((qp->q_flags & Q_ZSERIAL) != 0 && + qp->q_addr[n].serial != 0) + continue; + if (qp->q_addr[n].nretry < MAXRETRY) + goto found; + } while (n != qp->q_curaddr); + if ((qp->q_flags & Q_ZSERIAL) != 0) { + qremove(qp); + return; } } fail: @@ -894,7 +947,7 @@ retry(struct qinfo *qp) { * Give up. Can't reach destination. */ hp = (HEADER *)(qp->q_cmsg ? qp->q_cmsg : qp->q_msg); - if (qp->q_flags & Q_PRIMING) { + if ((qp->q_flags & Q_PRIMING) != 0) { /* Can't give up priming */ if (qp->q_expire < tt.tv_sec) { /* @@ -903,7 +956,6 @@ retry(struct qinfo *qp) { */ hp->rcode = NOERROR; hp->qr = hp->aa = 0; - qp->q_fwd = server_options->fwdtab; for (n = 0; n < (int)qp->q_naddr; n++) qp->q_addr[n].nretry = 0; n = 0; @@ -920,36 +972,40 @@ retry(struct qinfo *qp) { return; } ns_debug(ns_log_default, 5, "give up"); - n = ((HEADER *)qp->q_cmsg ? qp->q_cmsglen : qp->q_msglen); - hp->id = qp->q_id; - hp->qr = 1; - hp->ra = (NS_OPTION_P(OPTION_NORECURSE) == 0); - hp->rd = 1; - hp->rcode = SERVFAIL; + if ((qp->q_flags & Q_SYSTEM) == 0) { + n = ((HEADER *)qp->q_cmsg ? qp->q_cmsglen : qp->q_msglen); + hp->id = qp->q_id; + hp->qr = 1; + hp->ra = (NS_OPTION_P(OPTION_NORECURSE) == 0); + hp->rd = 1; + hp->rcode = SERVFAIL; #ifdef DEBUG - if (debug >= 10) - fp_nquery(qp->q_msg, n, log_get_stream(packet_channel)); + if (debug >= 10) + res_pquery(&res, qp->q_msg, n, + log_get_stream(packet_channel)); #endif - if (send_msg((u_char *)hp, n, qp)) { - ns_debug(ns_log_default, 1, - "gave up retry(%#lx) nsid=%d id=%d", - (u_long)qp, ntohs(qp->q_nsid), ntohs(qp->q_id)); + if (send_msg((u_char *)hp, n, qp)) { + ns_debug(ns_log_default, 1, + "gave up retry(%#lx) nsid=%d id=%d", + (u_long)qp, + ntohs(qp->q_nsid), ntohs(qp->q_id)); + } + if (NS_OPTION_P(OPTION_HOSTSTATS)) + nameserIncr(qp->q_from.sin_addr, nssSentFail); } - if (NS_OPTION_P(OPTION_HOSTSTATS)) - nameserIncr(qp->q_from.sin_addr, nssSentFail); qremove(qp); return; found: - if (qp->q_fwd == 0 && qp->q_addr[n].nretry == 0) + if (qp->q_addr[n].nretry == 0) qp->q_addr[n].stime = tt; qp->q_curaddr = n; hp = (HEADER *)qp->q_msg; - hp->rd = (qp->q_fwd ? 1 : 0); + hp->rd = (qp->q_addr[n].forwarder ? 1 : 0); nsa = Q_NEXTADDR(qp, n); ns_debug(ns_log_default, 1, "%s(addr=%d n=%d) -> [%s].%d ds=%d nsid=%d id=%d %dms", - (qp->q_fwd ? "reforw" : "resend"), + (qp->q_addr[n].forwarder ? "reforw" : "resend"), n, qp->q_addr[n].nretry, inet_ntoa(nsa->sin_addr), ntohs(nsa->sin_port), ds, @@ -959,9 +1015,38 @@ retry(struct qinfo *qp) { : (-1)); #ifdef DEBUG if (debug >= 10) - fp_nquery(qp->q_msg, qp->q_msglen, + res_pquery(&res, qp->q_msg, qp->q_msglen, log_get_stream(packet_channel)); #endif + key = tsig_key_from_addr(nsa->sin_addr); + if (key != NULL) { + smsgsize = qp->q_msglen + TSIG_BUF_SIZE; + smsg = memget(smsgsize); + smsglen = qp->q_msglen; + siglen = sizeof(sig); + memcpy(smsg, qp->q_msg, qp->q_msglen); + n = ns_sign(smsg, &smsglen, smsgsize, NOERROR, key, NULL, 0, + sig, &siglen, 0); + if (n == 0) { + oldqbuf = qp->q_msg; + oldqlen = qp->q_msglen; + qp->q_msglen = smsglen; + qp->q_msg = smsg; + has_tsig = 1; + qp->q_nstsig = new_tsig(key, sig, siglen); + } + else { + has_tsig = 0; + free_tsig(qp->q_nstsig); + qp->q_nstsig = NULL; + INSIST(0); + } + } else { + has_tsig = 0; + free_tsig(qp->q_nstsig); + qp->q_nstsig = NULL; + } + if (qp->q_flags & Q_USEVC) { if (tcp_send(qp) != NOERROR) ns_debug(ns_log_default, 3, @@ -971,18 +1056,32 @@ retry(struct qinfo *qp) { (struct sockaddr *)nsa, sizeof(struct sockaddr_in)) < 0) { + sendto_errno = errno; ns_debug(ns_log_default, 3, "error resending msg: %s", strerror(errno)); } + if (has_tsig == 1) { + memput(qp->q_msg, smsgsize); + qp->q_msg = oldqbuf; + qp->q_msglen = oldqlen; + } hp->rd = 1; /* leave set to 1 for dup detection */ nameserIncr(nsa->sin_addr, nssSentDupQ); unsched(qp); + switch (sendto_errno) { + case ENETDOWN: + case ENETUNREACH: + case EHOSTDOWN: + case EHOSTUNREACH: + schedretry(qp, (time_t) 0); + return; + } #ifdef SLAVE_FORWARD - if (NS_OPTION_P(OPTION_FORWARD_ONLY)) + if (NS_ZOPTION_P(qp->q_fzone, OPTION_FORWARD_ONLY)) schedretry(qp, (time_t)slave_retry); else #endif /* SLAVE_FORWARD */ - schedretry(qp, qp->q_fwd ? (2*RETRYBASE) : retrytime(qp)); + schedretry(qp, retrytime(qp)); } /* @@ -1020,16 +1119,10 @@ qflush() { void qremove(struct qinfo *qp) { - struct sockaddr_in empty_from; - - empty_from.sin_family = AF_INET; - empty_from.sin_addr.s_addr = htonl(INADDR_ANY); - empty_from.sin_port = htons(0); - ns_debug(ns_log_default, 3, "qremove(%#lx)", (u_long)qp); - if (qp->q_flags & Q_ZSERIAL) - qserial_answer(qp, 0, empty_from); + if ((qp->q_flags & Q_ZSERIAL) != 0) + qserial_answer(qp); unsched(qp); ns_freeqry(qp); } @@ -1049,10 +1142,12 @@ qfindid(u_int16_t id) { struct qinfo * qnew(const char *name, int class, int type) { struct qinfo *qp; + const char *s; + int escape = 0; qp = (struct qinfo *)memget(sizeof *qp); if (qp == NULL) - panic("qnew: memget failed", NULL); + ns_panic(ns_log_default, 1, "qnew: memget failed"); memset(qp, 0, sizeof *qp); ns_debug(ns_log_default, 5, "qnew(%#lx)", (u_long)qp); #ifdef BIND_NOTIFY @@ -1064,6 +1159,21 @@ qnew(const char *name, int class, int type) { qp->q_class = (u_int16_t)class; qp->q_type = (u_int16_t)type; qp->q_flags = 0; + s = name; + for (;;) { /* find forwarding zone, if any */ + if ((qp->q_fzone = find_zone(s, class)) != NULL && + (qp->q_fzone->z_flags & Z_FORWARD_SET) != 0) + break; + qp->q_fzone = NULL; + if (*s == '\0') + break; + while (*s != '\0' && (escape || *s != '.')) { + escape = escape ? 0 : (*s == '\\'); + s++; + } + if (*s != '\0') + s++; + } return (qp); } @@ -1101,7 +1211,6 @@ ns_freeqns(struct qinfo *qp, char *where) { void ns_freeqry(struct qinfo *qp) { struct qinfo *np; - struct databuf *dp; ns_debug(ns_log_default, 3, "ns_freeqry(%#lx)", (u_long)qp); if (qp->q_next) @@ -1115,6 +1224,10 @@ ns_freeqry(struct qinfo *qp) { freestr(qp->q_domain); if (qp->q_name != NULL) freestr(qp->q_name); + if (qp->q_tsig != NULL) + memput(qp->q_tsig, sizeof(struct tsig_record)); + if (qp->q_nstsig != NULL) + memput(qp->q_nstsig, sizeof(struct tsig_record)); ns_freeqns(qp, "ns_freeqry"); if (nsqhead == qp) nsqhead = qp->q_link; @@ -1130,3 +1243,27 @@ ns_freeqry(struct qinfo *qp) { } memput(qp, sizeof *qp); } + +void +nsfwdadd(struct qinfo *qp, struct fwdinfo *fwd) { + int i, n; + struct qserv *qs; + + n = qp->q_naddr; + while (fwd != NULL && n < MAXNS) { + qs = qp->q_addr; + for (i = 0; i < (u_int)n; i++, qs++) + if (ina_equal(qs->ns_addr.sin_addr, + fwd->fwdaddr.sin_addr)) + goto nextfwd; + qs->ns_addr = fwd->fwdaddr; + qs->ns = NULL; + qs->nsdata = NULL; + qs->forwarder = 1; + qs->nretry = 0; + n++; + nextfwd: + fwd = fwd->next; + } + qp->q_naddr = n; +} diff --git a/contrib/bind/bin/named/ns_func.h b/contrib/bind/bin/named/ns_func.h index bf58528..88c181ca 100644 --- a/contrib/bind/bin/named/ns_func.h +++ b/contrib/bind/bin/named/ns_func.h @@ -1,4 +1,5 @@ -/* Copyright (c) 1985, 1990 +/* + * Copyright (c) 1985, 1990 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,7 +31,8 @@ * SUCH DAMAGE. */ -/* Portions Copyright (c) 1993 by Digital Equipment Corporation. +/* + * 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 @@ -49,7 +51,8 @@ * SOFTWARE. */ -/* Portions Copyright (c) 1996, 1997 by Internet Software Consortium. +/* + * 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 @@ -65,14 +68,35 @@ * SOFTWARE. */ +/* + * Portions Copyright (c) 1999 by Check Point Software Technologies, 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, and that + * the name of Check Point Software Technologies Incorporated 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 CHECK POINT SOFTWARE TECHNOLOGIES + * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED + * 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. + */ + /* ns_func.h - declarations for ns_*.c's externally visible functions * - * $Id: ns_func.h,v 8.43 1998/03/20 00:53:44 halley Exp $ + * $Id: ns_func.h,v 8.90 1999/10/11 18:22:20 vixie Exp $ */ /* ++from ns_glue.c++ */ extern struct in_addr ina_get(const u_char *data); extern const char *sin_ntoa(struct sockaddr_in); +extern int ns_wouldlog(int category, int level); extern void ns_debug(int, int, const char *, ...), ns_info(int, const char *, ...), ns_notice(int, const char *, ...), @@ -92,6 +116,9 @@ extern char *__newstr(size_t, int), *__savestr(const char *, int), *checked_ctime(const time_t *t), *ctimel(long); +extern void __freestr_record(char *, char *, int); +extern char *__newstr_record(size_t, int, char *, int); +extern char *__savestr_record(const char *, int, char *, int); extern u_char *ina_put(struct in_addr ina, u_char *data), *savebuf(const u_char *, size_t, int); extern void dprintf(int level, const char *format, ...); @@ -103,21 +130,34 @@ extern void debug_freestr(char *, const char *, int); #define savestr(s, n) debug_savestr((s), (n), __FILE__, __LINE__) #define freestr(s) debug_freestr((s), __FILE__, __LINE__) #else +#ifdef RECORD_STRINGS +#define newstr(l, n) __newstr_record((l), (n), __FILE__, __LINE__) +#define savestr(s, n) __savestr_record((s), (n), __FILE__, __LINE__) +#define freestr(s) __freestr_record((s), __FILE__, __LINE__) +#else #define newstr(l, n) __newstr((l), (n)) #define savestr(s, n) __savestr((s), (n)) #define freestr(s) __freestr((s)) +#endif #endif /* DEBUG_STRINGS */ +int movefile(const char *, const char *); /* --from ns_glue.c-- */ +/* ++from ns_notify.c++ */ +#ifdef BIND_NOTIFY +void ns_notify(const char *, ns_class, ns_type); +void ns_unnotify(void); +#endif +/* --from ns_notify.c-- */ + /* ++from ns_resp.c++ */ extern void ns_resp(u_char *, int, struct sockaddr_in, struct qstream *), prime_cache(void), - delete_all(struct namebuf *, int, int), - delete_stale(struct namebuf *); + delete_all(struct namebuf *, int, int); +extern int delete_stale(struct namebuf *); extern struct qinfo *sysquery(const char *, int, int, - struct in_addr *, int, int); -extern void sysnotify(const char *, int, int); + struct in_addr *, int, u_int16_t, int); extern int doupdate(u_char *, u_char *, struct databuf **, int, int, int, u_int, struct sockaddr_in), send_msg(u_char *, int, struct qinfo *), @@ -125,7 +165,6 @@ extern int doupdate(u_char *, u_char *, struct databuf **, struct databuf **, int *, int), finddata(struct namebuf *, int, int, HEADER *, char **, int *, int *), - wanted(const struct databuf *, int, int), add_data(struct namebuf *, struct databuf **, u_char *, int, int *), @@ -142,7 +181,7 @@ extern void ns_req(u_char *, int, int, extern int stale(struct databuf *), make_rr(const char *, struct databuf *, u_char *, int, int, - u_char **, u_char **), + u_char **, u_char **, int), doaddinfo(HEADER *, u_char *, int), doaddauth(HEADER *, u_char *, int, struct namebuf *, @@ -154,13 +193,33 @@ extern int findZonePri(const struct zoneinfo *, /* --from ns_req.c-- */ /* ++from ns_xfr.c++ */ -extern void ns_xfr(struct qstream *qsp, struct namebuf *znp, +void ns_xfr(struct qstream *qsp, struct namebuf *znp, int zone, int class, int type, - int id, int opcode), + int id, int opcode, u_int32_t serial_ixfr, + struct tsig_record *in_tsig), ns_stopxfrs(struct zoneinfo *), - ns_freexfr(struct qstream *); + ns_freexfr(struct qstream *), + sx_newmsg(struct qstream *qsp), + sx_sendlev(struct qstream *qsp), + sx_sendsoa(struct qstream *qsp); /* --from ns_xfr.c-- */ +/* ++from ns_ctl.c++ */ +void ns_ctl_initialize(void); +void ns_ctl_shutdown(void); +void ns_ctl_defaults(controls *); +void ns_ctl_add(controls *, control); +control ns_ctl_new_inet(struct in_addr, u_int, ip_match_list); +#ifndef WINNT +control ns_ctl_new_unix(char *, mode_t, uid_t, gid_t); +#endif +void ns_ctl_install(controls *); +/* --from ns_ctl.c-- */ + +/* ++from ns_ixfr.c++ */ +void sx_send_ixfr(struct qstream *qsp); +/* --from ns_ixfr.c-- */ + /* ++from ns_forw.c++ */ extern time_t retrytime(struct qinfo *); extern int ns_forw(struct databuf *nsp[], @@ -174,7 +233,8 @@ extern int ns_forw(struct databuf *nsp[], int class, int type, struct namebuf *np, - int use_tcp), + int use_tcp, + struct tsig_record *in_tsig), haveComplained(u_long, u_long), nslookup(struct databuf *nsp[], struct qinfo *qp, @@ -191,7 +251,8 @@ extern void schedretry(struct qinfo *, time_t), qremove(struct qinfo *), ns_freeqns(struct qinfo *, char *), ns_freeqry(struct qinfo *), - freeComplaints(void); + freeComplaints(void), + nsfwdadd(struct qinfo *, struct fwdinfo *); extern struct qinfo *qfindid(u_int16_t), *qnew(const char *, int, int); /* --from ns_forw.c-- */ @@ -209,59 +270,82 @@ extern void sq_remove(struct qstream *), nsid_init(void), ns_setoption(int option), writestream(struct qstream *, const u_char *, int), - ns_need(int need), - opensocket_f(void); + ns_need_unsafe(enum need), + ns_need(enum need), + opensocket_f(void), + nsid_hash(u_char *, size_t); extern u_int16_t nsid_next(void); extern int sq_openw(struct qstream *, int), sq_writeh(struct qstream *, sq_closure), sq_write(struct qstream *, const u_char *, int), - ns_need_p(int option), tcp_send(struct qinfo *), aIsUs(struct in_addr); /* --from ns_main.c-- */ /* ++from ns_maint.c++ */ -extern void ns_maint(void), - zone_maint(struct zoneinfo *), +extern void zone_maint(struct zoneinfo *), sched_zone_maint(struct zoneinfo *), ns_cleancache(evContext ctx, void *uap, struct timespec due, struct timespec inter), + clean_cache_from(char *dname, struct hashbuf *htp), + remove_zone(struct zoneinfo *, const char *), purge_zone(const char *, struct hashbuf *, int), loadxfer(void), qserial_retrytime(struct zoneinfo *, time_t), qserial_query(struct zoneinfo *), - qserial_answer(struct qinfo *, u_int32_t, - struct sockaddr_in), + qserial_answer(struct qinfo *), #ifdef DEBUG printzoneinfo(int, int, int), #endif endxfer(void), - ns_reload(void); + addxfer(struct zoneinfo *), + ns_zreload(void), + ns_reload(void), + ns_reconfig(void); +#if 0 +extern int reload_all_unsafe(void); +#endif +extern int zonefile_changed_p(struct zoneinfo *); +int reload_master(struct zoneinfo *); +extern const char * deferred_reload_unsafe(struct zoneinfo *); +extern struct namebuf * purge_node(struct hashbuf *htp, struct namebuf *np); extern int clean_cache(struct hashbuf *, int); -extern void reapchild(evContext, void *, int); -extern const char * zoneTypeString(const struct zoneinfo *); +extern void reapchild(void); +extern const char * zoneTypeString(unsigned int); +extern void ns_heartbeat(evContext ctx, void *uap, + struct timespec, struct timespec); +extern void make_new_zones(void); +extern void free_zone(struct zoneinfo *); +extern struct zoneinfo *find_auth_zone(const char *, ns_class); /* --from ns_maint.c-- */ +/* ++from ns_sort.c++ */ +extern void sort_response(u_char *, u_char *, int, + struct sockaddr_in *); +/* --from ns_sort.c-- */ + /* ++from ns_init.c++ */ -extern void ns_refreshtime(struct zoneinfo *, time_t), - ns_retrytime(struct zoneinfo *, time_t), - ns_init(const char *); +extern void ns_refreshtime(struct zoneinfo *, time_t); +extern void ns_retrytime(struct zoneinfo *, time_t); +extern void ns_init(const char *); +extern void purgeandload(struct zoneinfo *zp); extern enum context ns_ptrcontext(const char *owner); extern enum context ns_ownercontext(int type, enum transport); -extern int ns_nameok(const char *name, int class, - struct zoneinfo *zp, +extern int ns_nameok(const struct qinfo *qry, const char *name, + int class, struct zoneinfo *zp, enum transport, enum context, const char *owner, struct in_addr source); extern int ns_wildcard(const char *name); -extern void zoneinit(struct zoneinfo *), - do_reload(const char *, int, int), - ns_shutdown(void); +extern void zoneinit(struct zoneinfo *); +extern void do_reload(const char *, int, int, int); +extern void ns_shutdown(void); /* --from ns_init.c-- */ /* ++from ns_ncache.c++ */ -extern void cache_n_resp(u_char *, int, struct sockaddr_in); +extern void cache_n_resp(u_char *, int, struct sockaddr_in, + const char *, int, int); /* --from ns_ncache.c-- */ /* ++from ns_udp.c++ */ @@ -280,42 +364,56 @@ extern struct nameser *nameserFind(struct in_addr addr, int flags); /* --from ns_stats.c-- */ /* ++from ns_update.c++ */ -u_char *findsoaserial(u_char *data); +void free_rrecp(ns_updque *, int rcode, struct sockaddr_in); +int findzone(const char *, int, int, int *, int); +u_char * findsoaserial(u_char *data); u_int32_t get_serial_unchecked(struct zoneinfo *zp); u_int32_t get_serial(struct zoneinfo *zp); void set_serial(struct zoneinfo *zp, u_int32_t serial); int schedule_soa_update(struct zoneinfo *, int); int schedule_dump(struct zoneinfo *); int incr_serial(struct zoneinfo *zp); -int merge_logs(struct zoneinfo *zp); -int zonedump(struct zoneinfo *zp); +int merge_logs(struct zoneinfo *zp, char *logname); +int zonedump(struct zoneinfo *zp, int isixfr); void dynamic_about_to_exit(void); enum req_action req_update(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, struct qstream *qsp, - int dfd, struct sockaddr_in from); + int dfd, struct sockaddr_in from, + struct tsig_record *in_tsig); void rdata_dump(struct databuf *dp, FILE *fp); /* --from ns_update.c-- */ /* ++from ns_config.c++ */ void free_zone_timerinfo(struct zoneinfo *); void free_zone_contents(struct zoneinfo *, int); -struct zoneinfo *find_zone(const char *, int, int); +struct zoneinfo * find_zone(const char *, int); zone_config begin_zone(char *, int); void end_zone(zone_config, int); int set_zone_type(zone_config, int); int set_zone_filename(zone_config, char *); int set_zone_checknames(zone_config, enum severity); +#ifdef BIND_NOTIFY int set_zone_notify(zone_config, int value); +#endif +int set_zone_maintain_ixfr_base(zone_config, int value); int set_zone_update_acl(zone_config, ip_match_list); int set_zone_query_acl(zone_config, ip_match_list); int set_zone_transfer_acl(zone_config, ip_match_list); int set_zone_transfer_source(zone_config, struct in_addr); +int set_zone_pubkey(zone_config, const int, const int, + const int, const char *); int set_zone_transfer_time_in(zone_config, long); int add_zone_master(zone_config, struct in_addr); +#ifdef BIND_NOTIFY int add_zone_notify(zone_config, struct in_addr); +#endif +void set_zone_forward(zone_config); +void add_zone_forwarder(zone_config, struct in_addr); +void set_zone_boolean_option(zone_config, int, int); options new_options(void); void free_options(options); -void set_boolean_option(options, int, int); +void free_rrset_order_list(rrset_order_list); +void set_global_boolean_option(options, int, int); listen_info_list new_listen_info_list(void); void free_listen_info_list(listen_info_list); void add_listen_on(options, u_int16_t, ip_match_list); @@ -323,11 +421,15 @@ FILE * write_open(char *filename); void update_pid_file(void); void set_options(options, int); void use_default_options(void); +enum ordering lookup_ordering(const char *); +rrset_order_list new_rrset_order_list(void); +rrset_order_element new_rrset_order_element(int, int, char *, enum ordering); ip_match_list new_ip_match_list(void); void free_ip_match_list(ip_match_list); ip_match_element new_ip_match_pattern(struct in_addr, u_int); ip_match_element new_ip_match_mask(struct in_addr, struct in_addr); ip_match_element new_ip_match_indirect(ip_match_list); +ip_match_element new_ip_match_key(struct dst_key *dst_key); ip_match_element new_ip_match_localhost(void); ip_match_element new_ip_match_localnets(void); void ip_match_negate(ip_match_element); @@ -335,12 +437,22 @@ void add_to_ip_match_list(ip_match_list, ip_match_element); void dprint_ip_match_list(int, ip_match_list, int, char *, char *); int ip_match_address(ip_match_list, struct in_addr); +int ip_match_addr_or_key(ip_match_list, struct in_addr, + struct dst_key *key); int ip_address_allowed(ip_match_list, struct in_addr); +int ip_addr_or_key_allowed(ip_match_list iml, + struct in_addr, + struct dst_key *key); int ip_match_network(ip_match_list, struct in_addr, struct in_addr); +int ip_match_key_name(ip_match_list iml, char *name); int distance_of_address(ip_match_list, struct in_addr); int ip_match_is_none(ip_match_list); -void add_forwarder(options, struct in_addr); +#ifdef BIND_NOTIFY +void free_also_notify(options); +int add_global_also_notify(options, struct in_addr); +#endif +void add_global_forwarder(options, struct in_addr); void free_forwarders(struct fwdinfo *); server_info find_server(struct in_addr); server_config begin_server(struct in_addr); @@ -349,13 +461,14 @@ void set_server_option(server_config, int, int); void set_server_transfers(server_config, int); void set_server_transfer_format(server_config, enum axfr_format); -void add_server_key_info(server_config, key_info); -key_info new_key_info(char *, char *, char *); -void free_key_info(key_info); -void dprint_key_info(key_info); +void add_server_key_info(server_config, struct dst_key *); +struct dst_key *new_key_info(char *, char *, char *); +void free_key_info(struct dst_key *); +struct dst_key *find_key(char *name, char *algorithm); +void dprint_key_info(struct dst_key *); key_info_list new_key_info_list(void); void free_key_info_list(key_info_list); -void add_to_key_info_list(key_info_list, key_info); +void add_to_key_info_list(key_info_list, struct dst_key *); void dprint_key_info_list(key_info_list); log_config begin_logging(void); void add_log_channel(log_config, int, log_channel); @@ -372,9 +485,14 @@ void load_configuration(const char *); /* ++from parser.y++ */ ip_match_list lookup_acl(char *); void define_acl(char *, ip_match_list); -key_info lookup_key(char *); -void define_key(char *, key_info); +struct dst_key *lookup_key(char *); +void define_key(char *, struct dst_key *); void parse_configuration(const char *); void parser_initialize(void); void parser_shutdown(void); /* --from parser.y-- */ +/* ++from ns_signal.c++ */ +void init_signals(void); +void block_signals(void); +void unblock_signals(void); +/* --from ns_signal.c-- */ diff --git a/contrib/bind/bin/named/ns_glob.h b/contrib/bind/bin/named/ns_glob.h index 8f39c84..b977f7b 100644 --- a/contrib/bind/bin/named/ns_glob.h +++ b/contrib/bind/bin/named/ns_glob.h @@ -1,9 +1,10 @@ /* * from ns.h 4.33 (Berkeley) 8/23/90 - * $Id: ns_glob.h,v 8.35 1998/05/05 19:44:20 halley Exp $ + * $Id: ns_glob.h,v 8.51 1999/10/15 21:53:32 vixie Exp $ */ -/* Copyright (c) 1986 +/* + * Copyright (c) 1986 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,7 +36,8 @@ * SUCH DAMAGE. */ -/* Portions Copyright (c) 1993 by Digital Equipment Corporation. +/* + * 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 @@ -54,7 +56,8 @@ * SOFTWARE. */ -/* Portions Copyright (c) 1996, 1997 by Internet Software Consortium. +/* + * 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 @@ -74,6 +77,9 @@ * Global variables for the name server. */ + /* original argv[] from main() */ +DECL char **saved_argv; + #ifdef DEBUG DECL int debug INIT(0); DECL int desired_debug INIT(0); @@ -82,6 +88,9 @@ DECL int desired_debug INIT(0); /* global event context */ DECL evContext ev; + /* global resolver context. */ +DECL struct __res_state res; + /* list of open streams */ DECL struct qstream *streamq; @@ -117,17 +126,23 @@ DECL time_t resettime; DECL struct qinfo *retryqp; /* default configuration file */ -DECL char *conffile INIT(NULL); +DECL char *conffile; /* default debug output file */ -DECL const char *debugfile INIT(_PATH_DEBUG); +DECL char *debugfile; /* zone information */ DECL struct zoneinfo *zones; - /* number of zones in use */ + /* number of zones allocated */ DECL int nzones; + /* free list of unused zones[] elements. */ +DECL LIST(struct zoneinfo) freezones; + + /* list of zones that have a reload pending. */ +DECL LIST(struct zoneinfo) reloadingzones; + /* set if we need a priming */ DECL int needs_prime_cache; @@ -192,8 +207,9 @@ DECL struct in_addr inaddr_any; /* Inits to 0.0.0.0 */ DECL options server_options INIT(NULL); DECL server_info nameserver_info INIT(NULL); +DECL key_info_list secretkey_info INIT(NULL); - /* These will disappear some day in favour of "struct nameser". */ +DECL int main_needs_exit INIT(0); DECL ip_match_list bogus_nameservers INIT(NULL); DECL log_context log_ctx; @@ -210,7 +226,6 @@ DECL ip_match_list local_addresses INIT(NULL); DECL ip_match_list local_networks INIT(NULL); /* are we running in no-fork mode? */ - DECL int foreground INIT(0); DECL const struct ns_sym logging_constants[] @@ -281,7 +296,9 @@ DECL const struct ns_sym category_constants[] { ns_log_db, "db" }, { ns_log_eventlib, "eventlib" }, { ns_log_packet, "packet" }, +#ifdef BIND_NOTIFY { ns_log_notify, "notify" }, +#endif { ns_log_cname, "cname" }, { ns_log_security, "security" }, { ns_log_os, "os" }, @@ -289,6 +306,7 @@ DECL const struct ns_sym category_constants[] { ns_log_maint, "maintenance" }, { ns_log_load, "load" }, { ns_log_resp_checks, "response-checks" }, + { ns_log_control, "control" }, { 0, NULL } } #endif @@ -308,6 +326,7 @@ DECL u_long globalStats[nssLast]; DECL evTimerID clean_timer; DECL evTimerID interface_timer; DECL evTimerID stats_timer; +DECL evTimerID heartbeat_timer; DECL int active_timers INIT(0); DECL uid_t user_id; @@ -317,3 +336,7 @@ DECL char * group_name INIT(NULL); DECL char * chroot_dir INIT(NULL); DECL int loading INIT(0); + +DECL int xfers_running INIT(0); +DECL int xfers_deferred INIT(0); +DECL int qserials_running INIT(0); diff --git a/contrib/bind/bin/named/ns_glue.c b/contrib/bind/bin/named/ns_glue.c index 460b64d..4b7972c 100644 --- a/contrib/bind/bin/named/ns_glue.c +++ b/contrib/bind/bin/named/ns_glue.c @@ -1,9 +1,9 @@ #if !defined(lint) && !defined(SABER) -static char rcsid[] = "$Id: ns_glue.c,v 8.7 1998/02/13 19:51:45 halley Exp $"; +static const char rcsid[] = "$Id: ns_glue.c,v 8.14 1999/10/19 02:06:26 gson Exp $"; #endif /* not lint */ /* - * Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -24,6 +24,7 @@ static char rcsid[] = "$Id: ns_glue.c,v 8.7 1998/02/13 19:51:45 halley Exp $"; #include <sys/param.h> #include <sys/socket.h> #include <sys/uio.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -88,6 +89,13 @@ sin_ntoa(struct sockaddr_in sin) { * Logging Support */ +int +ns_wouldlog(int category, int level) { + if (log_ctx_valid) + return (log_check(log_ctx, category, level)); + return (0); +} + void ns_debug(int category, int level, const char *format, ...) { va_list args; @@ -279,7 +287,7 @@ my_fclose(FILE *fp) { s = fclose(fp); if (s < 0) - ns_info(ns_log_default, "fclose(%d) failed: %m", fd, + ns_info(ns_log_default, "fclose(%d) failed: %s", fd, strerror(errno)); else ns_debug(ns_log_default, 3, "fclose(%d) succeeded", fd); @@ -303,6 +311,21 @@ savebuf(const u_char *buf, size_t len, int needpanic) { return (bp); } +char * +__newstr(size_t len, int needpanic) { + return (__newstr_record(len, needpanic, __FILE__, __LINE__)); +} + +char * +__savestr(const char *str, int needpanic) { + return (__savestr_record(str, needpanic, __FILE__, __LINE__)); +} + +void +__freestr(char *str) { + __freestr_record(str, __FILE__, __LINE__); +} + #ifdef DEBUG_STRINGS char * debug_newstr(size_t len, int needpanic, const char *file, int line) { @@ -310,7 +333,7 @@ debug_newstr(size_t len, int needpanic, const char *file, int line) { size = len + 3; /* 2 length bytes + NUL. */ printf("%s:%d: newstr %d\n", file, line, size); - return (__newstr(len, needpanic)); + return (__newstr_record(len, needpanic, file, line)); } char * @@ -320,7 +343,7 @@ debug_savestr(const char *str, int needpanic, const char *file, int line) { len = strlen(str); len += 3; /* 2 length bytes + NUL. */ printf("%s:%d: savestr %d %s\n", file, line, len, str); - return (__savestr(str, needpanic)); + return (__savestr_record(str, needpanic, file, line)); } void @@ -333,7 +356,7 @@ debug_freestr(char *str, const char *file, int line) { NS_GET16(len, bp); len += 3; /* 2 length bytes + NUL. */ printf("%s:%d: freestr %d %s\n", file, line, len, str); - __freestr(str); + __freestr_record(str, file, line); return; } #endif /* DEBUG_STRINGS */ @@ -342,12 +365,12 @@ debug_freestr(char *str, const char *file, int line) { * Return a counted string buffer big enough for a string of length 'len'. */ char * -__newstr(size_t len, int needpanic) { +__newstr_record(size_t len, int needpanic, char *file, int line) { u_char *buf, *bp; REQUIRE(len <= 65536); - buf = (u_char *)memget(2/*Len*/ + len + 1/*Nul*/); + buf = (u_char *)__memget_record(2/*Len*/ + len + 1/*Nul*/, file, line); if (buf == NULL) { if (needpanic) panic("savestr: memget failed (%s)", strerror(errno)); @@ -363,7 +386,7 @@ __newstr(size_t len, int needpanic) { * Save a NUL terminated string and return a pointer to it. */ char * -__savestr(const char *str, int needpanic) { +__savestr_record(const char *str, int needpanic, char *file, int line) { char *buf; size_t len; @@ -375,20 +398,20 @@ __savestr(const char *str, int needpanic) { else return (NULL); } - buf = __newstr(len, needpanic); + buf = __newstr_record(len, needpanic, file, line); memcpy(buf, str, len + 1); return (buf); } void -__freestr(char *str) { +__freestr_record(char *str, char *file, int line) { u_char *buf, *bp; size_t len; buf = (u_char *)str - 2/*Len*/; bp = buf; NS_GET16(len, bp); - memput(buf, 2/*Len*/ + len + 1/*Nul*/); + __memput_record(buf, 2/*Len*/ + len + 1/*Nul*/, file, line); } char * @@ -414,3 +437,14 @@ ctimel(long l) { return (checked_ctime(&t)); } + +/* + * 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. + */ +#ifndef HAVE_MOVEFILE +int +movefile(const char *oldname, const char *newname) { + return (rename(oldname, newname)); +} +#endif diff --git a/contrib/bind/bin/named/ns_init.c b/contrib/bind/bin/named/ns_init.c index 920bfeb..cc95ce6 100644 --- a/contrib/bind/bin/named/ns_init.c +++ b/contrib/bind/bin/named/ns_init.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)ns_init.c 4.38 (Berkeley) 3/21/91"; -static char rcsid[] = "$Id: ns_init.c,v 8.40 1998/04/07 18:11:58 halley Exp $"; +static const char sccsid[] = "@(#)ns_init.c 4.38 (Berkeley) 3/21/91"; +static const char rcsid[] = "$Id: ns_init.c,v 8.63 1999/10/15 19:49:04 vixie Exp $"; #endif /* not lint */ /* @@ -57,7 +57,7 @@ static char rcsid[] = "$Id: ns_init.c,v 8.40 1998/04/07 18:11:58 halley Exp $"; */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -79,6 +79,7 @@ static char rcsid[] = "$Id: ns_init.c,v 8.40 1998/04/07 18:11:58 halley Exp $"; #include <sys/param.h> #include <sys/socket.h> #include <sys/stat.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -97,6 +98,8 @@ static char rcsid[] = "$Id: ns_init.c,v 8.40 1998/04/07 18:11:58 halley Exp $"; #include <isc/logging.h> #include <isc/memcluster.h> +#include <isc/dst.h> + #include "port_after.h" #include "named.h" @@ -138,25 +141,37 @@ ns_init(const char *conffile) { gettime(&tt); if (loads == 0) { - zones = (struct zoneinfo *)memget(64 * sizeof *zones); - if (zones == NULL) - ns_panic(ns_log_config, 0, - "Not enough memory to allocate initial zones array"); - memset(zones, 0, 64 * sizeof *zones); - nzones = 1; /* zone zero is cache data */ - /* allocate cache hash table, formerly the root hash table. */ + /* Init zone data. */ + zones = NULL; + INIT_LIST(freezones); + INIT_LIST(reloadingzones); + nzones = 0; + make_new_zones(); + + /* Init cache. */ + zones[0].z_type = z_cache; + zones[0].z_origin = savestr("", 1); + + /* Allocate cache hash table, formerly the root hash table. */ hashtab = savehash((struct hashbuf *)NULL); - /* allocate root-hints/file-cache hash table */ + /* Allocate root-hints/file-cache hash table. */ fcachetab = savehash((struct hashbuf *)NULL); - /* init zone data */ - zones[0].z_type = Z_CACHE; - zones[0].z_origin = savestr("", 1); + + /* Init other misc stuff. */ + dst_init(); init_configuration(); } else { /* Mark previous zones as not yet found in boot file. */ + block_signals(); for (zp = &zones[1]; zp < &zones[nzones]; zp++) - zp->z_flags &= ~Z_FOUND; + if (zp->z_type != z_nil) { + zp->z_flags &= ~Z_FOUND; + if (LINKED(zp, z_reloadlink)) + UNLINK(reloadingzones, zp, + z_reloadlink); + } + unblock_signals(); } #ifdef DEBUG @@ -169,26 +184,20 @@ ns_init(const char *conffile) { load_configuration(conffile); /* Erase all old zones that were not found. */ - for (zp = &zones[1]; zp < &zones[nzones]; zp++) { - if (zp->z_type && (zp->z_flags & Z_FOUND) == 0) { -#ifdef BIND_UPDATE - /* - * A dynamic zone might have changed, so we - * need to dump it before removing it. - */ - if ((zp->z_flags & Z_DYNAMIC) && - ((zp->z_flags & Z_NEED_SOAUPDATE) || - (zp->z_flags & Z_NEED_DUMP))) - (void)zonedump(zp); -#endif - ns_stopxfrs(zp); - do_reload(zp->z_origin, zp->z_type, zp->z_class); - ns_notice(ns_log_config, - "%s zone \"%s\" (%s) removed", - zoneTypeString(zp), zp->z_origin, - p_class(zp->z_class)); - free_zone_contents(zp, 1); - memset(zp, 0, sizeof(*zp)); + for (zp = &zones[0]; zp < &zones[nzones]; zp++) { + if (zp->z_type == z_cache) + continue; + if (zp->z_type != z_nil && (zp->z_flags & Z_FOUND) == 0) + remove_zone(zp, "removed"); + } + /* Reload parent zones of zones removed */ + for (zp = &zones[0]; zp < &zones[nzones]; zp++) { + if (zp->z_type == z_cache) + continue; + if (zp->z_type != z_nil && + (zp->z_flags & Z_PARENT_RELOAD) != 0) { + zp->z_flags &= ~Z_PARENT_RELOAD; + purgeandload(zp); } } @@ -215,20 +224,22 @@ zoneinit(struct zoneinfo *zp) { * we will refresh the zone from a primary * immediately. */ - if (!zp->z_source) + if (zp->z_source == NULL) return; result = stat(zp->z_source, &sb); if (result != -1) { ns_stopxfrs(zp); purge_zone(zp->z_origin, hashtab, zp->z_class); } - if (result == -1 || db_load(zp->z_source, zp->z_origin, zp, NULL)) { + if (result == -1 || + db_load(zp->z_source, zp->z_origin, zp, NULL, ISNOTIXFR)) + { /* * Set zone to be refreshed immediately. */ zp->z_refresh = INIT_REFRESH; zp->z_retry = INIT_REFRESH; - if (!(zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING))) { + if ((zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING)) == 0) { zp->z_time = tt.tv_sec; sched_zone_maint(zp); } @@ -240,12 +251,17 @@ zoneinit(struct zoneinfo *zp) { } } +/* + * Purge the zone and reload all parent zones. This needs to be done when + * we unload a zone, since the child zone will have stomped the parent's + * delegation to that child when it was first loaded. + */ void -do_reload(const char *domain, int type, int class) { +do_reload(const char *domain, int type, int class, int mark) { struct zoneinfo *zp; - ns_debug(ns_log_config, 1, "do_reload: %s %d %d", - *domain ? domain : ".", type, class); + ns_debug(ns_log_config, 1, "do_reload: %s %d %d %d", + *domain ? domain : ".", type, class, mark); /* * Check if the zone has changed type. If so, we might not need to @@ -259,15 +275,11 @@ do_reload(const char *domain, int type, int class) { * * NOTE: we take care not to match ourselves. */ - if ((type != z_master && - find_zone(domain, z_master, class) != NULL) || - (type != z_slave && - (zp = find_zone(domain, z_slave, class)) != NULL && - zp->z_serial != 0) || - (type != z_stub && - (zp = find_zone(domain, z_stub, class)) != NULL && - zp->z_serial != 0) - ) + zp = find_zone(domain, class); + if (zp != NULL && + (type != z_master && zp->z_type == z_master) || + (type != z_slave && zp->z_type == z_slave && zp->z_serial != 0) || + (type != z_stub && zp->z_type == z_stub && zp->z_serial != 0)) return; /* @@ -301,49 +313,51 @@ do_reload(const char *domain, int type, int class) { else domain = ""; /* root zone */ - if ((zp = find_zone(domain, Z_STUB, class)) || - (zp = find_zone(domain, Z_CACHE, class)) || - (zp = find_zone(domain, Z_PRIMARY, class)) || - (zp = find_zone(domain, Z_SECONDARY, class))) { - + zp = find_zone(domain, class); + if (zp != NULL) { ns_debug(ns_log_config, 1, "do_reload: matched %s", *domain ? domain : "."); - - if (zp->z_type == Z_CACHE) - purge_zone(zp->z_origin, fcachetab, - zp->z_class); + if (mark) + zp->z_flags |= Z_PARENT_RELOAD; else - purge_zone(zp->z_origin, hashtab, zp->z_class); - - zp->z_flags &= ~Z_AUTH; - - switch (zp->z_type) { - case Z_SECONDARY: - case Z_STUB: - zoneinit(zp); - break; - case Z_PRIMARY: - if (db_load(zp->z_source, zp->z_origin, zp, 0) - == 0) - zp->z_flags |= Z_AUTH; - break; - case Z_CACHE: - (void)db_load(zp->z_source, zp->z_origin, zp, - 0); - break; - } + purgeandload(zp); break; } } } +void +purgeandload(struct zoneinfo *zp) { + if (zp->z_type == Z_HINT) + purge_zone(zp->z_origin, fcachetab, zp->z_class); + else + purge_zone(zp->z_origin, hashtab, zp->z_class); + + zp->z_flags &= ~Z_AUTH; + + switch (zp->z_type) { + case Z_SECONDARY: + case Z_STUB: + zoneinit(zp); + break; + case Z_PRIMARY: + if (db_load(zp->z_source, zp->z_origin, zp, 0, ISNOTIXFR) == 0) + zp->z_flags |= Z_AUTH; + break; + case Z_HINT: + case Z_CACHE: + (void)db_load(zp->z_source, zp->z_origin, zp, 0, ISNOTIXFR); + break; + } +} + #ifdef DEBUG /* prints out the content of zones */ static void content_zone(int end, int level) { int i; - for (i = 1; i <= end; i++) { + for (i = 0; i <= end; i++) { printzoneinfo(i, ns_log_config, level); } } @@ -353,7 +367,8 @@ enum context ns_ptrcontext(owner) const char *owner; { - if (samedomain(owner, "in-addr.arpa") || samedomain(owner, "ip6.int")) + if (ns_samedomain(owner, "in-addr.arpa") || + ns_samedomain(owner, "ip6.int")) return (hostname_ctx); return (domain_ctx); } @@ -370,6 +385,7 @@ ns_ownercontext(type, transport) case T_WKS: case T_MX: switch (transport) { + case update_trans: case primary_trans: case secondary_trans: context = owner_ctx; @@ -394,8 +410,8 @@ ns_ownercontext(type, transport) } int -ns_nameok(const char *name, int class, struct zoneinfo *zp, - enum transport transport, +ns_nameok(const struct qinfo *qry, const char *name, int class, + struct zoneinfo *zp, enum transport transport, enum context context, const char *owner, struct in_addr source) @@ -428,19 +444,45 @@ ns_nameok(const char *name, int class, struct zoneinfo *zp, "unexpected context %d in ns_nameok", (int)context); } if (!ok) { - char *s, *o; + char *q, *s, *o; if (source.s_addr == INADDR_ANY) s = savestr(transport_strings[transport], 0); else { s = newstr(strlen(transport_strings[transport]) + - sizeof " from [000.000.000.000]", 0); + sizeof " from [000.000.000.000] for [000.000.000.000]", 0); if (s) - sprintf(s, "%s from [%s]", + if ( (transport == response_trans) && + (qry != NULL) ) { + + if ( qry->q_flags & Q_PRIMING ) { + sprintf(s, "%s from [%s] for priming", + transport_strings[transport], + inet_ntoa(source)); + } else if ( qry->q_flags & Q_ZSERIAL ) { + sprintf(s, "%s from [%s] for soacheck", transport_strings[transport], inet_ntoa(source)); + } else if ( qry->q_flags & Q_SYSTEM ) { + sprintf(s, "%s from [%s] for sysquery", + transport_strings[transport], + inet_ntoa(source)); + } else { + q=strdup(inet_ntoa(qry->q_from.sin_addr)); + sprintf(s, "%s from [%s] for [%s]", + transport_strings[transport], + inet_ntoa(source), + q != NULL ? q : "memget failed"); + free(q); + } + + } else { + sprintf(s, "%s from [%s]", + transport_strings[transport], + inet_ntoa(source)); + } } - if (strcasecmp(owner, name) == 0) + if (ns_samename(owner, name) == 1) o = savestr("", 0); else { const char *t = (*owner == '\0') ? "." : owner; @@ -454,8 +496,11 @@ ns_nameok(const char *name, int class, struct zoneinfo *zp, * the message formatting and arguments. */ log_write(log_ctx, ns_log_default, - (transport == response_trans) ? - log_info : log_notice, + (transport != response_trans) || + (o == NULL) || (s == NULL) || + ( (qry != NULL) && + (qry->q_flags & (Q_PRIMING|Q_ZSERIAL)) ) ? + log_warning : log_info, "%s name \"%s\"%s %s (%s) is invalid - %s", context_strings[context], name, o != NULL ? o : "[memget failed]", @@ -484,29 +529,36 @@ void ns_shutdown() { struct zoneinfo *zp; +#ifdef BIND_NOTIFY + ns_unnotify(); +#endif /* Erase zones. */ for (zp = &zones[0]; zp < &zones[nzones]; zp++) { if (zp->z_type) { - if (zp->z_type != z_hint) { + if (zp->z_type != z_hint && zp->z_type != z_cache) { ns_stopxfrs(zp); purge_zone(zp->z_origin, hashtab, zp->z_class); - } + } else if (zp->z_type == z_hint) + purge_zone(zp->z_origin, fcachetab, + zp->z_class); free_zone_contents(zp, 1); } } - memput(zones, ((nzones / 64) + 1) * 64 * sizeof *zones); /* Erase the cache. */ clean_cache(hashtab, 1); hashtab->h_cnt = 0; /* ??? */ rm_hash(hashtab); + hashtab = NULL; clean_cache(fcachetab, 1); fcachetab->h_cnt = 0; /* ??? */ rm_hash(fcachetab); + fcachetab = NULL; + + if (zones != NULL) + memput(zones, nzones * sizeof *zones); + zones = NULL; -#ifdef BIND_NOTIFY - db_cancel_pending_notifies(); -#endif freeComplaints(); shutdown_configuration(); } diff --git a/contrib/bind/bin/named/ns_ixfr.c b/contrib/bind/bin/named/ns_ixfr.c new file mode 100644 index 0000000..76dbe6e --- /dev/null +++ b/contrib/bind/bin/named/ns_ixfr.c @@ -0,0 +1,563 @@ +#if !defined(lint) && !defined(SABER) +static const char rcsid[] = "$Id: ns_ixfr.c,v 8.17 1999/11/05 04:48:28 vixie Exp $"; +#endif /* not lint */ + +/* + * Portions Copyright (c) 1999 by Check Point Software Technologies, 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, and that + * the name of Check Point Software Technologies Incorporated 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 CHECK POINT SOFTWARE TECHNOLOGIES + * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED + * 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/param.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> + +#include <errno.h> +#include <fcntl.h> +#include <resolv.h> +#include <res_update.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <time.h> + +#include <isc/eventlib.h> +#include <isc/logging.h> +#include <isc/memcluster.h> + +#include "port_after.h" + +#include "named.h" + +static void sx_new_ixfrmsg(struct qstream * qsp); +void sx_send_ixfr(struct qstream * qsp); + +static int sx_flush(struct qstream * qsp), + sx_addrr(struct qstream * qsp, + const char *dname, + struct databuf * dp); +extern void sx_sendsoa(struct qstream * qsp); + +/* + * u_char * sx_new_ixfrmsg(msg) init the header of a message, reset the + * compression pointers, and reset the write pointer to the first byte + * following the header. + */ +static void +sx_new_ixfrmsg(struct qstream *qsp) { + HEADER * hp = (HEADER *) qsp->xfr.msg; + ns_updrec * up; + + memset(hp, 0, HFIXEDSZ); + hp->id = htons(qsp->xfr.id); + hp->opcode = qsp->xfr.opcode; + hp->qr = 1; + hp->aa = 1; + hp->rcode = NOERROR; + + qsp->xfr.ptrs[0] = qsp->xfr.msg; + qsp->xfr.ptrs[1] = NULL; + + qsp->xfr.cp = qsp->xfr.msg + HFIXEDSZ; + if (qsp->xfr.ixfr_zone == 0) { + int count, n; + int buflen; + struct namebuf *np; + struct hashbuf *htp; + struct zoneinfo *zp; + struct databuf *dp; + const char * fname; + u_char ** edp = qsp->xfr.ptrs + + sizeof qsp->xfr.ptrs / sizeof(u_char *); + + qsp->xfr.ixfr_zone = qsp->xfr.zone; + zp = &zones[qsp->xfr.zone]; + up = qsp->xfr.top.ixfr; + n = dn_comp(zp->z_origin, qsp->xfr.cp, + XFER_BUFSIZE - (qsp->xfr.cp - qsp->xfr.msg), NULL, NULL); + qsp->xfr.cp += n; + PUTSHORT((u_int16_t) T_IXFR, qsp->xfr.cp); + PUTSHORT((u_int16_t) zp->z_class, qsp->xfr.cp); + hp->qdcount = htons(ntohs(hp->qdcount) + 1); + count = qsp->xfr.cp - qsp->xfr.msg; + htp = hashtab; + np = nlookup(zp->z_origin, &htp, &fname, 0); + buflen = XFER_BUFSIZE; + foreach_rr(dp, np, T_SOA, qsp->xfr.class, qsp->xfr.zone) { + n = make_rr(zp->z_origin, dp, qsp->xfr.cp, qsp->xfr.eom - qsp->xfr.cp, 0, qsp->xfr.ptrs, edp, 0); + qsp->xfr.cp += n; + hp->ancount = htons(ntohs(hp->ancount) + 1); + } + } +} + +/* + * int sx_flush(qsp) flush the intermediate buffer out to the stream IO + * system. return: passed through from sq_write(). + */ +static int +sx_flush(struct qstream *qsp) { + int ret; + +#ifdef DEBUG + if (debug >= 10) + fp_nquery(qsp->xfr.msg, qsp->xfr.cp - qsp->xfr.msg, + log_get_stream(packet_channel)); +#endif + ret = sq_write(qsp, qsp->xfr.msg, qsp->xfr.cp - qsp->xfr.msg); + if (ret >= 0) + qsp->xfr.cp = NULL; + return (ret); +} + +/* + * int sx_addrr(qsp, name, dp) add name/dp's RR to the current assembly + * message. if it won't fit, write current message out, renew the message, + * and then RR should fit. return: -1 = the sq_write() failed so we could not + * queue the full message. 0 = one way or another, everything is fine. side + * effects: on success, the ANCOUNT is incremented and the pointers are + * advanced. + */ +static int +sx_addrr(struct qstream *qsp, const char *dname, struct databuf *dp) { + HEADER *hp = (HEADER *) qsp->xfr.msg; + u_char **edp = qsp->xfr.ptrs + sizeof qsp->xfr.ptrs / sizeof(u_char *); + int n; + + if (qsp->xfr.cp != NULL) { + if (qsp->xfr.transfer_format == axfr_one_answer && + sx_flush(qsp) < 0) + return (-1); + } + if (qsp->xfr.cp == NULL) + sx_new_ixfrmsg(qsp); + n = make_rr(dname, dp, qsp->xfr.cp, qsp->xfr.eom - qsp->xfr.cp, + 0, qsp->xfr.ptrs, edp, 0); + if (n < 0) { + if (sx_flush(qsp) < 0) + return (-1); + if (qsp->xfr.cp == NULL) + sx_new_ixfrmsg(qsp); + n = make_rr(dname, dp, qsp->xfr.cp, qsp->xfr.eom - qsp->xfr.cp, + 0, qsp->xfr.ptrs, edp, 0); + INSIST(n >= 0); + } + hp->ancount = htons(ntohs(hp->ancount) + 1); + qsp->xfr.cp += n; + return (0); +} + +void +sx_send_ixfr(struct qstream *qsp) { + char * cp; + u_int32_t serial = 0; + struct zoneinfo *zp = NULL; + struct databuf *soa_dp; + struct databuf *old_soadp; + ns_updrec * rp; + ns_updrec * trp; + int foundsoa; + + zp = &zones[qsp->xfr.zone]; + soa_dp = (struct databuf *) findzonesoa(zp); + if (soa_dp == NULL) { + /* XXX should be more graceful */ + ns_panic(ns_log_update, 1, + "sx_send_ixfr: unable to locate soa"); + } + old_soadp = memget(DATASIZE(soa_dp->d_size)); + memcpy(old_soadp, soa_dp, DATASIZE(soa_dp->d_size)); + + again: + switch (qsp->xfr.state) { + case s_x_firstsoa: + /* + * The current SOA has been emited already. + * It would be cleaner if the first one was emited here... + * + * if (sx_addrr(qsp, zp->z_origin, soa_dp) < 0) + * goto cleanup; + */ + qsp->xfr.state = s_x_deletesoa; + /* FALLTHROUGH */ + case s_x_deletesoa: + if (qsp->xfr.top.ixfr) { + foundsoa = 0; + rp = qsp->xfr.top.ixfr; + while (PREV(rp, r_link) != NULL) + rp = PREV(rp, r_link); + while (rp != NULL) { + if (rp->r_opcode == DELETE && + rp->r_dp != NULL && + rp->r_dp->d_type == T_SOA) { + if (sx_addrr(qsp, rp->r_dname, + rp->r_dp) < 0) + goto cleanup; + db_freedata(rp->r_dp); + rp->r_dp = NULL; + foundsoa = 1; + break; + } + trp = rp; + rp = NEXT(rp, r_link); + } + + if (!foundsoa) { + cp = (char *)findsoaserial(old_soadp->d_data); + PUTLONG(qsp->xfr.top.ixfr->r_zone, cp); + + if (sx_addrr(qsp, zp->z_origin, old_soadp) < 0) + goto cleanup; + } + } + qsp->xfr.state = s_x_deleting; + /* FALLTHROUGH */ + case s_x_deleting: + if (qsp->xfr.top.ixfr) { + /* + * The order s important here. + * Go to start of this update via PREV(r_link) + * then extract all deletions. + */ + rp = qsp->xfr.top.ixfr; + while (PREV(rp, r_link) != NULL) + rp = PREV(rp, r_link); + while (rp != NULL) { + if (rp->r_opcode == DELETE && + rp->r_dp != NULL) { + /* + * Drop any SOA deletes + */ + if (rp->r_dp->d_type != T_SOA && + sx_addrr(qsp, rp->r_dname, + rp->r_dp) < 0) + goto cleanup; + db_freedata(rp->r_dp); + rp->r_dp = NULL; + } + trp = rp; + rp = NEXT(rp, r_link); + } + } + qsp->xfr.state = s_x_addsoa; + /* FALLTHROUGH */ + case s_x_addsoa: + if (qsp->xfr.top.ixfr) { + foundsoa = 0; + rp = qsp->xfr.top.ixfr; + while (PREV(rp, r_link) != NULL) + rp = PREV(rp, r_link); + while (rp != NULL) { + if (rp->r_opcode == ADD && + rp->r_dp != NULL && + rp->r_dp->d_type == T_SOA) { + if (sx_addrr(qsp, rp->r_dname, + rp->r_dp) < 0) + goto cleanup; + db_freedata(rp->r_dp); + rp->r_dp = NULL; + foundsoa = 1; + break; + } + trp = rp; + rp = NEXT(rp, r_link); + } + + if (!foundsoa) { + cp = (char *)findsoaserial(old_soadp->d_data); + if (NEXT(qsp->xfr.top.ixfr, r_link) != NULL) { + trp = qsp->xfr.top.ixfr; + PUTLONG(NEXT(trp, r_link)->r_zone, cp); + if (sx_addrr(qsp, zp->z_origin, + old_soadp) < 0) + goto cleanup; + } else { + if (sx_addrr(qsp, zp->z_origin, + soa_dp) < 0) + goto cleanup; + } + } + } + qsp->xfr.state = s_x_adding; + /* FALLTHROUGH */ + case s_x_adding: + if (qsp->xfr.top.ixfr) { + /* see s_x_deleting */ + rp = qsp->xfr.top.ixfr; + while (PREV(rp, r_link) != NULL) + rp = PREV(rp, r_link); + while (rp != NULL) { + if (rp->r_opcode == ADD && + rp->r_dp != NULL && + rp->r_dp->d_type != T_SOA) { + if (sx_addrr(qsp, rp->r_dname, + rp->r_dp) < 0) + goto cleanup; + db_freedata(rp->r_dp); + rp->r_dp = NULL; + } + trp = rp; + rp = NEXT(rp, r_link); + } + /* move to next update */ + rp = qsp->xfr.top.ixfr; + qsp->xfr.top.ixfr = NEXT(rp, r_link); + PREV(rp, r_link) = NULL; + + /* clean up old update */ + while (rp != NULL) { + trp = PREV(rp, r_link); + if (rp->r_dp != NULL) { + db_freedata(rp->r_dp); + rp->r_dp = NULL; + } + res_freeupdrec(rp); + rp = trp; + } + } + qsp->xfr.state = s_x_lastsoa; + /* FALLTHROUGH */ + case s_x_lastsoa: + if (qsp->xfr.ixfr_zone != 0) { + sx_addrr(qsp, zp->z_origin, soa_dp); + } + break; + } + qsp->xfr.state = s_x_done; + sx_flush(qsp); + sq_writeh(qsp, sq_flushw); + cleanup: + memput(old_soadp, DATASIZE(old_soadp->d_size)); +} + + +#ifndef MAXBSIZE +#define MAXBSIZE 8192 +#endif + + +int ixfr_log_maint(struct zoneinfo *zp) { + int fd, rcount, wcount, rval; + int found = 0, seek = 0; + FILE *to_fp, *from_fp, *db_fp; + static char *tmpname; + struct stat db_sb; + struct stat sb; + static char buf[MAXBSIZE]; + + ns_debug(ns_log_default, 3, "ixfr_log_maint(%s)", zp->z_origin); + + tmpname = memget(strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1); + if (!tmpname) { + ns_warning(ns_log_default, "memget failed"); + return (-1); + } +#ifdef SHORT_FNAMES + filenamecpy(tmpname, zp->z_ixfr_base); +#else + (void) strcpy(tmpname, zp->z_ixfr_base); +#endif /* SHORT_FNAMES */ + + (void) strcat(tmpname, ".XXXXXX"); + if ((fd = mkstemp(tmpname)) == -1) { + ns_warning(ns_log_db, "can't make tmpfile (%s): %s", + strerror(errno)); + memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1)); + return (-1); + } + if ((to_fp = fdopen(fd, "r+")) == NULL) { + ns_warning(ns_log_db, "%s: %s", + tmpname, strerror(errno)); + (void) unlink(tmpname); + memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1)); + (void) close(fd); + return (-1); + } + /* find out how big the zone db file is */ + if ((db_fp = fopen(zp->z_source, "r")) == NULL) { + ns_warning(ns_log_db, "%s: %s", + zp->z_source, strerror(errno)); + (void) unlink(tmpname); + memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1)); + (void) my_fclose(to_fp); + (void) close(fd); + return (-1); + } + if (fstat(fileno(db_fp), &db_sb) < 0) { + ns_warning(ns_log_db, "%s: %s", + zp->z_source, strerror(errno)); + (void) my_fclose(to_fp); + (void) my_fclose(db_fp); + (void) close(fd); + (void) unlink(tmpname); + memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1)); + return (-1); + } + (void) my_fclose(db_fp); + ns_debug(ns_log_default, 3, "%s, size %d blk %d", + zp->z_source, db_sb.st_size, + db_sb.st_size); + + /* open up the zone ixfr log */ + if ((from_fp = fopen(zp->z_ixfr_base, "r")) == NULL) { + ns_warning(ns_log_db, "%s: %s", + zp->z_ixfr_base, strerror(errno)); + (void) my_fclose(to_fp); + (void) close(fd); + (void) unlink(tmpname); + memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1)); + return (-1); + } + + if (fstat(fileno(from_fp), &sb) < 0) { + ns_warning(ns_log_db, "%s: %s", + zp->z_ixfr_base, strerror(errno)); + (void) my_fclose(to_fp); + (void) close(fd); + (void) unlink(tmpname); + (void) my_fclose(from_fp); + memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1)); + return (-1); + } + ns_debug(ns_log_default, 3, "%s, size %d log_s %d max %d\n", + zp->z_ixfr_base, + sb.st_size, + zp->z_log_size_ixfr, + zp->z_max_log_size_ixfr); + if (zp->z_max_log_size_ixfr) { + if (sb.st_size > zp->z_max_log_size_ixfr) + seek = sb.st_size - (zp->z_max_log_size_ixfr + (zp->z_max_log_size_ixfr *.10)); + else + seek = 0; + } else { + if (sb.st_size > (db_sb.st_size * .50)) + seek = sb.st_size - ((db_sb.st_size * .50) + + ((db_sb.st_size * zp->z_max_log_size_ixfr) *.10)); + else + seek = 0; + } + ns_debug(ns_log_default, 3, "seek: %d", seek); + if (seek < 1) + { + ns_debug(ns_log_default, 3, "%s does not need to be reduced", + zp->z_ixfr_base); + (void) my_fclose(to_fp); + (void) close(fd); + (void) unlink(tmpname); + (void) my_fclose(from_fp); + memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1)); + return (-1); + } + + + if (fgets(buf, sizeof(buf), from_fp) == NULL) { + ns_error(ns_log_update, "fgets() from %s failed: %s", + zp->z_ixfr_base, strerror(errno)); + (void) my_fclose(from_fp); + (void) my_fclose(to_fp); + (void) close(fd); + (void) unlink(tmpname); + memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1)); + return (-1); + } + if (strcmp(buf, LogSignature) != 0) { + ns_error(ns_log_update, "invalid log file %s", + zp->z_ixfr_base); + (void) my_fclose(from_fp); + (void) my_fclose(to_fp); + (void) close(fd); + (void) unlink(tmpname); + memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1)); + return (-3); + } + + if (fseek( from_fp, seek, 0) < 0) { + (void) my_fclose(from_fp); + (void) my_fclose(to_fp); + (void) close(fd); + (void) unlink(tmpname); + memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1)); + return (-1); + } + + found = 0; + for (;;) { + if (getword(buf, sizeof buf, from_fp, 0)) { + if (strcasecmp(buf, "[END_DELTA]") == 0) { + if (!(fgets(buf, 2, from_fp) == NULL)) /* eat <cr><lf> */ + found = 1; + break; + } + } + if (feof(from_fp)) + break; + } + if (found) { + ns_debug(ns_log_default, 1, "ixfr_log_maint(): found [END_DELTA]"); + + while ((rcount = fread(buf, sizeof(char), MAXBSIZE, from_fp)) > 0) { + wcount = fwrite(buf, sizeof(char), rcount, to_fp); + if (rcount != wcount || wcount == -1) { + ns_warning(ns_log_default, "ixfr_log_maint: error in writting copy"); + rval = 1; + break; + } + } + if (rcount < 0) { + ns_warning(ns_log_default, "ixfr_log_maint: error in reading copy"); + rval = 1; + } + } + (void) my_fclose(to_fp); + (void) close(fd); + (void) my_fclose(from_fp); + if (rename(tmpname, zp->z_ixfr_base) == -1) { + ns_warning(ns_log_default, "can not rename %s to %s :%s", + tmpname, zp->z_ixfr_base, strerror(errno)); + } + (void) unlink(tmpname); + memput(tmpname, (strlen(zp->z_ixfr_base) + sizeof(".XXXXXX") + 1)); + if ((from_fp = fopen(zp->z_ixfr_base, "r")) == NULL) { + ns_warning(ns_log_db, "%s: %s", + zp->z_ixfr_base, strerror(errno)); + return (-1); + } + if (fstat(fileno(from_fp), &sb) < 0) { + ns_warning(ns_log_db, "%s: %s", + zp->z_ixfr_base, strerror(errno)); + (void) my_fclose(from_fp); + return (-1); + } + if (sb.st_size <= 0) + (void) unlink(zp->z_ixfr_base); + (void) my_fclose(from_fp); + + ns_debug(ns_log_default, 3, "%s, size %d log_s %d max %d\n", + zp->z_ixfr_base, + sb.st_size, + zp->z_log_size_ixfr, + zp->z_max_log_size_ixfr); + return (0); +} diff --git a/contrib/bind/bin/named/ns_lexer.c b/contrib/bind/bin/named/ns_lexer.c index fe319fa..244d5f6 100644 --- a/contrib/bind/bin/named/ns_lexer.c +++ b/contrib/bind/bin/named/ns_lexer.c @@ -1,9 +1,9 @@ #if !defined(lint) && !defined(SABER) -static char rcsid[] = "$Id: ns_lexer.c,v 8.12 1997/12/04 08:11:52 halley Exp $"; +static const char rcsid[] = "$Id: ns_lexer.c,v 8.19 1999/10/13 16:39:08 vixie Exp $"; #endif /* not lint */ /* - * Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -22,6 +22,8 @@ static char rcsid[] = "$Id: ns_lexer.c,v 8.12 1997/12/04 08:11:52 halley Exp $"; #include "port_before.h" #include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -52,6 +54,7 @@ typedef enum lexer_state { } LexerState; #define LEX_EOF 0x01 +#define LEXER_MAX_PUSHBACK 2 typedef struct lexer_file_context { const char * name; @@ -61,6 +64,8 @@ typedef struct lexer_file_context { u_int flags; int warnings; int errors; + u_int pushback_count; + char pushback[LEXER_MAX_PUSHBACK]; struct lexer_file_context * next; } *LexerFileContext; @@ -216,21 +221,29 @@ static struct keyword keywords[] = { {"acl", T_ACL}, {"address", T_ADDRESS}, {"algorithm", T_ALGID}, + {"allow", T_ALLOW}, {"allow-query", T_ALLOW_QUERY}, + {"allow-recursion", T_ALLOW_RECURSION}, {"allow-transfer", T_ALLOW_TRANSFER}, {"allow-update", T_ALLOW_UPDATE}, +#ifdef BIND_NOTIFY {"also-notify", T_ALSO_NOTIFY}, +#endif {"auth-nxdomain", T_AUTH_NXDOMAIN}, + {"blackhole", T_BLACKHOLE}, {"bogus", T_BOGUS}, {"category", T_CATEGORY}, + {"class", T_CLASS}, {"channel", T_CHANNEL}, {"check-names", T_CHECK_NAMES}, {"cleaning-interval", T_CLEAN_INTERVAL}, + {"controls", T_CONTROLS}, {"coresize", T_CORESIZE}, {"datasize", T_DATASIZE}, {"deallocate-on-exit", T_DEALLOC_ON_EXIT}, {"debug", T_DEBUG}, {"default", T_DEFAULT}, + {"dialup", T_DIALUP}, {"directory", T_DIRECTORY}, {"dump-file", T_DUMP_FILE}, {"dynamic", T_DYNAMIC}, @@ -243,47 +256,70 @@ static struct keyword keywords[] = { {"first", T_FIRST}, {"forward", T_FORWARD}, {"forwarders", T_FORWARDERS}, + {"group", T_GROUP}, + {"has-old-clients", T_HAS_OLD_CLIENTS}, + {"heartbeat-interval", T_HEARTBEAT}, {"hint", T_HINT}, {"host-statistics", T_HOSTSTATS}, {"if-no-answer", T_IF_NO_ANSWER}, {"if-no-domain", T_IF_NO_DOMAIN}, {"ignore", T_IGNORE}, {"include", T_INCLUDE}, + {"inet", T_INET}, {"interface-interval", T_INTERFACE_INTERVAL}, + {"ixfr-base", T_FILE_IXFR}, + {"ixfr-tmp-file", T_IXFR_TMP}, {"key", T_SEC_KEY}, {"keys", T_KEYS}, + {"lame-ttl", T_LAME_TTL}, {"listen-on", T_LISTEN_ON}, {"logging", T_LOGGING}, + {"maintain-ixfr-base", T_MAINTAIN_IXFR_BASE}, {"many-answers", T_MANY_ANSWERS}, {"master", T_MASTER}, {"masters", T_MASTERS}, + {"max-ixfr-log-size", T_MAX_LOG_SIZE_IXFR}, + {"max-ncache-ttl", T_MAX_NCACHE_TTL}, {"max-transfer-time-in", T_MAX_TRANSFER_TIME_IN}, {"memstatistics-file", T_MEMSTATS_FILE}, + {"min-roots", T_MIN_ROOTS}, {"multiple-cnames", T_MULTIPLE_CNAMES}, + {"name", T_NAME}, {"named-xfer", T_NAMED_XFER}, {"no", T_NO}, +#ifdef BIND_NOTIFY {"notify", T_NOTIFY}, +#endif {"null", T_NULL_OUTPUT}, {"one-answer", T_ONE_ANSWER}, {"only", T_ONLY}, + {"order", T_ORDER}, {"options", T_OPTIONS}, + {"owner", T_OWNER}, + {"perm", T_PERM}, {"pid-file", T_PIDFILE}, {"port", T_PORT}, {"print-category", T_PRINT_CATEGORY}, {"print-severity", T_PRINT_SEVERITY}, {"print-time", T_PRINT_TIME}, + {"pubkey", T_PUBKEY}, {"query-source", T_QUERY_SOURCE}, + {"rfc2308-type1", T_RFC2308_TYPE1}, + {"rrset-order", T_RRSET_ORDER}, {"recursion", T_RECURSION}, {"response", T_RESPONSE}, {"secret", T_SECRET}, + {"serial-queries", T_SERIAL_QUERIES}, {"server", T_SERVER}, {"severity", T_SEVERITY}, {"size", T_SIZE}, {"slave", T_SLAVE}, + {"sortlist", T_SORTLIST}, {"stacksize", T_STACKSIZE}, {"statistics-file", T_STATS_FILE}, {"statistics-interval", T_STATS_INTERVAL}, {"stub", T_STUB}, + {"support-ixfr", T_SUPPORT_IXFR}, {"syslog", T_SYSLOG}, {"topology", T_TOPOLOGY}, {"transfer-format", T_TRANSFER_FORMAT}, @@ -292,9 +328,15 @@ static struct keyword keywords[] = { {"transfers-in", T_TRANSFERS_IN}, {"transfers-out", T_TRANSFERS_OUT}, {"transfers-per-ns", T_TRANSFERS_PER_NS}, + {"treat-cr-as-space", T_TREAT_CR_AS_SPACE}, {"true", T_TRUE}, + {"trusted-keys", T_TRUSTED_KEYS}, {"type", T_TYPE}, + {"unix", T_UNIX}, {"unlimited", T_UNLIMITED}, + {"use-id-pool", T_USE_ID_POOL}, + {"use-ixfr", T_USE_IXFR}, + {"version", T_VERSION}, {"versions", T_VERSIONS}, {"warn", T_WARN}, {"yes", T_YES}, @@ -351,6 +393,7 @@ lexer_begin_file(const char *filename, FILE *stream) { lf->flags = 0; lf->warnings = 0; lf->errors = 0; + lf->pushback_count = 0; lf->next = current_file; current_file = lf; } @@ -370,14 +413,29 @@ lexer_end_file(void) { * Character Input */ +#define LEXER_GETC(c, cf) \ + do { \ + if ((cf)->pushback_count > 0) { \ + (cf)->pushback_count--; \ + (c) = (cf)->pushback[(cf)->pushback_count]; \ + } else \ + (c) = getc((cf)->stream); \ + } while (0); + +#define LEXER_UNGETC(c, cf) \ + do { \ + INSIST((cf)->pushback_count < LEXER_MAX_PUSHBACK); \ + (cf)->pushback[(cf)->pushback_count++] = (c); \ + } while (0); + static void scan_to_comment_end(int c_plus_plus_style) { - int c, nc; + int c; int done = 0; int prev_was_star = 0; while (!done) { - c = getc(current_file->stream); + LEXER_GETC(c, current_file); switch (c) { case EOF: if (!c_plus_plus_style) @@ -399,7 +457,7 @@ scan_to_comment_end(int c_plus_plus_style) { we want it to be a delimiter for anything before the comment started */ - ungetc(c, current_file->stream); + LEXER_UNGETC(c, current_file); done = 1; } else { current_file->line_number++; @@ -419,7 +477,7 @@ get_next_char(int comment_ok) { if (current_file->flags & LEX_EOF) return (EOF); - c = getc(current_file->stream); + LEXER_GETC(c, current_file); if (comment_ok) { while (c == '/' || c == '#') { @@ -427,9 +485,9 @@ get_next_char(int comment_ok) { scan_to_comment_end(1); if (current_file->flags & LEX_EOF) return (EOF); - c = getc(current_file->stream); + LEXER_GETC(c, current_file); } else { - nc = getc(current_file->stream); + LEXER_GETC(nc, current_file); switch (nc) { case EOF: current_file->flags |= LEX_EOF; @@ -439,10 +497,10 @@ get_next_char(int comment_ok) { scan_to_comment_end((nc == '/')); if (current_file->flags & LEX_EOF) return (EOF); - c = getc(current_file->stream); + LEXER_GETC(c, current_file); break; default: - ungetc((nc), current_file->stream); + LEXER_UNGETC(nc, current_file); return ('/'); } } @@ -461,7 +519,7 @@ put_back_char(int c) { if (c == EOF) current_file->flags |= LEX_EOF; else { - ungetc((c), current_file->stream); + LEXER_UNGETC(c, current_file); if (c == '\n') current_file->line_number--; } @@ -504,7 +562,7 @@ add_to_identifier(LexerIdentifier id, int c) { parser_error(0, "identifier too long"); current_file->state = scan; /* discard chars until we hit a non-identifier char */ - while (identifier_char(c)) { + while (c != EOF && identifier_char(c)) { c = get_next_char(1); } put_back_char(c); @@ -526,7 +584,7 @@ add_to_identifier(LexerIdentifier id, int c) { */ int yylex() { - int c, i; + int c; int comment_ok = 1; int token = -1; symbol_value value; @@ -581,7 +639,7 @@ yylex() { break; case number: - if (identifier_char(c)) { + if (c != EOF && identifier_char(c)) { if (!isdigit(c)) current_file->state = (c == '.') ? ipv4 : identifier; @@ -590,13 +648,13 @@ yylex() { put_back_char(c); current_file->state = scan; finish_identifier(id); - yylval.num = atoi(id->buffer); + yylval.num = strtol(id->buffer, (char**)0, 0); token = L_NUMBER; } break; case identifier: - if (identifier_char(c)) { + if (c != EOF && identifier_char(c)) { add_to_identifier(id, c); } else { put_back_char(c); @@ -615,7 +673,7 @@ yylex() { break; case ipv4: - if (identifier_char(c)) { + if (c != EOF && identifier_char(c)) { if (!isdigit(c)) { if (c != '.' || (id->flags & LEX_CONSECUTIVE_DOTS)) @@ -725,7 +783,7 @@ lexer_initialize() { special_chars['*'] = 1; id = (LexerIdentifier)memget(sizeof (struct lexer_identifier)); if (id == NULL) - panic("memget failed in init_once", NULL); + panic("memget failed in lexer_initialize", NULL); init_keywords(); import_all_constants(); lexer_initialized = 1; @@ -746,5 +804,6 @@ lexer_shutdown(void) { free_symbol_table(keyword_table); free_symbol_table(constants); memput(id, sizeof (struct lexer_identifier)); + id = NULL; lexer_initialized = 0; } diff --git a/contrib/bind/bin/named/ns_lexer.h b/contrib/bind/bin/named/ns_lexer.h index 3491df3..66c19f2 100644 --- a/contrib/bind/bin/named/ns_lexer.h +++ b/contrib/bind/bin/named/ns_lexer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -15,8 +15,8 @@ * SOFTWARE. */ -#ifndef NS_LEXER_H -#define NS_LEXER_H +#ifndef _NS_LEXER_H +#define _NS_LEXER_H /* * Note: <stdio.h> and "ns_parseutil.h" must be included @@ -42,4 +42,4 @@ void lexer_shutdown(void); extern symbol_table constants; -#endif /* NS_LEXER_H */ +#endif /* !_NS_LEXER_H */ diff --git a/contrib/bind/bin/named/ns_main.c b/contrib/bind/bin/named/ns_main.c index 194d368..1377098 100644 --- a/contrib/bind/bin/named/ns_main.c +++ b/contrib/bind/bin/named/ns_main.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)ns_main.c 4.55 (Berkeley) 7/1/91"; -static char rcsid[] = "$Id: ns_main.c,v 8.67 1998/04/28 19:17:46 halley Exp $"; +static const char sccsid[] = "@(#)ns_main.c 4.55 (Berkeley) 7/1/91"; +static const char rcsid[] = "$Id: ns_main.c,v 8.117 1999/11/08 23:01:38 vixie Exp $"; #endif /* not lint */ /* @@ -57,7 +57,7 @@ static char rcsid[] = "$Id: ns_main.c,v 8.67 1998/04/28 19:17:46 halley Exp $"; */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -75,10 +75,11 @@ static char rcsid[] = "$Id: ns_main.c,v 8.67 1998/04/28 19:17:46 halley Exp $"; #if !defined(lint) && !defined(SABER) char copyright[] = -"@(#) Copyright (c) 1986, 1989, 1990 The Regents of the University of California.\n\ - portions Copyright (c) 1993 Digital Equipment Corporation\n\ - portions Copyright (c) 1995, 1996, 1997 Internet Software Consortium\n\ - All rights reserved.\n"; +"@(#) Copyright (c) 1986, 1989, 1990 The Regents of the University of California.\n" +"portions Copyright (c) 1993 Digital Equipment Corporation\n" +"portions Copyright (c) 1995-1999 Internet Software Consortium\n" +"portions Copyright (c) 1999 Check Point Software Technologies\n" +"All rights reserved.\n"; #endif /* not lint */ /* @@ -94,6 +95,7 @@ char copyright[] = #include <sys/wait.h> #include <sys/ioctl.h> #include <sys/socket.h> +#include <sys/un.h> #ifdef SVR4 /* XXX */ # include <sys/sockio.h> #else @@ -139,21 +141,32 @@ char copyright[] = /* list of interfaces */ static LIST(struct _interface) iflist; static int iflist_initialized = 0; +static int iflist_dont_rescan = 0; - -static const int drbufsize = 8 * 1024, /* UDP rcv buf size */ - dsbufsize = 16 * 1024, /* UDP snd buf size */ - sbufsize = 16 * 1024; /* TCP snd buf size */ +static const int drbufsize = 32 * 1024, /* UDP rcv buf size */ + dsbufsize = 48 * 1024, /* UDP snd buf size */ + sbufsize = 16 * 1024, /* TCP snd buf size */ + nudptrans = 20, /* #/udps per select */ + listenmax = 50; static u_int16_t nsid_state; -static int needs; +static u_int16_t *nsid_pool; /* optional query id pool */ +static u_int16_t *nsid_vtable; /* optional shuffle table */ +static u_int32_t nsid_hash_state; +static u_int16_t nsid_a1, nsid_a2, nsid_a3; +static u_int16_t nsid_c1, nsid_c2, nsid_c3; +static u_int16_t nsid_state2; +static int nsid_algorithm; + +typedef void (*handler)(void); +static int needs = 0; +static handler handlers[main_need_num]; static struct qstream *sq_add(void); static int opensocket_d(interface *), opensocket_s(interface *); static void sq_query(struct qstream *), - dq_remove(interface *), - ns_handle_needs(void); + dq_remove(interface *); static int sq_dowrite(struct qstream *); static void use_desired_debug(void); static void stream_write(evContext, void *, int, int); @@ -162,7 +175,8 @@ static interface * if_find(struct in_addr, u_int16_t port); static int sq_here(struct qstream *); -static void stream_accept(evContext, void *, int, +static void deallocate_everything(void), + stream_accept(evContext, void *, int, const void *, int, const void *, int), stream_getlen(evContext, void *, int, int), @@ -175,14 +189,20 @@ static void stream_accept(evContext, void *, int, static void stream_send(evContext, void *, int, const void *, int, const void *, int); -static void init_signals(void); -static void set_signal_handler(int, SIG_FN (*)()); static int only_digits(const char *); +static void init_needs(void), + handle_need(void); + +#ifndef HAVE_CUSTOM +static void custom_init(void), + custom_shutdown(void); +#endif + static void usage() { fprintf(stderr, -"Usage: named [-d #] [-q] [-r] [-f] [-p port] [[-b|-c] configfile]\n"); +"Usage: named [-d #] [-q] [-r] [-v] [-f] [-p port] [[-b|-c] configfile]\n"); #ifdef CAN_CHANGE_ID fprintf(stderr, " [-u (username|uid)] [-g (groupname|gid)]\n"); @@ -202,20 +222,16 @@ static char bad_directory[] = "chdir failed for directory '%s': %s"; /*ARGSUSED*/ int main(int argc, char *argv[], char *envp[]) { - int n, udpcnt; - char *arg; - struct qstream *sp; - interface *ifp; - const int on = 1; - int rfd, size, len, debug_option; - char **argp, *p; + int n; + char *p; int ch; - FILE *fp; /* file descriptor for pid file */ struct passwd *pw; struct group *gr; -#ifdef HAVE_GETRUSAGE - struct rlimit rl; + +#ifdef _AUX_SOURCE + set42sig(); #endif + debugfile = savestr(_PATH_DEBUG, 1); user_id = getuid(); group_id = getgid(); @@ -231,7 +247,17 @@ main(int argc, char *argv[], char *envp[]) { (void) umask(022); - while ((ch = getopt(argc, argv, "b:c:d:g:p:t:u:w:qrf")) != EOF) { + /* Save argv[] before getopt() destroys it -- needed for execvp(). */ + saved_argv = malloc(sizeof(char *) * (argc + 1)); + INSIST(saved_argv != NULL); + for (n = 0; n < argc; n++) { + saved_argv[n] = strdup(argv[n]); + INSIST(saved_argv[n] != NULL); + } + saved_argv[argc] = NULL; + /* XXX we need to free() this for clean shutdowns. */ + + while ((ch = getopt(argc, argv, "b:c:d:g:p:t:u:vw:qrf")) != -1) { switch (ch) { case 'b': case 'c': @@ -291,6 +317,10 @@ main(int argc, char *argv[], char *envp[]) { chroot_dir = savestr(optarg, 1); break; + case 'v': + fprintf(stderr, "%s\n", Version); + exit(1); + #ifdef CAN_CHANGE_ID case 'u': user_name = savestr(optarg, 1); @@ -390,6 +420,10 @@ main(int argc, char *argv[], char *envp[]) { /* Establish global event context. */ evCreate(&ev); + /* Establish global resolver context. */ + res_ninit(&res); + res.options &= ~(RES_DEFNAMES | RES_DNSRCH | RES_RECURSE); + /* * Set up logging. */ @@ -416,14 +450,14 @@ main(int argc, char *argv[], char *envp[]) { use_desired_debug(); #endif + /* Perform system-dependent initialization */ + custom_init(); + + init_needs(); init_signals(); ns_notice(ns_log_default, "starting. %s", Version); - _res.options &= ~(RES_DEFNAMES | RES_DNSRCH | RES_RECURSE); - - nsid_init(); - /* * Initialize and load database. */ @@ -434,6 +468,8 @@ main(int argc, char *argv[], char *envp[]) { time(&boottime); resettime = boottime; + nsid_init(); + /* * Fork and go into background now that * we've done any slow initialization @@ -477,21 +513,46 @@ main(int argc, char *argv[], char *envp[]) { ns_panic(ns_log_security, 1, "setuid(%s): %s", user_name, strerror(errno)); ns_info(ns_log_security, "user = %s", user_name); + if (user_id != 0) + iflist_dont_rescan++; } #endif /* CAN_CHANGE_ID */ ns_notice(ns_log_default, "Ready to answer queries."); gettime(&tt); prime_cache(); - for (;;) { + while (!main_needs_exit) { evEvent event; - if (needs) - ns_handle_needs(); - INSIST_ERR(evGetNext(ev, &event, EV_WAIT) != -1); - INSIST_ERR(evDispatch(ev, event) != -1); + ns_debug(ns_log_default, 15, "main loop"); + if (needs != 0) { + /* Drain outstanding events; handlers ~block~. */ + while (evGetNext(ev, &event, EV_POLL) != -1) + INSIST_ERR(evDispatch(ev, event) != -1); + INSIST_ERR(errno == EINTR || errno == EWOULDBLOCK); + handle_need(); + } else if (evGetNext(ev, &event, EV_WAIT) != -1) { + INSIST_ERR(evDispatch(ev, event) != -1); + } else { + INSIST_ERR(errno == EINTR); + } } - /* NOTREACHED */ + ns_info(ns_log_default, "named shutting down"); +#ifdef BIND_UPDATE + dynamic_about_to_exit(); +#endif + if (server_options && server_options->pid_filename) + (void)unlink(server_options->pid_filename); + ns_logstats(ev, NULL, evNowTime(), evConsTime(0, 0)); + + if (NS_OPTION_P(OPTION_DEALLOC_ON_EXIT)) + deallocate_everything(); + else + shutdown_configuration(); + + /* Cleanup for system-dependent stuff */ + custom_shutdown(); + return (0); } @@ -508,7 +569,7 @@ stream_accept(evContext lev, void *uap, int rfd, interface *ifp = uap; struct qstream *sp; struct iovec iov; - int n, len; + int len, n; const int on = 1; #ifdef IP_OPTIONS /* XXX */ u_char ip_opts[IP_OPT_BUF_SIZE]; @@ -594,21 +655,6 @@ stream_accept(evContext lev, void *uap, int rfd, /* Condition the socket. */ -/* XXX clean up */ -#if 0 - if ((n = fcntl(rfd, F_GETFL, 0)) == -1) { - ns_info(ns_log_default, "fcntl(rfd, F_GETFL): %s", - strerror(errno)); - (void) close(rfd); - return; - } - if (fcntl(rfd, F_SETFL, n|PORT_NONBLOCK) == -1) { - ns_info(ns_log_default, "fcntl(rfd, NONBLOCK): %s", - strerror(errno)); - (void) close(rfd); - return; - } -#endif #ifndef CANNOT_SET_SNDBUF if (setsockopt(rfd, SOL_SOCKET, SO_SNDBUF, (char*)&sbufsize, sizeof sbufsize) < 0) { @@ -626,6 +672,19 @@ stream_accept(evContext lev, void *uap, int rfd, return; } + if ((n = fcntl(rfd, F_GETFL, 0)) == -1) { + ns_info(ns_log_default, "fcntl(rfd, F_GETFL): %s", + strerror(errno)); + (void) close(rfd); + return; + } + if (fcntl(rfd, F_SETFL, n|PORT_NONBLOCK) == -1) { + ns_info(ns_log_default, "fcntl(rfd, NONBLOCK): %s", + strerror(errno)); + (void) close(rfd); + return; + } + /* * We don't like IP options. Turn them off if the connection came in * with any. log this event since it usually indicates a security @@ -685,20 +744,23 @@ tcp_send(struct qinfo *qp) { ns_debug(ns_log_default, 1, "tcp_send"); if ((sp = sq_add()) == NULL) { - return(SERVFAIL); + return (SERVFAIL); } if ((sp->s_rfd = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) == -1) { sq_remove(sp); - return(SERVFAIL); + return (SERVFAIL); + } + if (sp->s_rfd > evHighestFD(ev)) { + sq_remove(sp); + return (SERVFAIL); } - if (sq_openw(sp, qp->q_msglen + INT16SZ) == -1) { sq_remove(sp); - return(SERVFAIL); + return (SERVFAIL); } if (sq_write(sp, qp->q_msg, qp->q_msglen) == -1) { sq_remove(sp); - return(SERVFAIL); + return (SERVFAIL); } if (setsockopt(sp->s_rfd, SOL_SOCKET, SO_KEEPALIVE, @@ -711,17 +773,14 @@ tcp_send(struct qinfo *qp) { sp->s_time = tt.tv_sec; /* last transaction time */ sp->s_refcnt = 1; sp->flags |= STREAM_DONE_CLOSE; - if (qp->q_fwd) - sp->s_from = qp->q_fwd->fwdaddr; - else - sp->s_from = qp->q_addr[qp->q_curaddr].ns_addr; + sp->s_from = qp->q_addr[qp->q_curaddr].ns_addr; if (evConnect(ev, sp->s_rfd, &sp->s_from, sizeof(sp->s_from), stream_send, sp, &sp->evID_c) == -1) { sq_remove(sp); return (SERVFAIL); } sp->flags |= STREAM_CONNECT_EV; - return(NOERROR); + return (NOERROR); } static void @@ -763,7 +822,8 @@ stream_write(evContext ctx, void *uap, int fd, int evmask) { if (sp->s_wbuf) { memput(sp->s_wbuf, sp->s_wbuf_end - sp->s_wbuf); - sp->s_wbuf = NULL; + sp->s_wbuf_send = sp->s_wbuf_free = NULL; + sp->s_wbuf_end = sp->s_wbuf = NULL; } (void) evDeselectFD(ev, sp->evID_w); sp->flags &= ~STREAM_WRITE_EV; @@ -811,6 +871,13 @@ stream_getlen(evContext lev, void *uap, int fd, int bytes) { */ sp->s_size = ns_get16(sp->s_temp); ns_debug(ns_log_default, 5, "stream message: %d bytes", sp->s_size); + if (sp->s_size < HFIXEDSZ) { + ns_error(ns_log_default, + "stream_getlen(%s): request too small", + sin_ntoa(sp->s_from)); + sq_remove(sp); + return; + } if (!(sp->flags & STREAM_MALLOC)) { sp->s_bufsize = 64*1024-1; /* maximum tcp message size */ @@ -834,7 +901,6 @@ stream_getlen(evContext lev, void *uap, int fd, int bytes) { static void stream_getmsg(evContext lev, void *uap, int fd, int bytes) { struct qstream *sp = uap; - int buflen, n; sp->flags &= ~STREAM_READ_EV; if (bytes == -1) { @@ -847,10 +913,12 @@ stream_getmsg(evContext lev, void *uap, int fd, int bytes) { gettime(&tt); sp->s_time = tt.tv_sec; - ns_debug(ns_log_default, 5, "sp %#x rfd %d size %d time %d next %#x", - sp, sp->s_rfd, sp->s_size, sp->s_time, sp->s_next); - ns_debug(ns_log_default, 5, "\tbufsize %d bytes %d", sp->s_bufsize, - bytes); + if (ns_wouldlog(ns_log_default,5)) { + ns_debug(ns_log_default, 5, "sp %#x rfd %d size %d time %d next %#x", + sp, sp->s_rfd, sp->s_size, sp->s_time, sp->s_next); + ns_debug(ns_log_default, 5, "\tbufsize %d bytes %d", sp->s_bufsize, + bytes); + } /* * Do we have enough memory for the query? If not, and if we have a @@ -882,12 +950,16 @@ datagram_read(evContext lev, void *uap, int fd, int evmask) { interface *ifp = uap; struct sockaddr_in from; int from_len = sizeof from; - int n; + int n, nudp; union { HEADER h; /* Force alignment of 'buf'. */ u_char buf[PACKETSZ+1]; } u; + tt = evTimeVal(evNowTime()); + nudp = 0; + + more: n = recvfrom(fd, (char *)u.buf, sizeof u.buf, 0, (struct sockaddr *)&from, &from_len); @@ -911,15 +983,6 @@ datagram_read(evContext lev, void *uap, int fd, int evmask) { * ignore them. */ return; - case EBADF: - case ENOTCONN: - case ENOTSOCK: - case EFAULT: - /* - * If one these happens, we're broken. - */ - ns_panic(ns_log_default, 1, "recvfrom: %s", - strerror(errno)); default: /* * An error we don't expect. Log it and press @@ -931,14 +994,14 @@ datagram_read(evContext lev, void *uap, int fd, int evmask) { } } -#ifndef BSD /* Handle bogosity on systems that need it. */ if (n == 0) return; -#endif - ns_debug(ns_log_default, 1, "datagram from %s, fd %d, len %d", - sin_ntoa(from), fd, n); + if (ns_wouldlog(ns_log_default, 1)) { + ns_debug(ns_log_default, 1, "datagram from %s, fd %d, len %d", + sin_ntoa(from), fd, n); + } if (n > PACKETSZ) { /* @@ -949,8 +1012,9 @@ datagram_read(evContext lev, void *uap, int fd, int evmask) { ns_debug(ns_log_default, 1, "truncated oversize UDP packet"); } - gettime(&tt); /* Keep 'tt' current. */ dispatch_message(u.buf, n, PACKETSZ, NULL, from, fd, ifp); + if (++nudp < nudptrans) + goto more; } static void @@ -961,8 +1025,35 @@ dispatch_message(u_char *msg, int msglen, int buflen, struct qstream *qsp, if (msglen < HFIXEDSZ) { ns_debug(ns_log_default, 1, "dropping undersize message"); + if (qsp) { + qsp->flags |= STREAM_DONE_CLOSE; + sq_done(qsp); + } return; } + + if (server_options->blackhole_acl != NULL && + ip_match_address(server_options->blackhole_acl, + from.sin_addr) == 1) { + ns_debug(ns_log_default, 1, + "dropping blackholed %s from %s", + hp->qr ? "response" : "query", + sin_ntoa(from)); + if (qsp) { + qsp->flags |= STREAM_DONE_CLOSE; + sq_done(qsp); + } + return; + } + + /* Drop UDP packets from port zero. They are invariable forged. */ + if (qsp == NULL && ntohs(from.sin_port) == 0) { + ns_notice(ns_log_security, + "dropping source port zero packet from %s", + sin_ntoa(from)); + return; + } + if (hp->qr) { ns_resp(msg, msglen, from, qsp); if (qsp) @@ -976,6 +1067,10 @@ dispatch_message(u_char *msg, int msglen, int buflen, struct qstream *qsp, ns_notice(ns_log_security, "refused query on non-query socket from %s", sin_ntoa(from)); + if (qsp) { + qsp->flags |= STREAM_DONE_CLOSE; + sq_done(qsp); + } /* XXX Send refusal here. */ } } @@ -986,17 +1081,24 @@ getnetconf(int periodic_scan) { struct ifreq ifreq; struct in_addr ina; interface *ifp; - char buf[32768], *cp, *cplim; - u_int32_t nm; + char *buf, *cp, *cplim; + static int bufsiz = 4095; time_t my_generation = time(NULL); - int s, cpsize; + int s, cpsize, n; int found; listen_info li; - u_int16_t port; ip_match_element ime; u_char *mask_ptr; struct in_addr mask; + if (iflist_initialized) { + if (iflist_dont_rescan) + return; + } else { + INIT_LIST(iflist); + iflist_initialized = 1; + } + ns_debug(ns_log_default, 1, "getnetconf(generation %lu)", (u_long)my_generation); @@ -1010,11 +1112,6 @@ getnetconf(int periodic_scan) { return; } - if (!iflist_initialized) { - INIT_LIST(iflist); - iflist_initialized = 1; - } - if (local_addresses != NULL) free_ip_match_list(local_addresses); local_addresses = new_ip_match_list(); @@ -1022,11 +1119,46 @@ getnetconf(int periodic_scan) { free_ip_match_list(local_networks); local_networks = new_ip_match_list(); - ifc.ifc_len = sizeof buf; - ifc.ifc_buf = buf; - if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) - ns_panic(ns_log_default, 1, "get interface configuration: %s", - strerror(errno)); + for (;;) { + buf = memget(bufsiz); + if (!buf) + ns_panic(ns_log_default, 1, + "memget(interface)", NULL); + ifc.ifc_len = bufsiz; + ifc.ifc_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(&ifc) >= 0) + break; +#else + if ((n = ioctl(s, SIOCGIFCONF, (char *)&ifc)) != -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 + * ifc.ifc_len is too near to the end of the + * buffer we will grow it just in case and + * retry. + */ + if (ifc.ifc_len + 2 * sizeof(ifreq) < bufsiz) + break; + } +#endif + if ((n == -1) && errno != EINVAL) + ns_panic(ns_log_default, 1, + "get interface configuration: %s", + strerror(errno)); + + if (bufsiz > 1000000) + ns_panic(ns_log_default, 1, + "get interface configuration: maximum buffer size exceeded"); + memput(buf, bufsiz); + bufsiz += 4096; + } ns_debug(ns_log_default, 2, "getnetconf: SIOCGIFCONF: ifc_len = %d", ifc.ifc_len); @@ -1035,7 +1167,7 @@ getnetconf(int periodic_scan) { cplim = buf + ifc.ifc_len; /* skip over if's with big ifr_addr's */ for (cp = buf; cp < cplim; cp += cpsize) { memcpy(&ifreq, cp, sizeof ifreq); -#if defined HAVE_SA_LEN +#ifdef HAVE_SA_LEN #ifdef FIX_ZERO_SA_LEN if (ifreq.ifr_addr.sa_len == 0) ifreq.ifr_addr.sa_len = 16; @@ -1228,6 +1360,7 @@ getnetconf(int periodic_scan) { } } close(s); + memput(buf, bufsiz); ns_debug(ns_log_default, 7, "local addresses:"); dprint_ip_match_list(ns_log_default, local_addresses, 2, "", ""); @@ -1270,6 +1403,23 @@ opensocket_d(interface *ifp) { strerror(errno)); return (-1); } + if (ifp->dfd > evHighestFD(ev)) { + ns_error(ns_log_default, "socket too high: %d", ifp->dfd); + close(ifp->dfd); + return (-1); + } + if ((n = fcntl(ifp->dfd, F_GETFL, 0)) == -1) { + ns_info(ns_log_default, "fcntl(ifp->dfd, F_GETFL): %s", + strerror(errno)); + (void) close(ifp->dfd); + return (-1); + } + if (fcntl(ifp->dfd, F_SETFL, n|PORT_NONBLOCK) == -1) { + ns_info(ns_log_default, "fcntl(ifp->dfd, NONBLOCK): %s", + strerror(errno)); + (void) close(ifp->dfd); + return (-1); + } #ifdef F_DUPFD /* XXX */ /* * Leave a space for stdio to work in. @@ -1350,6 +1500,11 @@ opensocket_s(interface *ifp) { strerror(errno)); return (-1); } + if (ifp->sfd > evHighestFD(ev)) { + ns_error(ns_log_default, "socket too high: %d", ifp->sfd); + close(ifp->sfd); + return (-1); + } #ifdef F_DUPFD /* XXX */ /* * Leave a space for stdio to work in. @@ -1386,7 +1541,7 @@ opensocket_s(interface *ifp) { sleep(30); goto again; } - if (evListen(ev, ifp->sfd, 5/*XXX*/, stream_accept, ifp, &ifp->evID_s) + if (evListen(ev, ifp->sfd, listenmax, stream_accept, ifp, &ifp->evID_s) == -1) { ns_error(ns_log_default, "evListen(sfd=%d): %s", ifp->sfd, strerror(errno)); @@ -1460,6 +1615,8 @@ opensocket_f() { if ((ds = socket(AF_INET, SOCK_DGRAM, 0)) < 0) ns_panic(ns_log_default, 1, "socket(SOCK_DGRAM): %s", strerror(errno)); + if (ds > evHighestFD(ev)) + ns_panic(ns_log_default, 1, "socket too high: %d", ds); if (setsockopt(ds, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on) != 0) { ns_notice(ns_log_default, "setsockopt(REUSEADDR): %s", @@ -1468,7 +1625,7 @@ opensocket_f() { } if (bind(ds, (struct sockaddr *)&server_options->query_source, sizeof server_options->query_source) < 0) - ns_panic(ns_log_default, 1, "opensocket_f: bind(%s): %s", + ns_panic(ns_log_default, 0, "opensocket_f: bind(%s): %s", sin_ntoa(server_options->query_source), strerror(errno)); @@ -1513,56 +1670,6 @@ setdebug(int new_debug) { #endif } -static SIG_FN -onhup(int sig) { - ns_need(MAIN_NEED_RELOAD); -} - -static SIG_FN -onintr(int sig) { - ns_need(MAIN_NEED_EXIT); -} - -static SIG_FN -setdumpflg(int sig) { - ns_need(MAIN_NEED_DUMP); -} - -#ifdef DEBUG -static SIG_FN -setIncrDbgFlg(int sig) { - desired_debug++; - ns_need(MAIN_NEED_DEBUG); -} - -static SIG_FN -setNoDbgFlg(int sig) { - desired_debug = 0; - ns_need(MAIN_NEED_DEBUG); -} -#endif /*DEBUG*/ - -#if defined(QRYLOG) && defined(SIGWINCH) -static SIG_FN -setQrylogFlg(int sig) { - ns_need(MAIN_NEED_QRYLOG); -} -#endif /*QRYLOG && SIGWINCH*/ - -static SIG_FN -setstatsflg(int sig) { - ns_need(MAIN_NEED_STATSDUMP); -} - -static SIG_FN -discard_pipe(int sig) { -#ifdef SIGPIPE_ONE_SHOT - int saved_errno = errno; - set_signal_handler(SIGPIPE, discard_pipe); - errno = saved_errno; -#endif -} - /* ** Routines for managing stream queue */ @@ -1601,7 +1708,8 @@ sq_remove(struct qstream *qp) { if (qp->s_wbuf != NULL) { memput(qp->s_wbuf, qp->s_wbuf_end - qp->s_wbuf); - qp->s_wbuf = NULL; + qp->s_wbuf_send = qp->s_wbuf_free = NULL; + qp->s_wbuf_end = qp->s_wbuf = NULL; } if (qp->flags & STREAM_MALLOC) memput(qp->s_buf, qp->s_bufsize); @@ -1655,7 +1763,7 @@ sq_flush(struct qstream *allbut) { */ int sq_openw(struct qstream *qs, int buflen) { -#ifdef SO_LINGER /* XXX */ +#ifdef DO_SO_LINGER /* XXX */ static const struct linger ll = { 1, 120 }; #endif @@ -1666,7 +1774,7 @@ sq_openw(struct qstream *qs, int buflen) { qs->s_wbuf_send = qs->s_wbuf; qs->s_wbuf_free = qs->s_wbuf; qs->s_wbuf_end = qs->s_wbuf + buflen; -#ifdef SO_LINGER /* XXX */ +#ifdef DO_SO_LINGER /* XXX */ /* kernels that map pages for IO end up failing if the pipe is full * at exit and we take away the final buffer. this is really a kernel * bug but it's harmless on systems that are not broken, so... @@ -1685,6 +1793,7 @@ sq_dowrite(struct qstream *qs) { if (qs->s_wbuf_free > qs->s_wbuf_send) { int n = write(qs->s_rfd, qs->s_wbuf_send, qs->s_wbuf_free - qs->s_wbuf_send); + INSIST(qs->s_wbuf != NULL); if (n < 0) { if (errno != EINTR && errno != EAGAIN #if (EWOULDBLOCK != EAGAIN) @@ -1831,8 +1940,10 @@ sq_done(struct qstream *sp) { struct iovec iov; if (sp->s_wbuf != NULL) { + INSIST(sp->s_wbuf_send == sp->s_wbuf_free); memput(sp->s_wbuf, sp->s_wbuf_end - sp->s_wbuf); - sp->s_wbuf = NULL; + sp->s_wbuf_send = sp->s_wbuf_free = NULL; + sp->s_wbuf_end = sp->s_wbuf = NULL; } if (sp->flags & STREAM_AXFR) ns_freexfr(sp); @@ -1950,7 +2061,6 @@ net_mask(struct in_addr ina) { */ int aIsUs(struct in_addr addr) { - interface *ifp; if (ina_hlong(addr) == INADDR_ANY || if_find(addr, 0) != NULL) return (1); @@ -1982,22 +2092,397 @@ if_find(struct in_addr addr, u_int16_t port) { * allocation scheme to make it a little harder to predict them. Note * that the resolver will need the same protection so the cleverness * should be put there rather than here; this is just an interface layer. + * + * This is true but ... most clients only send out a few queries, they + * use varying port numbers, and the queries aren't sent to the outside + * world which we know is full of spoofers. Doing a good job of randomizing + * ids may also be to expensive for each client. Queries forwarded by the + * server always come from the same port (unless you let 8.x pick a port + * and restart it periodically - maybe it should open several and use + * them randomly). The server sends out lots more queries, and if it's + * cache is corrupted, it has the potential to affect more clients. + * NOTE: - randomizing the ID or source port doesn't help a bit if the + * queries can be sniffed. + * -- DL + */ + +/* + * Allow the user to pick one of two ID randomization algorithms. + * + * The first algorithm is an adaptation of the sequence shuffling + * algorithm discovered by Carter Bays and S. D. Durham [ACM Trans. Math. + * Software 2 (1976), 59-64], as documented as Algorithm B in Chapter + * 3.2.2 in Volume 2 of Knuth's "The Art of Computer Programming". We use + * a randomly selected linear congruential random number generator with a + * modulus of 2^16, whose increment is a randomly picked odd number, and + * whose multiplier is picked from a set which meets the following + * criteria: + * Is of the form 8*n+5, which ensures "high potency" according to + * principle iii in the summary chapter 3.6. This form also has a + * gcd(a-1,m) of 4 which is good according to principle iv. + * + * Is between 0.01 and 0.99 times the modulus as specified by + * principle iv. + * + * Passes the spectral test "with flying colors" (ut >= 1) in + * dimensions 2 through 6 as calculated by Algorithm S in Chapter + * 3.3.4 and the ratings calculated by formula 35 in section E. + * + * Of the multipliers that pass this test, pick the set that is + * best according to the theoretical bounds of the serial + * correlation test. This was calculated using a simplified + * version of Knuth's Theorem K in Chapter 3.3.3. + * + * These criteria may not be important for this use, but we might as well + * pick from the best generators since there are so many possible ones and + * we don't have that many random bits to do the picking. + * + * We use a modulus of 2^16 instead of something bigger so that we will + * tend to cycle through all the possible IDs before repeating any, + * however the shuffling will perturb this somewhat. Theoretically there + * is no minimimum interval between two uses of the same ID, but in + * practice it seems to be >64000. + * + * Our adaptatation of Algorithm B mixes the hash state which has + * captured various random events into the shuffler to perturb the + * sequence. + * + * One disadvantage of this algorithm is that if the generator parameters + * were to be guessed, it would be possible to mount a limited brute force + * attack on the ID space since the IDs are only shuffled within a limited + * range. + * + * The second algorithm uses the same random number generator to populate + * a pool of 65536 IDs. The hash state is used to pick an ID from a window + * of 4096 IDs in this pool, then the chosen ID is swapped with the ID + * at the beginning of the window and the window position is advanced. + * This means that the interval between uses of the ID will be no less + * than 65536-4096. The ID sequence in the pool will become more random + * over time. + * + * For both algorithms, two more linear congruential random number generators + * are selected. The ID from the first part of algorithm is used to seed + * the first of these generators, and its output is used to seed the second. + * The strategy is use these generators as 1 to 1 hashes to obfuscate the + * properties of the generator used in the first part of either algorithm. + * + * The first algorithm may be suitable for use in a client resolver since + * its memory requirements are fairly low and it's pretty random out of + * the box. It is somewhat succeptible to a limited brute force attack, + * so the second algorithm is probably preferable for a longer running + * program that issues a large number of queries and has time to randomize + * the pool. + */ + +#define NSID_SHUFFLE_TABLE_SIZE 100 /* Suggested by Knuth */ +/* + * Pick one of the next 4096 IDs in the pool. + * There is a tradeoff here between randomness and how often and ID is reused. + */ +#define NSID_LOOKAHEAD 4096 /* Must be a power of 2 */ +#define NSID_SHUFFLE_ONLY 1 /* algorithm 1 */ +#define NSID_USE_POOL 2 /* algorithm 2 */ + +/* + * Keep a running hash of various bits of data that we'll use to + * stir the ID pool or perturb the ID generator + */ +void +nsid_hash(u_char *data, size_t len) { + /* + * Hash function similar to the one we use for hashing names. + * We don't fold case or toss the upper bit here, though. + * This hash doesn't do much interesting when fed binary zeros, + * so there may be a better hash function. + * This function doesn't need to be very strong since we're + * only using it to stir the pool, but it should be reasonably + * fast. + */ + while (len-- > 0) { + HASHROTATE(nsid_hash_state); + nsid_hash_state += *data++; + } +} + +/* + * Table of good linear congruential multipliers for modulus 2^16 + * in order of increasing serial correlation bounds (so trim from + * the end). */ +static const u_int16_t nsid_multiplier_table[] = { + 17565, 25013, 11733, 19877, 23989, 23997, 24997, 25421, + 26781, 27413, 35901, 35917, 35973, 36229, 38317, 38437, + 39941, 40493, 41853, 46317, 50581, 51429, 53453, 53805, + 11317, 11789, 12045, 12413, 14277, 14821, 14917, 18989, + 19821, 23005, 23533, 23573, 23693, 27549, 27709, 28461, + 29365, 35605, 37693, 37757, 38309, 41285, 45261, 47061, + 47269, 48133, 48597, 50277, 50717, 50757, 50805, 51341, + 51413, 51581, 51597, 53445, 11493, 14229, 20365, 20653, + 23485, 25541, 27429, 29421, 30173, 35445, 35653, 36789, + 36797, 37109, 37157, 37669, 38661, 39773, 40397, 41837, + 41877, 45293, 47277, 47845, 49853, 51085, 51349, 54085, + 56933, 8877, 8973, 9885, 11365, 11813, 13581, 13589, + 13613, 14109, 14317, 15765, 15789, 16925, 17069, 17205, + 17621, 17941, 19077, 19381, 20245, 22845, 23733, 24869, + 25453, 27213, 28381, 28965, 29245, 29997, 30733, 30901, + 34877, 35485, 35613, 36133, 36661, 36917, 38597, 40285, + 40693, 41413, 41541, 41637, 42053, 42349, 45245, 45469, + 46493, 48205, 48613, 50861, 51861, 52877, 53933, 54397, + 55669, 56453, 56965, 58021, 7757, 7781, 8333, 9661, + 12229, 14373, 14453, 17549, 18141, 19085, 20773, 23701, + 24205, 24333, 25261, 25317, 27181, 30117, 30477, 34757, + 34885, 35565, 35885, 36541, 37957, 39733, 39813, 41157, + 41893, 42317, 46621, 48117, 48181, 49525, 55261, 55389, + 56845, 7045, 7749, 7965, 8469, 9133, 9549, 9789, + 10173, 11181, 11285, 12253, 13453, 13533, 13757, 14477, + 15053, 16901, 17213, 17269, 17525, 17629, 18605, 19013, + 19829, 19933, 20069, 20093, 23261, 23333, 24949, 25309, + 27613, 28453, 28709, 29301, 29541, 34165, 34413, 37301, + 37773, 38045, 38405, 41077, 41781, 41925, 42717, 44437, + 44525, 44613, 45933, 45941, 47077, 50077, 50893, 52117, + 5293, 55069, 55989, 58125, 59205, 6869, 14685, 15453, + 16821, 17045, 17613, 18437, 21029, 22773, 22909, 25445, + 25757, 26541, 30709, 30909, 31093, 31149, 37069, 37725, + 37925, 38949, 39637, 39701, 40765, 40861, 42965, 44813, + 45077, 45733, 47045, 50093, 52861, 52957, 54181, 56325, + 56365, 56381, 56877, 57013, 5741, 58101, 58669, 8613, + 10045, 10261, 10653, 10733, 11461, 12261, 14069, 15877, + 17757, 21165, 23885, 24701, 26429, 26645, 27925, 28765, + 29197, 30189, 31293, 39781, 39909, 40365, 41229, 41453, + 41653, 42165, 42365, 47421, 48029, 48085, 52773, 5573, + 57037, 57637, 58341, 58357, 58901, 6357, 7789, 9093, + 10125, 10709, 10765, 11957, 12469, 13437, 13509, 14773, + 15437, 15773, 17813, 18829, 19565, 20237, 23461, 23685, + 23725, 23941, 24877, 25461, 26405, 29509, 30285, 35181, + 37229, 37893, 38565, 40293, 44189, 44581, 45701, 47381, + 47589, 48557, 4941, 51069, 5165, 52797, 53149, 5341, + 56301, 56765, 58581, 59493, 59677, 6085, 6349, 8293, + 8501, 8517, 11597, 11709, 12589, 12693, 13517, 14909, + 17397, 18085, 21101, 21269, 22717, 25237, 25661, 29189, + 30101, 31397, 33933, 34213, 34661, 35533, 36493, 37309, + 40037, 4189, 42909, 44309, 44357, 44389, 4541, 45461, + 46445, 48237, 54149, 55301, 55853, 56621, 56717, 56901, + 5813, 58437, 12493, 15365, 15989, 17829, 18229, 19341, + 21013, 21357, 22925, 24885, 26053, 27581, 28221, 28485, + 30605, 30613, 30789, 35437, 36285, 37189, 3941, 41797, + 4269, 42901, 43293, 44645, 45221, 46893, 4893, 50301, + 50325, 5189, 52109, 53517, 54053, 54485, 5525, 55949, + 56973, 59069, 59421, 60733, 61253, 6421, 6701, 6709, + 7101, 8669, 15797, 19221, 19837, 20133, 20957, 21293, + 21461, 22461, 29085, 29861, 30869, 34973, 36469, 37565, + 38125, 38829, 39469, 40061, 40117, 44093, 47429, 48341, + 50597, 51757, 5541, 57629, 58405, 59621, 59693, 59701, + 61837, 7061, 10421, 11949, 15405, 20861, 25397, 25509, + 25893, 26037, 28629, 28869, 29605, 30213, 34205, 35637, + 36365, 37285, 3773, 39117, 4021, 41061, 42653, 44509, + 4461, 44829, 4725, 5125, 52269, 56469, 59085, 5917, + 60973, 8349, 17725, 18637, 19773, 20293, 21453, 22533, + 24285, 26333, 26997, 31501, 34541, 34805, 37509, 38477, + 41333, 44125, 46285, 46997, 47637, 48173, 4925, 50253, + 50381, 50917, 51205, 51325, 52165, 52229, 5253, 5269, + 53509, 56253, 56341, 5821, 58373, 60301, 61653, 61973, + 62373, 8397, 11981, 14341, 14509, 15077, 22261, 22429, + 24261, 28165, 28685, 30661, 34021, 34445, 39149, 3917, + 43013, 43317, 44053, 44101, 4533, 49541, 49981, 5277, + 54477, 56357, 57261, 57765, 58573, 59061, 60197, 61197, + 62189, 7725, 8477, 9565, 10229, 11437, 14613, 14709, + 16813, 20029, 20677, 31445, 3165, 31957, 3229, 33541, + 36645, 3805, 38973, 3965, 4029, 44293, 44557, 46245, + 48917, 4909, 51749, 53709, 55733, 56445, 5925, 6093, + 61053, 62637, 8661, 9109, 10821, 11389, 13813, 14325, + 15501, 16149, 18845, 22669, 26437, 29869, 31837, 33709, + 33973, 34173, 3677, 3877, 3981, 39885, 42117, 4421, + 44221, 44245, 44693, 46157, 47309, 5005, 51461, 52037, + 55333, 55693, 56277, 58949, 6205, 62141, 62469, 6293, + 10101, 12509, 14029, 17997, 20469, 21149, 25221, 27109, + 2773, 2877, 29405, 31493, 31645, 4077, 42005, 42077, + 42469, 42501, 44013, 48653, 49349, 4997, 50101, 55405, + 56957, 58037, 59429, 60749, 61797, 62381, 62837, 6605, + 10541, 23981, 24533, 2701, 27333, 27341, 31197, 33805, + 3621, 37381, 3749, 3829, 38533, 42613, 44381, 45901, + 48517, 51269, 57725, 59461, 60045, 62029, 13805, 14013, + 15461, 16069, 16157, 18573, 2309, 23501, 28645, 3077, + 31541, 36357, 36877, 3789, 39429, 39805, 47685, 47949, + 49413, 5485, 56757, 57549, 57805, 58317, 59549, 62213, + 62613, 62853, 62933, 8909, 12941, 16677, 20333, 21541, + 24429, 26077, 26421, 2885, 31269, 33381, 3661, 40925, + 42925, 45173, 4525, 4709, 53133, 55941, 57413, 57797, + 62125, 62237, 62733, 6773, 12317, 13197, 16533, 16933, + 18245, 2213, 2477, 29757, 33293, 35517, 40133, 40749, + 4661, 49941, 62757, 7853, 8149, 8573, 11029, 13421, + 21549, 22709, 22725, 24629, 2469, 26125, 2669, 34253, + 36709, 41013, 45597, 46637, 52285, 52333, 54685, 59013, + 60997, 61189, 61981, 62605, 62821, 7077, 7525, 8781, + 10861, 15277, 2205, 22077, 28517, 28949, 32109, 33493, + 3685, 39197, 39869, 42621, 44997, 48565, 5221, 57381, + 61749, 62317, 63245, 63381, 23149, 2549, 28661, 31653, + 33885, 36341, 37053, 39517, 42805, 45853, 48997, 59349, + 60053, 62509, 63069, 6525, 1893, 20181, 2365, 24893, + 27397, 31357, 32277, 33357, 34437, 36677, 37661, 43469, + 43917, 50997, 53869, 5653, 13221, 16741, 17893, 2157, + 28653, 31789, 35301, 35821, 61613, 62245, 12405, 14517, + 17453, 18421, 3149, 3205, 40341, 4109, 43941, 46869, + 48837, 50621, 57405, 60509, 62877, 8157, 12933, 12957, + 16501, 19533, 3461, 36829, 52357, 58189, 58293, 63053, + 17109, 1933, 32157, 37701, 59005, 61621, 13029, 15085, + 16493, 32317, 35093, 5061, 51557, 62221, 20765, 24613, + 2629, 30861, 33197, 33749, 35365, 37933, 40317, 48045, + 56229, 61157, 63797, 7917, 17965, 1917, 1973, 20301, + 2253, 33157, 58629, 59861, 61085, 63909, 8141, 9221, + 14757, 1581, 21637, 26557, 33869, 34285, 35733, 40933, + 42517, 43501, 53653, 61885, 63805, 7141, 21653, 54973, + 31189, 60061, 60341, 63357, 16045, 2053, 26069, 33997, + 43901, 54565, 63837, 8949, 17909, 18693, 32349, 33125, + 37293, 48821, 49053, 51309, 64037, 7117, 1445, 20405, + 23085, 26269, 26293, 27349, 32381, 33141, 34525, 36461, + 37581, 43525, 4357, 43877, 5069, 55197, 63965, 9845, + 12093, 2197, 2229, 32165, 33469, 40981, 42397, 8749, + 10853, 1453, 18069, 21693, 30573, 36261, 37421, 42533 +}; +#define NSID_MULT_TABLE_SIZE \ + ((sizeof nsid_multiplier_table)/(sizeof nsid_multiplier_table[0])) void -nsid_init() { - nsid_state = res_randomid(); +nsid_init(void) { + struct timeval now; + pid_t mypid; + u_int16_t a1ndx, a2ndx, a3ndx, c1ndx, c2ndx, c3ndx; + int i; + + if (nsid_algorithm != 0) + return; + + gettimeofday(&now, NULL); + mypid = getpid(); + + /* Initialize the state */ + nsid_hash_state = 0; + nsid_hash((u_char *)&now, sizeof now); + nsid_hash((u_char *)&mypid, sizeof mypid); + + /* + * Select our random number generators and initial seed. + * We could really use more random bits at this point, + * but we'll try to make a silk purse out of a sows ear ... + */ + /* generator 1 */ + a1ndx = ((u_long) NSID_MULT_TABLE_SIZE * + (nsid_hash_state & 0xFFFF)) >> 16; + nsid_a1 = nsid_multiplier_table[a1ndx]; + c1ndx = (nsid_hash_state >> 9) & 0x7FFF; + nsid_c1 = 2*c1ndx + 1; + /* generator 2, distinct from 1 */ + a2ndx = ((u_long) (NSID_MULT_TABLE_SIZE - 1) * + ((nsid_hash_state >> 10) & 0xFFFF)) >> 16; + if (a2ndx >= a1ndx) + a2ndx++; + nsid_a2 = nsid_multiplier_table[a2ndx]; + c2ndx = nsid_hash_state % 32767; + if (c2ndx >= c1ndx) + c2ndx++; + nsid_c2 = 2*c2ndx + 1; + /* generator 3, distinct from 1 and 2 */ + a3ndx = ((u_long) (NSID_MULT_TABLE_SIZE - 2) * + ((nsid_hash_state >> 20) & 0xFFFF)) >> 16; + if (a3ndx >= a1ndx || a3ndx >= a2ndx) + a3ndx++; + if (a3ndx >= a1ndx && a3ndx >= a2ndx) + a3ndx++; + nsid_a3 = nsid_multiplier_table[a3ndx]; + c3ndx = nsid_hash_state % 32766; + if (c3ndx >= c1ndx || c3ndx >= c2ndx) + c3ndx++; + if (c3ndx >= c1ndx && c3ndx >= c2ndx) + c3ndx++; + nsid_c3 = 2*c3ndx + 1; + + nsid_state = ((nsid_hash_state >> 16) ^ (nsid_hash_state)) & 0xFFFF; + + /* Do the algorithm specific initialization */ + INSIST(server_options != NULL); + if (NS_OPTION_P(OPTION_USE_ID_POOL) == 0) { + /* Algorithm 1 */ + nsid_algorithm = NSID_SHUFFLE_ONLY; + nsid_vtable = memget(NSID_SHUFFLE_TABLE_SIZE * + (sizeof(u_int16_t)) ); + if (!nsid_vtable) + ns_panic(ns_log_default, 1, "memget(nsid_vtable)", + NULL); + for (i = 0; i < NSID_SHUFFLE_TABLE_SIZE; i++) { + nsid_vtable[i] = nsid_state; + nsid_state = (((u_long) nsid_a1 * nsid_state) + nsid_c1) + & 0xFFFF; + } + nsid_state2 = nsid_state; + } else { + /* Algorithm 2 */ + nsid_algorithm = NSID_USE_POOL; + nsid_pool = memget(0x10000 * (sizeof(u_int16_t))); + if (!nsid_pool) + ns_panic(ns_log_default, 1, "memget(nsid_pool)", NULL); + for (i = 0; ; i++) { + nsid_pool[i] = nsid_state; + nsid_state = (((u_long) nsid_a1 * nsid_state) + nsid_c1) & 0xFFFF; + if (i == 0xFFFF) + break; + } + } } +#define NSID_RANGE_MASK (NSID_LOOKAHEAD - 1) + +#define NSID_POOL_MASK 0xFFFF /* used to wrap the pool index */ + u_int16_t nsid_next() { - if (nsid_state == 65535) - nsid_state = 0; - else - nsid_state++; - return (nsid_state); + u_int16_t id, compressed_hash; + + compressed_hash = ((nsid_hash_state >> 16) ^ (nsid_hash_state)) & + 0xFFFF; + if (nsid_algorithm == NSID_SHUFFLE_ONLY) { + u_int16_t j; + + /* + * This is the original Algorithm B + * j = ((u_long) NSID_SHUFFLE_TABLE_SIZE * nsid_state2) + * >> 16; + * + * We'll perturb it with some random stuff ... + */ + j = ((u_long) NSID_SHUFFLE_TABLE_SIZE * + (nsid_state2 ^ compressed_hash)) >> 16; + nsid_state2 = id = nsid_vtable[j]; + nsid_state = (((u_long) nsid_a1 * nsid_state) + nsid_c1) & + 0xFFFF; + nsid_vtable[j] = nsid_state; + } else if (nsid_algorithm == NSID_USE_POOL) { + u_int16_t pick; + + pick = compressed_hash & NSID_RANGE_MASK; + id = nsid_pool[(nsid_state + pick) & NSID_POOL_MASK]; + if (pick != 0) { + /* Swap two IDs to stir the pool */ + nsid_pool[(nsid_state + pick) & NSID_POOL_MASK] = + nsid_pool[nsid_state]; + nsid_pool[nsid_state] = id; + } + + /* increment the base pointer into the pool */ + if (nsid_state == 65535) + nsid_state = 0; + else + nsid_state++; + } else + ns_panic(ns_log_default, 1, "Unknown ID algorithm", NULL); + + /* Now lets obfuscate ... */ + id = (((u_long) nsid_a2 * id) + nsid_c2) & 0xFFFF; + id = (((u_long) nsid_a3 * id) + nsid_c3) & 0xFFFF; + + return (id); } +/* Note: this function CAN'T deallocate the saved_argv[]. */ static void deallocate_everything(void) { FILE *f; @@ -2010,6 +2495,7 @@ deallocate_everything(void) { free_addinfo(); ns_shutdown(); dq_remove_all(); + db_lame_destroy(); if (local_addresses != NULL) free_ip_match_list(local_addresses); if (local_networks != NULL) @@ -2020,12 +2506,23 @@ deallocate_everything(void) { evDestroy(ev); if (conffile != NULL) freestr(conffile); + conffile = NULL; + if (debugfile != NULL) + freestr(debugfile); + debugfile = NULL; if (user_name != NULL) freestr(user_name); + user_name = NULL; if (group_name != NULL) freestr(group_name); + group_name = NULL; if (chroot_dir != NULL) freestr(chroot_dir); + chroot_dir = NULL; + if (nsid_pool != NULL) + memput(nsid_pool, 0x10000 * (sizeof(u_int16_t))); + nsid_pool = NULL; + irs_destroy(); if (f != NULL) { memstats(f); (void)fclose(f); @@ -2034,7 +2531,12 @@ deallocate_everything(void) { static void ns_exit(void) { - ns_info(ns_log_default, "named shutting down"); + main_needs_exit++; +} + +static void +ns_restart(void) { + ns_info(ns_log_default, "named restarting"); #ifdef BIND_UPDATE dynamic_about_to_exit(); #endif @@ -2043,16 +2545,18 @@ ns_exit(void) { ns_logstats(ev, NULL, evNowTime(), evConsTime(0, 0)); if (NS_OPTION_P(OPTION_DEALLOC_ON_EXIT)) deallocate_everything(); - exit(0); + else + shutdown_configuration(); + execvp(saved_argv[0], saved_argv); + abort(); } static void use_desired_debug(void) { #ifdef DEBUG sigset_t set; - int bad; - /* protect against race conditions by blocking debugging signals */ + /* Protect against race conditions by blocking debugging signals. */ if (sigemptyset(&set) < 0) { ns_error(ns_log_os, @@ -2086,73 +2590,76 @@ use_desired_debug(void) { #endif } -static void +void toggle_qrylog(void) { qrylog = !qrylog; ns_notice(ns_log_default, "query log %s\n", qrylog ?"on" :"off"); } -#ifdef BIND_NOTIFY static void -do_notify_after_load(void) { - evDo(ev, (const void *)notify_after_load); +wild(void) { + ns_panic(ns_log_default, 1, "wild need", NULL); } -#endif - + /* * This is a functional interface to the global needs and options. */ -static const struct need_handler { - int need; - void (*handler)(void); - } need_handlers[] = { - { MAIN_NEED_RELOAD, ns_reload }, - { MAIN_NEED_MAINT, ns_maint }, - { MAIN_NEED_ENDXFER, endxfer }, - { MAIN_NEED_ZONELOAD, loadxfer }, - { MAIN_NEED_DUMP, doadump }, - { MAIN_NEED_STATSDUMP, ns_stats }, - { MAIN_NEED_EXIT, ns_exit }, - { MAIN_NEED_QRYLOG, toggle_qrylog }, - { MAIN_NEED_DEBUG, use_desired_debug }, -#ifdef BIND_NOTIFY - { MAIN_NEED_NOTIFY, do_notify_after_load }, -#endif - { 0, NULL } - }; +static void +init_needs(void) { + int need; + + for (need = 0; need < main_need_num; need++) + handlers[need] = wild; + handlers[main_need_zreload] = ns_zreload; + handlers[main_need_reload] = ns_reload; + handlers[main_need_reconfig] = ns_reconfig; + handlers[main_need_endxfer] = endxfer; + handlers[main_need_zoneload] = loadxfer; + handlers[main_need_dump] = doadump; + handlers[main_need_statsdump] = ns_stats; + handlers[main_need_exit] = ns_exit; + handlers[main_need_qrylog] = toggle_qrylog; + handlers[main_need_debug] = use_desired_debug; + handlers[main_need_restart] = ns_restart; + handlers[main_need_reap] = reapchild; +} -void -ns_setoption(int option) { - ns_warning(ns_log_default, "used obsolete ns_setoption(%d)", option); +static void +handle_need(void) { + int need; + + ns_debug(ns_log_default, 15, "handle_need()"); + for (need = 0; need < main_need_num; need++) + if ((needs & (1 << need)) != 0) { + /* Turn off flag first, handlers ~turn~ it back on. */ + block_signals(); + needs &= ~(1 << need); + unblock_signals(); + (handlers[need])(); + return; + } + ns_panic(ns_log_default, 1, "handle_need() found no needs", NULL); } void -ns_need(int need) { - needs |= need; +ns_need(enum need need) { + block_signals(); + ns_need_unsafe(need); + unblock_signals(); } -int -ns_need_p(int need) { - return ((needs & need) != 0); +/* Note: this function should only be called with signals blocked. */ +void +ns_need_unsafe(enum need need) { + needs |= (1 << need); } -static void -ns_handle_needs() { - const struct need_handler *nhp; - - for (nhp = need_handlers; nhp->need && nhp->handler; nhp++) { - if ((needs & nhp->need) != 0) { - /* - * Turn off flag first, handler might turn it back on. - */ - needs &= ~nhp->need; - (*nhp->handler)(); - } - } +void +ns_setoption(int option) { + ns_warning(ns_log_default, "used obsolete ns_setoption(%d)", option); } - void writestream(struct qstream *sp, const u_char *msg, int msglen) { if (sq_openw(sp, msglen + INT16SZ) == -1) { @@ -2166,45 +2673,6 @@ writestream(struct qstream *sp, const u_char *msg, int msglen) { sq_writeh(sp, sq_flushw); } -static void -set_signal_handler(int sig, SIG_FN (*handler)()) { - struct sigaction sa; - - memset(&sa, 0, sizeof sa); - sa.sa_handler = handler; - if (sigemptyset(&sa.sa_mask) < 0) { - ns_error(ns_log_os, - "sigemptyset failed in set_signal_handler(%d): %s", - sig, strerror(errno)); - return; - } - if (sigaction(sig, &sa, NULL) < 0) - ns_error(ns_log_os, - "sigaction failed in set_signal_handler(%d): %s", - sig, strerror(errno)); -} - -static void -init_signals() { - set_signal_handler(SIGINT, setdumpflg); - set_signal_handler(SIGILL, setstatsflg); -#ifdef DEBUG - set_signal_handler(SIGUSR1, setIncrDbgFlg); - set_signal_handler(SIGUSR2, setNoDbgFlg); -#endif - set_signal_handler(SIGHUP, onhup); -#if defined(SIGWINCH) && defined(QRYLOG) /* XXX */ - set_signal_handler(SIGWINCH, setQrylogFlg); -#endif - set_signal_handler(SIGCHLD, reapchild); - set_signal_handler(SIGPIPE, discard_pipe); - set_signal_handler(SIGTERM, onintr); -#if defined(SIGXFSZ) /* XXX */ - /* Wierd DEC Hesiodism, harmless. */ - set_signal_handler(SIGXFSZ, onhup); -#endif -} - static int only_digits(const char *s) { if (*s == '\0') @@ -2216,3 +2684,54 @@ only_digits(const char *s) { } return (1); } +#if defined(__GNUC__) && defined(__BOUNDS_CHECKING_ON) + /* Use bounds checking malloc, etc. */ +void * +memget(size_t len) { + return (malloc(len)); +} + +void +memput(void *addr, size_t len) { + free(addr); +} + +int +meminit(size_t init_max_size, size_t target_size) { + return (0); +} + +void * +memget_debug(size_t size, const char *file, int line) { + void *ptr; + ptr = __memget(size); + 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(ptr, size); +} + +void +memstats(FILE *out) { + fputs("No memstats\n", out); +} +#endif + +#ifndef HAVE_CUSTOM +/* Standard implementation has nothing here */ +static void +custom_init(void) { + /* Noop. */ +} + +static void +custom_shutdown(void) { + /* Noop. */ +} +#endif diff --git a/contrib/bind/bin/named/ns_maint.c b/contrib/bind/bin/named/ns_maint.c index 75568ff..69a8fc3 100644 --- a/contrib/bind/bin/named/ns_maint.c +++ b/contrib/bind/bin/named/ns_maint.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)ns_maint.c 4.39 (Berkeley) 3/2/91"; -static char rcsid[] = "$Id: ns_maint.c,v 8.39 1998/04/14 00:34:39 halley Exp $"; +static const char sccsid[] = "@(#)ns_maint.c 4.39 (Berkeley) 3/2/91"; +static const char rcsid[] = "$Id: ns_maint.c,v 8.95 1999/10/13 16:39:09 vixie Exp $"; #endif /* not lint */ /* @@ -57,7 +57,7 @@ static char rcsid[] = "$Id: ns_maint.c,v 8.39 1998/04/14 00:34:39 halley Exp $"; */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -73,6 +73,26 @@ static char rcsid[] = "$Id: ns_maint.c,v 8.39 1998/04/14 00:34:39 halley Exp $"; * SOFTWARE. */ +/* + * Portions Copyright (c) 1999 by Check Point Software Technologies, 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, and that + * the name of Check Point Software Technologies Incorporated 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 CHECK POINT SOFTWARE TECHNOLOGIES + * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED + * 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/param.h> @@ -80,11 +100,13 @@ static char rcsid[] = "$Id: ns_maint.c,v 8.39 1998/04/14 00:34:39 halley Exp $"; #include <sys/socket.h> #include <sys/wait.h> #include <sys/stat.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/inet.h> #include <arpa/nameser.h> +#include <assert.h> #include <errno.h> #include <signal.h> #include <resolv.h> @@ -99,25 +121,25 @@ static char rcsid[] = "$Id: ns_maint.c,v 8.39 1998/04/14 00:34:39 halley Exp $"; #include <isc/logging.h> #include <isc/memcluster.h> +#include <isc/dst.h> + #include "port_after.h" #include "named.h" -static int xfers_running, /* # of xfers running */ - xfers_deferred, /* # of needed xfers not run yet */ - qserials_running, - nxfers(struct zoneinfo *, int), +static int nxfers(struct zoneinfo *, int), bottom_of_zone(struct databuf *, int); static void startxfer(struct zoneinfo *), abortxfer(struct zoneinfo *), - addxfer(struct zoneinfo *), tryxfer(void), purge_z_2(struct hashbuf *, int); -#define qserial_qfull() (qserials_running == MAXQSERIAL) +#ifndef HAVE_SPAWNXFER +static pid_t spawnxfer(char **, struct zoneinfo *); +#endif -static time_t stats_time; +static time_t stats_time; /* Redundant ??? XXX ogud */ /* State of all running zone transfers */ static struct { @@ -132,23 +154,6 @@ static struct { /* - * Perform maintenance on all zones that need it. - */ -void -ns_maint() { - struct zoneinfo *zp; - int zonenum, deleted; - - gettime(&tt); - - ns_debug(ns_log_maint, 1, "ns_maint()"); - - for (zp = zones, zonenum = 0; zp < &zones[nzones]; zp++, zonenum++) - zone_maint(zp); - ns_debug(ns_log_maint, 1, "exit ns_maint()"); -} - -/* * Perform routine zone maintenance. */ void @@ -173,10 +178,16 @@ zone_maint(struct zoneinfo *zp) { #endif if (zp->z_serial != 0 && ((zp->z_lastupdate+zp->z_expire) < (u_int32_t)tt.tv_sec)) { + /* calls purge_zone */ + do_reload(zp->z_origin, zp->z_type, zp->z_class, 0); + /* reset zone state */ + zp->z_flags &= ~Z_AUTH; + zp->z_refresh = INIT_REFRESH; + zp->z_retry = INIT_REFRESH; zp->z_serial = 0; - /* XXX should we clear Z_AUTH here? */ } - if (zp->z_flags & (Z_NEED_RELOAD|Z_NEED_XFER|Z_QSERIAL)) { + if ((zp->z_flags & (Z_NEED_RELOAD|Z_NEED_XFER|Z_QSERIAL)) != 0) + { ns_retrytime(zp, tt.tv_sec); break; } @@ -190,12 +201,26 @@ zone_maint(struct zoneinfo *zp) { zp->z_time = tt.tv_sec + 30; break; } - qserial_query(zp); + /* + * If we don't have the zone loaded or dialup is off + * or we attempted a qserial_query before and the queue was + * full attempt to verify / load the zone. + */ + if ((zp->z_serial == 0) || (zp->z_flags & Z_NEED_QSERIAL) || + (zp->z_dialup == zdialup_no) || + (zp->z_dialup == zdialup_use_default && + NS_OPTION_P(OPTION_NODIALUP))) + qserial_query(zp); + else { + ns_info(ns_log_default, "Suppressed qserial_query(%s)", + *(zp->z_origin) ? zp->z_origin : "."); + ns_refreshtime(zp, tt.tv_sec); + } break; #ifdef BIND_UPDATE case Z_PRIMARY: - if (! (zp->z_flags & Z_DYNAMIC)) + if ((zp->z_flags & Z_DYNAMIC) == 0) break; if (tt.tv_sec >= zp->z_soaincrtime && zp->z_soaincrintvl > 0 && @@ -214,7 +239,7 @@ zone_maint(struct zoneinfo *zp) { if (tt.tv_sec >= zp->z_dumptime && zp->z_dumpintvl > 0 && zp->z_flags & Z_NEED_DUMP) { - if (zonedump(zp) < 0) { + if (zonedump(zp, ISNOTIXFR) < 0) { /* Try again later. */ ns_error(ns_log_maint, "zone dump for '%s' failed, rescheduling", @@ -222,6 +247,8 @@ zone_maint(struct zoneinfo *zp) { zp->z_dumptime = 0; (void)schedule_dump(zp); } + if (zp->z_maintain_ixfr_base) + ixfr_log_maint(zp); } break; #endif /* BIND_UPDATE */ @@ -249,11 +276,18 @@ do_zone_maint(evContext ctx, void *uap, struct timespec due, ns_debug(ns_log_maint, 1, "do_zone_maint for zone %s (class %s)", zti->name, p_class(zti->class)); - zp = find_zone(zti->name, zti->type, zti->class); + zp = find_zone(zti->name, zti->class); if (zp == NULL) { ns_error(ns_log_maint, "do_zone_maint: %s zone '%s' (class %s) is not authoritative", - zoneTypeString(zp), zti->name, + zoneTypeString(zti->type), zti->name, + p_class(zti->class)); + return; + } + if (zp->z_type != zti->type) { + ns_error(ns_log_maint, + "do_zone_maint: %s zone '%s' (class %s) has changed its type", + zoneTypeString(zti->type), zti->name, p_class(zti->class)); return; } @@ -270,13 +304,12 @@ do_zone_maint(evContext ctx, void *uap, struct timespec due, void sched_zone_maint(struct zoneinfo *zp) { time_t next_maint = (time_t)0; - char *zone_name; ztimer_info zti; if (zp->z_time != 0) next_maint = zp->z_time; #ifdef BIND_UPDATE - if (zp->z_type == z_master && (zp->z_flags & Z_DYNAMIC)) { + if (zp->z_type == z_master && (zp->z_flags & Z_DYNAMIC) != 0) { if (zp->z_soaincrintvl > 0 && (next_maint == 0 || next_maint > zp->z_soaincrtime)) next_maint = zp->z_soaincrtime; @@ -363,10 +396,46 @@ ns_cleancache(evContext ctx, void *uap, gettime(&tt); INSIST(uap == NULL); deleted = clean_cache(hashtab, 0); - ns_info(ns_log_maint, "Cleaned cache of %d RR%s", + ns_info(ns_log_maint, "Cleaned cache of %d RRset%s", deleted, (deleted==1) ? "" : "s"); } +void +ns_heartbeat(evContext ctx, void *uap, struct timespec due, + struct timespec inter) +{ + struct zoneinfo *zp; + + gettime(&tt); + INSIST(uap == NULL); + + for (zp = zones; zp < &zones[nzones]; zp++) { + enum zonetype zt = zp->z_type; + + if ((zt == z_nil) || + (zp->z_dialup == zdialup_no) || + (zp->z_dialup == zdialup_use_default && + NS_OPTION_P(OPTION_NODIALUP))) + continue; +#ifdef BIND_NOTIFY + if ((zp->z_notify == znotify_no) || + ((zp->z_notify == znotify_use_default) && + NS_OPTION_P(OPTION_NONOTIFY))) + continue; +#endif + if ((zt == z_slave || zt == z_stub) && + (zp->z_flags & + (Z_NEED_RELOAD|Z_NEED_XFER|Z_QSERIAL|Z_XFER_RUNNING) + ) == 0) { + ns_info(ns_log_default, + "Heartbeat: qserial \"%s\"", + *(zp->z_origin) ? zp->z_origin : "."); + qserial_query(zp); + } + } +} + + /* * Mark a zone "up to date" after named-xfer tells us this or we * discover it through the qserial_*() logic. @@ -418,57 +487,131 @@ qserial_query(struct zoneinfo *zp) { ns_debug(ns_log_default, 1, "qserial_query(%s)", zp->z_origin); - if (qserial_qfull()) { + if (qserials_running >= server_options->serial_queries) { qserial_retrytime(zp, tt.tv_sec); + zp->z_flags |= Z_NEED_QSERIAL; return; } qp = sysquery(zp->z_origin, zp->z_class, T_SOA, - zp->z_addr, zp->z_addrcnt, QUERY); - if (!qp) { - ns_info(ns_log_default, "qserial_query(%s): sysquery FAILED", - zp->z_origin); + zp->z_addr, zp->z_addrcnt, + ntohs(zp->z_port) ? zp->z_port : ns_port, + QUERY); + if (qp == NULL) { + ns_debug(ns_log_default, 1, + "qserial_query(%s): sysquery FAILED", + zp->z_origin); /* XXX - this is bad, we should do something */ qserial_retrytime(zp, tt.tv_sec); + zp->z_flags |= Z_NEED_QSERIAL; return; } qp->q_flags |= Q_ZSERIAL; qp->q_zquery = zp; zp->z_flags |= Z_QSERIAL; - zp->z_xaddr = inaddr_any; + zp->z_flags &= ~Z_NEED_QSERIAL; + zp->z_xaddrcnt = 0; ns_refreshtime(zp, tt.tv_sec); qserials_running++; ns_debug(ns_log_default, 1, "qserial_query(%s) QUEUED", zp->z_origin); } +static int +qserv_compare(const void *a, const void *b) { + const struct qserv *qs1 = a, *qs2 = b; + u_int32_t s1 = qs1->serial, s2 = qs2->serial; + + /* Note that we sort the "best" serial numbers to the front. */ + if (s1 == s2) + return (0); + if (s1 == 0) + return (-1); + if (s2 == 0) + return (1); + if (!SEQ_GT(s1, s2)) + return (1); + assert(SEQ_GT(s1, s2)); + return (-1); +} + void -qserial_answer(struct qinfo *qp, u_int32_t serial, struct sockaddr_in from) { +qserial_answer(struct qinfo *qp) { struct zoneinfo *zp = qp->q_zquery; + struct qserv *qs = NULL; + u_int32_t serial = 0; + int n, cnt = 0; - ns_debug(ns_log_default, 1, "qserial_answer(%s, %u)", zp->z_origin, - serial); + /* Take this query out of the global quotas. */ zp->z_flags &= ~Z_QSERIAL; qp->q_flags &= ~Q_ZSERIAL; /* keeps us from being called twice */ qserials_running--; + + /* Find best serial among those returned. */ + for (n = 0; n < qp->q_naddr; n++) { + qs = &qp->q_addr[n]; + ns_debug(ns_log_default, 1, "qserial_answer(%s): [%s] -> %lu", + zp->z_origin, inet_ntoa(qs->ns_addr.sin_addr), + qs->serial); + /* Don't consider serials which weren't set by a response. */ + if (qs->serial == 0) + continue; + /* Count valid answers. */ + cnt++; + /* Remove from consideration serials which aren't "better." */ + if (zp->z_serial != 0 && !SEQ_GT(qs->serial, zp->z_serial)) { + if (serial == 0 && qs->serial == zp->z_serial) + serial = qs->serial; + + if (qs->serial != zp->z_serial) + ns_notice(ns_log_xfer_in, + "Zone \"%s\" (%s) SOA serial# (%lu) rcvd from [%s] is < ours (%lu)%s", + zp->z_origin, p_class(zp->z_class), + qs->serial, + inet_ntoa(qs->ns_addr.sin_addr), + zp->z_serial, qp->q_naddr != 1 ? + ": skipping" : ""); + qs->serial = 0; + continue; + } + if (serial == 0 || SEQ_GT(qs->serial, serial)) + serial = qs->serial; + } + + /* If we have an existing serial number, then sort by "better." */ + if (zp->z_serial != 0) { + qsort(qp->q_addr, qp->q_naddr, sizeof(struct qserv), + qserv_compare); + for (n = 0; n < qp->q_naddr; n++) { + qs = &qp->q_addr[n]; + ns_debug(ns_log_default, 1, + "qserial_answer after sort: [%s] -> %lu", + inet_ntoa(qs->ns_addr.sin_addr), + qs->serial); + } + } + + /* Now see about kicking off an inbound transfer. */ if (serial == 0) { - /* An error occurred, or the query timed out. */ - ns_info(ns_log_default, "Err/TO getting serial# for \"%s\"", - zp->z_origin); + /* An error occurred, or the all queries timed out. */ + if (qp->q_naddr != cnt) + ns_info(ns_log_xfer_in, + "Err/TO getting serial# for \"%s\"", + zp->z_origin); addxfer(zp); - } else if (SEQ_GT(serial, zp->z_serial) || !zp->z_serial) { - ns_debug(ns_log_default, 1, + } else if (zp->z_serial == 0 || SEQ_GT(serial, zp->z_serial)) { + ns_debug(ns_log_xfer_in, 1, "qserial_answer: zone is out of date"); - zp->z_xaddr = from.sin_addr; /* don't use qp->q_from */ - addxfer(zp); - } else if (SEQ_GT(zp->z_serial, serial)) { - if (!haveComplained((u_long)zp, (u_long)"went backward")) { - ns_notice(ns_log_default, - "Zone \"%s\" (class %d) SOA serial# (%u) rcvd from [%s] is < ours (%u)", - zp->z_origin, zp->z_class, serial, - inet_ntoa(from.sin_addr), zp->z_serial); + /* Use all servers whose serials are better than ours. */ + zp->z_xaddrcnt = 0; + for (n = 0; n < qp->q_naddr; n++) { + qs = &qp->q_addr[n]; + if (qs->serial != 0) + zp->z_xaddr[zp->z_xaddrcnt++] = + qs->ns_addr.sin_addr; } - } else { - ns_debug(ns_log_default, 1, + addxfer(zp); + } else if (zp->z_serial == serial) { + ns_debug(ns_log_xfer_in, 1, "qserial_answer: zone serial is still OK"); markUpToDate(zp); sched_zone_maint(zp); @@ -476,34 +619,86 @@ qserial_answer(struct qinfo *qp, u_int32_t serial, struct sockaddr_in from) { } /* - * Start an asynchronous zone transfer for a zone. - * Depends on current time being in tt. - * Caller must do sched_zone_maint(zp) after startxfer returns. + * Writes TSIG key info for an address to a file, optionally opening it first. + */ +static int +write_tsig_info(struct in_addr addr, char *name, int *fd, int creat_failed) { + server_info si; + DST_KEY *dst_key; + int tsig_fd = *fd; + char tsig_str[1024], secret_buf64[172]; + u_char secret_buf[128]; + int secret_len; + + si = find_server(addr); + if (si == NULL || si->key_list == NULL || si->key_list->first == NULL) + return(0); + dst_key = si->key_list->first->key; + if (tsig_fd < 0 && creat_failed == 0) { + *fd = tsig_fd = creat(name, S_IRUSR); + if (tsig_fd < 0) { + ns_warning(ns_log_default, + "write_tsig_info: creat(%s) for TSIG info failed", + name); + return(-1); + } + } + if (creat_failed != 0) + return(-1); + memset(secret_buf, 0, sizeof(secret_buf)); + secret_len = dst_key_to_buffer(dst_key, secret_buf, sizeof(secret_buf)); + b64_ntop(secret_buf, secret_len, secret_buf64, sizeof(secret_buf64)); + sprintf(tsig_str, "%s\n%s\n%d\n%s\n", + inet_ntoa(addr), dst_key->dk_key_name, dst_key->dk_alg, + secret_buf64); + write(tsig_fd, tsig_str, strlen(tsig_str)); + return (0); +} + +/* + * Start an asynchronous zone transfer for a zone. Depends on current time + * being in tt. Caller must do a sched_zone_maint(zp) after we return. */ static void startxfer(struct zoneinfo *zp) { - char *argv[NSMAX + 20], argv_ns[NSMAX][MAXDNAME]; - int argc = 0, argc_ns = 0, pid, i; + char *argv[NSMAX*2 + 20], argv_ns[NSMAX][MAXDNAME]; + int argc = 0, argc_ns = 0, i; + pid_t pid; u_int cnt; char debug_str[10]; char serial_str[10]; char port_str[10]; char class_str[10]; char src_str[20]; + int tsig_fd = -1; + char tsig_name[MAXPATHLEN+1], *s; + int tsig_ret = 0; - ns_debug(ns_log_default, 1, "startxfer() %s", zp->z_origin); + ns_debug(ns_log_default, 1, "startxfer() %s", + zp->z_origin[0] != '\0' ? zp->z_origin : "."); argv[argc++] = server_options->named_xfer; argv[argc++] = "-z"; argv[argc++] = zp->z_origin; argv[argc++] = "-f"; argv[argc++] = zp->z_source; - argv[argc++] = "-s"; - sprintf(serial_str, "%u", zp->z_serial); - argv[argc++] = serial_str; - if (zp->z_axfr_src.s_addr != 0) { +#ifdef BIND_IXFR + if (zp->z_ixfr_tmp) { + argv[argc++] = "-i"; + argv[argc++] = zp->z_ixfr_tmp; + } +#endif + if (zp->z_serial != 0) { + argv[argc++] = "-s"; + sprintf(serial_str, "%u", zp->z_serial); + argv[argc++] = serial_str; + } + if (zp->z_axfr_src.s_addr != 0 || + server_options->axfr_src.s_addr != 0) { argv[argc++] = "-x"; - argv[argc++] = strcpy(src_str, inet_ntoa(zp->z_axfr_src)); + argv[argc++] = strcpy(src_str, inet_ntoa( + (zp->z_axfr_src.s_addr != 0) ? zp->z_axfr_src : + server_options->axfr_src)); } argv[argc++] = "-C"; sprintf(class_str, "%d", zp->z_class); @@ -511,8 +706,14 @@ startxfer(struct zoneinfo *zp) { if (zp->z_flags & Z_SYSLOGGED) argv[argc++] = "-q"; argv[argc++] = "-P"; - sprintf(port_str, "%d", ns_port); + sprintf(port_str, "%d", ntohs(zp->z_port) != 0 ? zp->z_port : ns_port); argv[argc++] = port_str; + argv[argc++] = "-T"; + sprintf(tsig_name, "%s.%d", zp->z_origin, getpid()); + s = tsig_name; + while ((s = strchr(s, '/')) != NULL) + *s = '_'; + argv[argc++] = tsig_name; #ifdef STUBS if (zp->z_type == Z_STUB) argv[argc++] = "-S"; @@ -531,40 +732,45 @@ startxfer(struct zoneinfo *zp) { } #endif - if (ina_hlong(zp->z_xaddr) != INADDR_ANY) { - /* - * Address was specified by the qserial logic, use it - * first. - */ - if (aIsUs(zp->z_xaddr) && - !haveComplained((u_long)zp, (u_long)startxfer)) { - ns_notice(ns_log_default, - "attempted to fetch zone %s from self (%s)", - zp->z_origin, inet_ntoa(zp->z_xaddr)); - } else - argv[argc++] = strcpy(argv_ns[argc_ns++], - inet_ntoa(zp->z_xaddr)); + if (zp->z_xaddrcnt == 0) { + for (zp->z_xaddrcnt = 0; + zp->z_xaddrcnt < zp->z_addrcnt; + zp->z_xaddrcnt++) + zp->z_xaddr[zp->z_xaddrcnt] = + zp->z_addr[zp->z_xaddrcnt]; } /* * Copy the server ip addresses into argv, after converting - * to ascii and saving the static inet_ntoa result. Skip zp->z_xaddr - * if seen. + * to ascii and saving the static inet_ntoa result. + * Also, send TSIG key info into a file for the child. */ - for (cnt = 0; cnt < zp->z_addrcnt; cnt++) { + for (cnt = 0; cnt < zp->z_xaddrcnt; cnt++) { struct in_addr a; - a = zp->z_addr[cnt]; - if (ina_equal(a, zp->z_xaddr)) - continue; - if (aIsUs(a) && - !haveComplained((u_long)zp, (u_long)startxfer)) { - ns_notice(ns_log_default, - "attempted to fetch zone %s from self (%s)", - zp->z_origin, inet_ntoa(a)); + a = zp->z_xaddr[cnt]; + if (aIsUs(a) && ns_port == zp->z_port) { + if (!haveComplained((u_long)zp, (u_long)startxfer)) + ns_notice(ns_log_default, + "attempted to fetch zone %s from self (%s)", + zp->z_origin, inet_ntoa(a)); continue; } argv[argc++] = strcpy(argv_ns[argc_ns++], inet_ntoa(a)); +#ifdef BIND_IXFR + if (zp->z_ixfr_tmp != NULL) { + server_info si = find_server(a); + + if (si != NULL && + (si->flags & SERVER_INFO_SUPPORT_IXFR) != 0) + argv[argc++] = "ixfr"; + else + argv[argc++] = "axfr"; + } +#endif + tsig_ret = write_tsig_info(a, tsig_name, &tsig_fd, tsig_ret); } + if (tsig_fd > 0) + close(tsig_fd); argv[argc] = NULL; @@ -594,26 +800,21 @@ startxfer(struct zoneinfo *zp) { #endif /* DEBUG */ gettime(&tt); - for (i = 0; i < MAX_XFERS_RUNNING; i++) { - if (xferstatus[i].xfer_pid == 0) { - xferstatus[i].xfer_state = XFER_RUNNING; + for (i = 0; i < MAX_XFERS_RUNNING; i++) + if (xferstatus[i].xfer_pid == 0) break; - } - } - if ((pid = vfork()) == -1) { - ns_error(ns_log_default, "xfer vfork: %s", strerror(errno)); + if (i == MAX_XFERS_RUNNING) { + ns_warning(ns_log_default, + "startxfer: too many xfers running"); zp->z_time = tt.tv_sec + 10; + (void)nxfers(zp, -1); return; } - - if (pid == 0) { - /* Child. */ - execv(server_options->named_xfer, argv); - ns_error(ns_log_default, "can't exec %s: %s", - server_options->named_xfer, strerror(errno)); - _exit(XFER_FAIL); /* Avoid duplicate buffer flushes. */ - } - /* Parent. */ + + if ((pid = spawnxfer(argv, zp)) == -1) + unlink(tsig_name); + + xferstatus[i].xfer_state = XFER_RUNNING; xferstatus[i].xfer_pid = pid; /* XXX - small race condition here if we * can't hold signals */ ns_debug(ns_log_default, 1, "started xfer child %d", pid); @@ -628,18 +829,20 @@ startxfer(struct zoneinfo *zp) { } const char * -zoneTypeString(const struct zoneinfo *zp) { +zoneTypeString(u_int type) { static char ret[sizeof "(4294967296?)"]; /* 2^32 */ - switch (zp->z_type) { + switch (type) { case Z_MASTER: return ("master"); case Z_SLAVE: return ("slave"); #ifdef STUBS case Z_STUB: return ("stub"); #endif + case Z_HINT: return ("hint"); case Z_CACHE: return ("cache"); + case Z_FORWARD: return ("forward"); default: - sprintf(ret, "(%u?)", (u_int32_t)zp->z_type); + sprintf(ret, "(%u?)", type); return (ret); } } @@ -660,7 +863,7 @@ printzoneinfo(int zonenum, int category, int level) { ns_debug(category, level, "zone %d: %s, class %s, type %s", zonenum, zp->z_origin[0] ? zp->z_origin : ".", - p_class(zp->z_class), zoneTypeString(zp)); + p_class(zp->z_class), zoneTypeString(zp->z_type)); if (zp->z_source) ns_debug(category, level, "\tsource %s", zp->z_source); ns_debug(category, level, "\tflags %lx, serial %u, minimum %u", @@ -674,7 +877,7 @@ printzoneinfo(int zonenum, int category, int level) { else ns_debug(category, level, "\tz_time %lu", zp->z_time); #ifdef BIND_UPDATE - if (zp->z_type == z_master && zp->z_flags & Z_DYNAMIC) { + if (zp->z_type == z_master && (zp->z_flags & Z_DYNAMIC) != 0) { ns_debug(category, level, "\tdumpintvl %lu, soaincrintvl %lu deferupdcnt %lu", zp->z_dumpintvl, zp->z_soaincrintvl, @@ -700,13 +903,58 @@ printzoneinfo(int zonenum, int category, int level) { } #endif /* DEBUG */ +/* + * Remove all cached data below dname, class independent. + */ +void +clean_cache_from(char *dname, struct hashbuf *htp) { + const char *fname; + struct databuf *dp, *pdp; + struct namebuf *np; + struct hashbuf *phtp = htp; + int root_zone = 0; + + ns_debug(ns_log_default, 1, "clean_cache_from(%s)", dname); + if ((np = nlookup(dname, &phtp, &fname, 0)) && dname == fname && + !ns_wildcard(NAME(*np))) { + for (pdp = NULL, dp = np->n_data; dp != NULL; (void)NULL) { + if (dp->d_zone == DB_Z_CACHE) + dp = rm_datum(dp, np, pdp, NULL); + else { + pdp = dp; + dp = dp->d_next; + } + } + + if (*dname == '\0') + root_zone = 1; + + if (np->n_hash != NULL || root_zone) { + struct hashbuf *h; + + if (root_zone) + h = htp; + else + h = np->n_hash; + (void)clean_cache(h, 1); + if (h->h_cnt == 0 && !root_zone) { + rm_hash(np->n_hash); + np->n_hash = NULL; + } + } + + if (!root_zone && np->n_hash == NULL && np->n_data == NULL) + (void) purge_node(htp, np); + } +} + /* clean_cache(htp, all) * Scan the entire cache looking for expired TTL's on nonauthoritative * data, and remove it. if `all' is true, ignore TTL and rm everything. * notes: * this should be lazy and eventlib driven. * return: - * number of deleted RRs. + * number of deleted RRs (all=1) or RRsets (all=0). */ int clean_cache(struct hashbuf *htp, int all) { @@ -718,12 +966,17 @@ clean_cache(struct hashbuf *htp, int all) { nppend = htp->h_tab + htp->h_size; for (npp = htp->h_tab; npp < nppend; npp++) { for (pnp = NULL, np = *npp; np != NULL; np = npn) { + again: for (pdp = NULL, dp = np->n_data; dp != NULL; (void)NULL) { - if (dp->d_zone == DB_Z_CACHE && - (stale(dp) || all)) { + if (all && dp->d_zone == DB_Z_CACHE) { dp = rm_datum(dp, np, pdp, NULL); deleted++; + } else if (dp->d_zone == DB_Z_CACHE && + stale(dp)) { + delete_all(np, dp->d_class, dp->d_type); + deleted++; + goto again; } else { pdp = dp; dp = dp->d_next; @@ -753,6 +1006,78 @@ clean_cache(struct hashbuf *htp, int all) { return (deleted); } +/* struct namebuf * + * purge_node(htp, np) + * Remove entry from cache. + * Prerequisites: + * Node is empty and has no children. + * Paramters: + * htp - root of recursive hash table this node is part of. + * np - the node to be deleted. + * Return: + * pointer to parent. + */ +struct namebuf * +purge_node(struct hashbuf *htp, struct namebuf *np) { + struct namebuf **npp, **nppend; + struct namebuf *npn, *pnp, *nnp, *parent; + struct hashbuf *phtp; + + ns_debug(ns_log_default, 3, "purge_node: cleaning cache"); + INSIST(np->n_hash == NULL && np->n_data == NULL); + + /* Walk parent hashtable looking for ourself. */ + parent = np->n_parent; + if (parent != NULL) + phtp = parent->n_hash; + else + phtp = htp; + + if (phtp == NULL) { + /* XXX why shouldn't we panic? */ + } else { + nppend = phtp->h_tab + phtp->h_size; + for (npp = phtp->h_tab; npp < nppend; npp++) { + for (pnp = NULL, nnp = *npp; nnp != NULL; nnp = npn) { + if (nnp == np) { + ns_debug(ns_log_default, 3, + "purge_node: found ourself"); + npn = rm_name(nnp, npp, pnp); + phtp->h_cnt--; + } else { + npn = nnp->n_next; + pnp = nnp; + } + } + } + } + return (parent); +} + +void +remove_zone(struct zoneinfo *zp, const char *verb) { +#ifdef BIND_UPDATE + /* + * A dynamic zone might have changed, so we + * need to dump it before removing it. + */ + if ((zp->z_flags & Z_DYNAMIC) != 0 && + ((zp->z_flags & Z_NEED_SOAUPDATE) != 0 || + (zp->z_flags & Z_NEED_DUMP) != 0)) + (void) zonedump(zp, ISNOTIXFR); +#endif + ns_stopxfrs(zp); + do_reload(zp->z_origin, zp->z_type, zp->z_class, 1); + ns_notice(ns_log_config, "%s zone \"%s\" (%s) %s", + zoneTypeString(zp->z_type), zp->z_origin, + p_class(zp->z_class), verb); + free_zone_contents(zp, 1); + memset(zp, 0, sizeof(*zp)); + zp->z_type = z_nil; /* Pedantic; memset() did it. */ + INIT_LINK(zp, z_reloadlink); + free_zone(zp); +} + void purge_zone(const char *dname, struct hashbuf *htp, int class) { const char *fname; @@ -783,7 +1108,6 @@ purge_zone(const char *dname, struct hashbuf *htp, int class) { h = htp; else h = np->n_hash; - purge_z_2(h, class); if (h->h_cnt == 0 && !root_zone) { rm_hash(np->n_hash); @@ -791,39 +1115,8 @@ purge_zone(const char *dname, struct hashbuf *htp, int class) { } } - /* remove entry from cache, if required */ - if (np->n_hash == NULL && np->n_data == NULL) { - struct namebuf **npp, **nppend; - struct namebuf *npn, *pnp, *nnp; - - ns_debug(ns_log_default, 3, - "purge_zone: cleaning cache"); - - /* Walk parent hashtable looking for ourself. */ - if (np->n_parent) - phtp = np->n_parent->n_hash; - else - phtp = htp; /* top / root zone */ - - if (phtp) { - nppend = phtp->h_tab + phtp->h_size; - for (npp = phtp->h_tab; npp < nppend; npp++) { - for (pnp = NULL, nnp = *npp; - nnp != NULL; - nnp = npn) { - if (nnp == np) { - ns_debug(ns_log_default, 3, - "purge_zone: found our selves"); - npn = rm_name(nnp,npp,pnp); - phtp->h_cnt--; - } else { - npn = nnp->n_next; - pnp = nnp; - } - } - } - } - } + if (!root_zone && np->n_hash == NULL && np->n_data == NULL) + (void) purge_node(htp, np); } } @@ -903,12 +1196,12 @@ nxfers(struct zoneinfo *zp, int delta) { struct nameser *nsp; int ret; - if (ina_hlong(zp->z_xaddr) != INADDR_ANY) - nsa = zp->z_xaddr; /* qserial overrode address */ - else if (!zp->z_addrcnt) - return (-1); - else + if (zp->z_xaddrcnt != 0) + nsa = zp->z_xaddr[0]; /* first ns holds zone's xfer limit */ + else if (zp->z_addrcnt != 0) nsa = zp->z_addr[0]; /* first ns holds zone's xfer limit */ + else + return (-1); if (!(nsp = nameserFind(nsa, NS_F_INSERT))) return (-1); /* probably ENOMEM */ @@ -976,27 +1269,25 @@ pid %lu - forgetting, processes may accumulate", } /* - * SIGCHLD signal handler: process exit of xfer's. + * Process exit of xfer's. */ void -reapchild(evContext ctx, void *uap, int sig) { - int pid, i; +reapchild(void) { + int i; + pid_t pid; WAIT_T status; - int saved_errno = errno; gettime(&tt); - while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { + while ((pid = (pid_t)waitpid(-1, &status, WNOHANG)) > 0) { for (i = 0; i < MAX_XFERS_RUNNING; i++) { if (xferstatus[i].xfer_pid == pid) { xferstatus[i].xfer_status = status; xferstatus[i].xfer_state = XFER_DONE; - ns_need(MAIN_NEED_ENDXFER); + ns_need(main_need_endxfer); break; } } } - - errno = saved_errno; } /* @@ -1005,7 +1296,8 @@ reapchild(evContext ctx, void *uap, int sig) { void endxfer() { struct zoneinfo *zp; - int exitstatus, pid, i; + int exitstatus, i; + pid_t pid; WAIT_T status; gettime(&tt); @@ -1045,11 +1337,43 @@ endxfer() { sched_zone_maint(zp); break; - case XFER_SUCCESS: + case XFER_SUCCESSAXFR: + case XFER_SUCCESSAXFRIXFRFILE: + zp->z_xferpid = XFER_ISAXFR; + if (exitstatus == XFER_SUCCESSAXFRIXFRFILE) { + zp->z_xferpid = XFER_ISAXFRIXFR; + } + movefile(zp->z_ixfr_tmp, zp->z_source); /* XXX should incorporate loadxfer() */ zp->z_flags |= Z_NEED_RELOAD; zp->z_flags &= ~Z_SYSLOGGED; - ns_need(MAIN_NEED_ZONELOAD); + ns_need(main_need_zoneload); + break; + + case XFER_SUCCESSIXFR: + zp->z_xferpid = XFER_ISIXFR; + zp->z_log_size_ixfr++; + ns_notice(ns_log_default, + "IXFR Success %s", + zp->z_ixfr_tmp); + if (merge_logs(zp, zp->z_ixfr_tmp) >= 0) { + ns_notice(ns_log_default, + "IXFR Merge success %s", + zp->z_ixfr_tmp); + + (void)unlink(zp->z_updatelog); + (void)unlink(zp->z_ixfr_base); + movefile(zp->z_ixfr_tmp, + zp->z_ixfr_base); + (void)unlink(zp->z_ixfr_tmp); + if (zonedump(zp, ISIXFR) < 0) + ns_warning(ns_log_db, + "error in write ixfr updates to zone file %s", + zp ->z_source); + } else + ns_notice(ns_log_default, + "IXFR Merge failed %s", + zp->z_ixfr_tmp); break; case XFER_TIMEOUT: @@ -1157,8 +1481,11 @@ tryxfer() { * Reload zones whose transfers have completed. */ void -loadxfer() { +loadxfer(void) { struct zoneinfo *zp; + u_int32_t old_serial,new_serial; + char *tmpnom; + int isixfr; gettime(&tt); for (zp = zones; zp < &zones[nzones]; zp++) { @@ -1166,11 +1493,35 @@ loadxfer() { ns_debug(ns_log_default, 1, "loadxfer() \"%s\"", zp->z_origin[0] ? zp->z_origin : "."); zp->z_flags &= ~(Z_NEED_RELOAD|Z_AUTH); -/* XXX this is bad, should be done in ns_reload() for primary changes. */ +/* XXX this is bad, should be done in ns_zreload() for primary changes. */ ns_stopxfrs(zp); - purge_zone(zp->z_origin, hashtab, zp->z_class); - if (!db_load(zp->z_source, zp->z_origin, zp, NULL)) + old_serial = zp->z_serial; + if (zp->z_xferpid == XFER_ISIXFR) { + tmpnom = zp->z_ixfr_tmp; + isixfr = ISIXFR; + } else { + tmpnom = zp->z_source; + purge_zone(zp->z_origin, hashtab, zp->z_class); + isixfr = ISNOTIXFR; + } + if (zp->z_xferpid == XFER_ISAXFRIXFR) { + tmpnom= zp->z_source; + purge_zone(zp->z_origin, hashtab, zp->z_class); + isixfr = ISNOTIXFR; + } + + if (!db_load(tmpnom, zp->z_origin, zp, NULL, isixfr)) { zp->z_flags |= Z_AUTH; + if (isixfr == ISIXFR) { + new_serial= zp ->z_serial; + ns_warning(ns_log_db, "ISIXFR"); + ns_warning(ns_log_db, "error in updating ixfr data base file %s from %s", zp -> z_ixfr_base, zp ->z_ixfr_tmp); + if (zonedump(zp,ISIXFR)<0) + ns_warning(ns_log_db, "error in write ixfr updates to zone file %s", zp ->z_source); + + } + } + zp->z_xferpid = 0; if (zp->z_flags & Z_TMP_FILE) (void) unlink(zp->z_source); sched_zone_maint(zp); @@ -1181,7 +1532,7 @@ loadxfer() { /* * Add this zone to the set of those needing transfers. */ -static void +void addxfer(struct zoneinfo *zp) { if (!(zp->z_flags & Z_NEED_XFER)) { zp->z_flags |= Z_NEED_XFER; @@ -1191,21 +1542,203 @@ addxfer(struct zoneinfo *zp) { } /* - * Flush and reload data base. + * Mark one zone as requiring a reload. + * Note that it should be called with signals blocked, + * and should not allocate memory (since it can be called from a sighandler). + */ +const char * +deferred_reload_unsafe(struct zoneinfo *zp) { + INSIST(zp->z_type != z_nil); + if (!zonefile_changed_p(zp)) + return ("Zone file has not changed."); + if (LINKED(zp, z_reloadlink)) + return ("Zone is already scheduled for reloading."); + APPEND(reloadingzones, zp, z_reloadlink); + ns_need_unsafe(main_need_zreload); + return ("Zone is now scheduled for reloading."); +} + +/* + * If we've loaded this file, and the file has not been modified and contains + * no $INCLUDE, then there's no need to reload. + */ +int +zonefile_changed_p(struct zoneinfo *zp) { + struct stat sb; + + INSIST(zp->z_type != z_nil); + return ((zp->z_flags & Z_INCLUDE) != 0 || + stat(zp->z_source, &sb) == -1 || + zp->z_ftime != sb.st_mtime); +} + +int +reload_master(struct zoneinfo *zp) { + INSIST(zp->z_type == z_master); + zp->z_flags &= ~Z_AUTH; + ns_stopxfrs(zp); + /* XXX what about parent zones? */ + purge_zone(zp->z_origin, hashtab, zp->z_class); + ns_debug(ns_log_config, 1, "reloading zone"); +#ifdef BIND_UPDATE + if ((zp->z_flags & Z_DYNAMIC) != 0) { + struct stat sb; + + if (stat(zp->z_source, &sb) < 0) + ns_error(ns_log_config, "stat(%s) failed: %s", + zp->z_source, strerror(errno)); + else { + if ((sb.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) != 0) + ns_warning(ns_log_config, + "dynamic zone file '%s' is writable", + zp->z_source); + } + } +#endif + if (!db_load(zp->z_source, zp->z_origin, zp, NULL, ISNOTIXFR)) + zp->z_flags |= Z_AUTH; + zp->z_refresh = 0; /* no maintenance needed */ + zp->z_time = 0; +#ifdef BIND_UPDATE + zp->z_lastupdate = 0; + if ((zp->z_flags & Z_DYNAMIC) != 0) + if (merge_logs(zp, zp->z_updatelog) == 1) + return (1); +#endif + return (0); +} + +/* + * Called by main() when main_need_zreload has been set. Should pull one + * zone off of the reloadingzones list and reload it, then if the list is + * not then empty, should turn main_need_zreload on again for the next call. + * It is not an error to call this when the reloadingzones list is empty. + */ +void +ns_zreload(void) { + struct zoneinfo *zp; + + block_signals(); + if (EMPTY(reloadingzones)) { + unblock_signals(); + return; + } + zp = HEAD(reloadingzones); + UNLINK(reloadingzones, zp, z_reloadlink); + unblock_signals(); + + reload_master(zp); + + block_signals(); + if (!EMPTY(reloadingzones)) + ns_need_unsafe(main_need_zreload); + unblock_signals(); +} + +/* + * Flush and reload configuration file and data base. */ void -ns_reload() { +ns_reload(void) { ns_notice(ns_log_default, "reloading nameserver"); + INSIST(reloading == 0); qflush(); sq_flush(NULL); -#ifdef FORCED_RELOAD - reloading = 1; /* to force transfer if secondary and backing up */ -#endif + reloading++; /* To force transfer if secondary and backing up. */ ns_init(conffile); time(&resettime); -#ifdef FORCED_RELOAD - reloading = 0; -#endif /* FORCED_RELOAD */ + reloading--; ns_notice(ns_log_default, "Ready to answer queries."); } + +/* + * Reload configuration, look for new or deleted zones, not changed ones. + */ +void +ns_reconfig(void) { + INSIST(reconfiging == 0); + reconfiging++; /* To ignore zones which aren't new or deleted. */ + ns_reload(); + reconfiging--; +} + +void +make_new_zones(void) { + struct zoneinfo *zp; + int n; + + ns_debug(ns_log_config, 1, "Adding %d template zones", NEWZONES); + zp = (struct zoneinfo *) + memget((nzones + NEWZONES) * sizeof(struct zoneinfo)); + if (zp == NULL) + panic("no memory for more zones", NULL); + memset(zp, 0, (nzones + NEWZONES) * sizeof(struct zoneinfo)); + if (zones != NULL) { + memcpy(zp, zones, nzones * sizeof(struct zoneinfo)); + memput(zones, nzones * sizeof(struct zoneinfo)); + } + zones = zp; + block_signals(); + for (n = 0; n < NEWZONES; n++) { + INIT_LINK(&zones[nzones], z_reloadlink); + if (nzones != 0) + free_zone(&zones[nzones]); + nzones++; + } + unblock_signals(); +} + +void +free_zone(struct zoneinfo *zp) { + if (LINKED(zp, z_reloadlink)) + panic("freeing reloading zone", NULL); + if (zp->z_type != z_nil) + panic("freeing unfree zone", NULL); + APPEND(freezones, zp, z_freelink); +} + +#ifndef HAVE_SPAWNXFER +static pid_t +spawnxfer(char **argv, struct zoneinfo *zp) { + pid_t pid = (pid_t)vfork(); + + if (pid == -1) { + ns_error(ns_log_default, "xfer vfork: %s", strerror(errno)); + zp->z_time = tt.tv_sec + 10; + return (pid); + } + if (pid == 0) { + /* Child. */ + execv(server_options->named_xfer, argv); + ns_error(ns_log_default, "can't exec %s: %s", + server_options->named_xfer, strerror(errno)); + (void)nxfers(zp, -1); + _exit(XFER_FAIL); /* Avoid duplicate buffer flushes. */ + } + return (pid); +} +#endif + +struct zoneinfo * +find_auth_zone(const char *zname, ns_class zclass) { + struct zoneinfo *zp; + struct hashbuf *htp; + struct namebuf *np; + const char *fname; + int zn; + + zp = find_zone(zname, zclass); + if (zp != NULL && + (zp->z_type == z_slave || + zp->z_type == z_master || + zp->z_type == z_stub)) + return (zp); + + htp = hashtab; + np = nlookup(zname, &htp, &fname, 0); + if (np != NULL && (zn = findMyZone(np, zclass)) != DB_Z_CACHE) + return (&zones[zn]); + + return (NULL); +} diff --git a/contrib/bind/bin/named/ns_ncache.c b/contrib/bind/bin/named/ns_ncache.c index 413ccc6..437072c 100644 --- a/contrib/bind/bin/named/ns_ncache.c +++ b/contrib/bind/bin/named/ns_ncache.c @@ -1,9 +1,9 @@ #if !defined(lint) && !defined(SABER) -static char rcsid[] = "$Id: ns_ncache.c,v 8.17 1998/03/20 01:12:01 halley Exp $"; +static const char rcsid[] = "$Id: ns_ncache.c,v 8.26 1999/10/13 16:39:10 vixie Exp $"; #endif /* not lint */ /* - * Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -25,6 +25,7 @@ static char rcsid[] = "$Id: ns_ncache.c,v 8.17 1998/03/20 01:12:01 halley Exp $" #include <sys/param.h> #include <sys/socket.h> #include <sys/file.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -51,44 +52,77 @@ static char rcsid[] = "$Id: ns_ncache.c,v 8.17 1998/03/20 01:12:01 halley Exp $" } while (0) void -cache_n_resp(u_char *msg, int msglen, struct sockaddr_in from) { +cache_n_resp(u_char *msg, int msglen, struct sockaddr_in from, + const char *qname, int qclass, int qtype) +{ struct databuf *dp; HEADER *hp; u_char *cp, *eom, *rdatap; char dname[MAXDNAME]; - int n; - int type, class; - int Vcode; - int flags; - u_int16_t ancount; - u_int dlen; + int n, type, class, flags; + u_int ancount, nscount, dlen; +#ifdef RETURNSOA + u_int32_t ttl; + u_int16_t atype; + u_char *sp, *cp1; + u_char data[MAXDATA]; + size_t len = sizeof data; +#endif nameserIncr(from.sin_addr, nssRcvdNXD); hp = (HEADER *)msg; - cp = msg+HFIXEDSZ; + cp = msg + HFIXEDSZ; eom = msg + msglen; - - n = dn_expand(msg, eom, cp, dname, sizeof dname); - if (n < 0) { - ns_debug(ns_log_ncache, 1, - "Query expand name failed: cache_n_resp"); + + switch (ntohs(hp->qdcount)) { + case 0: + dname[sizeof dname - 1] = '\0'; + strncpy(dname, qname, sizeof dname); + if (dname[sizeof dname - 1] != '\0') { + ns_debug(ns_log_ncache, 1, + "qp->qname too long (%d)", strlen(qname)); + hp->rcode = FORMERR; + return; + } + class = qclass; + type = qtype; + break; + case 1: + n = dn_expand(msg, eom, cp, dname, sizeof dname); + if (n < 0) { + ns_debug(ns_log_ncache, 1, + "Query expand name failed: cache_n_resp"); + hp->rcode = FORMERR; + return; + } + cp += n; + BOUNDS_CHECK(cp, 2 * INT16SZ); + GETSHORT(type, cp); + GETSHORT(class, cp); + if (class > CLASS_MAX) { + ns_debug(ns_log_ncache, 1, + "bad class in cache_n_resp"); + hp->rcode = FORMERR; + return; + } + break; + default: + ns_debug(ns_log_ncache, 1, + "QDCOUNT>1 (%d) in cache_n_resp", ntohs(hp->qdcount)); hp->rcode = FORMERR; return; } - cp += n; - BOUNDS_CHECK(cp, 2 * INT16SZ); - GETSHORT(type, cp); - GETSHORT(class, cp); ns_debug(ns_log_ncache, 1, "ncache: dname %s, type %d, class %d", dname, type, class); ancount = ntohs(hp->ancount); + nscount = ntohs(hp->nscount); while (ancount--) { u_int32_t ttl; - u_int16_t atype; - u_int16_t aclass; + u_int atype, aclass; + n = dn_skipname(cp, eom); if (n < 0) { ns_debug(ns_log_ncache, 3, "ncache: form error"); @@ -99,7 +133,9 @@ cache_n_resp(u_char *msg, int msglen, struct sockaddr_in from) { GETSHORT(atype, cp); GETSHORT(aclass, cp); if (atype != T_CNAME || aclass != class) { - ns_debug(ns_log_ncache, 3, "ncache: form error"); + ns_debug(ns_log_ncache, 3, + "ncache: not CNAME (%s) or wrong class (%s)", + p_type(atype), p_class(aclass)); return; } GETLONG(ttl, cp); @@ -108,84 +144,81 @@ cache_n_resp(u_char *msg, int msglen, struct sockaddr_in from) { rdatap = cp; n = dn_expand(msg, msg + msglen, cp, dname, sizeof dname); if (n < 0) { - ns_debug(ns_log_ncache, 3, "ncache: form error"); + ns_debug(ns_log_ncache, 3, "ncache: bad cname target"); return; } cp += n; if (cp != rdatap + dlen) { - ns_debug(ns_log_ncache, 3, "ncache: form error"); + ns_debug(ns_log_ncache, 3, "ncache: bad cname rdata"); return; } } + dp = NULL; #ifdef RETURNSOA - if (hp->nscount) { - u_int32_t ttl; - u_int16_t atype; - u_char *tp = cp; - u_char *cp1; - u_char data[MAXDATA]; - size_t len = sizeof data; + while (nscount--) { + sp = cp; /* we store NXDOMAIN as T_SOA regardless of the query type */ if (hp->rcode == NXDOMAIN) type = T_SOA; /* store ther SOA record */ - n = dn_skipname(tp, msg + msglen); + n = dn_skipname(cp, msg + msglen); if (n < 0) { ns_debug(ns_log_ncache, 3, "ncache: form error"); return; } - tp += n; + cp += n; - BOUNDS_CHECK(tp, 3 * INT16SZ + INT32SZ); - GETSHORT(atype, tp); /* type */ + BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ); + GETSHORT(atype, cp); /* type */ + cp += INT16SZ; /* class */ + GETLONG(ttl, cp); /* ttl */ + GETSHORT(dlen, cp); /* dlen */ + BOUNDS_CHECK(cp, dlen); if (atype != T_SOA) { ns_debug(ns_log_ncache, 3, "ncache: type (%d) != T_SOA", atype); - goto no_soa; + cp += dlen; + continue; } - tp += INT16SZ; /* class */ - GETLONG(ttl, tp); /* ttl */ - GETSHORT(dlen, tp); /* dlen */ - BOUNDS_CHECK(tp, dlen); - rdatap = tp; + rdatap = cp; /* origin */ - n = dn_expand(msg, msg + msglen, tp, (char*)data, len); + n = dn_expand(msg, msg + msglen, cp, (char*)data, len); if (n < 0) { ns_debug(ns_log_ncache, 3, "ncache: origin form error"); return; } - tp += n; + cp += n; n = strlen((char*)data) + 1; cp1 = data + n; len -= n; /* mail */ - n = dn_expand(msg, msg + msglen, tp, (char*)cp1, len); + n = dn_expand(msg, msg + msglen, cp, (char*)cp1, len); if (n < 0) { ns_debug(ns_log_ncache, 3, "ncache: mail form error"); return; } - tp += n; + cp += n; n = strlen((char*)cp1) + 1; cp1 += n; len -= n; n = 5 * INT32SZ; - BOUNDS_CHECK(tp, n); - memcpy(cp1, tp, n); + BOUNDS_CHECK(cp, n); + memcpy(cp1, cp, n); /* serial, refresh, retry, expire, min */ cp1 += n; len -= n; - tp += n; - if (tp != rdatap + dlen) { + cp += n; + if (cp != rdatap + dlen) { ns_debug(ns_log_ncache, 3, "ncache: form error"); return; } /* store the zone of the soa record */ - n = dn_expand(msg, msg + msglen, cp, (char*)cp1, len); + n = dn_expand(msg, msg + msglen, sp, (char*)cp1, len); if (n < 0) { ns_debug(ns_log_ncache, 3, "ncache: form error 2"); return; @@ -193,17 +226,28 @@ cache_n_resp(u_char *msg, int msglen, struct sockaddr_in from) { n = strlen((char*)cp1) + 1; cp1 += n; - dp = savedata(class, type, MIN(ttl, NTTL) + tt.tv_sec, data, + /* + * we only want to store these long enough so that + * ns_resp can find it. + */ + if (qtype == T_SOA && hp->rcode == NXDOMAIN) + ttl = 0; + dp = savedata(class, type, + MIN(ttl, server_options->max_ncache_ttl) + + tt.tv_sec, data, cp1 - data); - } else { - no_soa: -#endif - dp = savedata(class, type, NTTL + tt.tv_sec, NULL, 0); -#ifdef RETURNSOA + break; } #endif + if (dp == NULL) +#ifdef STRICT_RFC2308 + dp = savedata(class, type, tt.tv_sec, NULL, 0); +#else + dp = savedata(class, type, NTTL + tt.tv_sec, NULL, 0); +#endif dp->d_zone = DB_Z_CACHE; dp->d_cred = hp->aa ? DB_C_AUTH : DB_C_ANSWER; + dp->d_secure = DB_S_INSECURE; /* BEW - should be UNCHECKED */ dp->d_clev = 0; if(hp->rcode == NXDOMAIN) { dp->d_rcode = NXDOMAIN; diff --git a/contrib/bind/bin/named/ns_notify.c b/contrib/bind/bin/named/ns_notify.c new file mode 100644 index 0000000..ac03732e --- /dev/null +++ b/contrib/bind/bin/named/ns_notify.c @@ -0,0 +1,379 @@ +#if !defined(lint) && !defined(SABER) +static const char rcsid[] = "$Id: ns_notify.c,v 8.4 1999/10/15 19:49:04 vixie Exp $"; +#endif /* not lint */ + +/* + * Copyright (c) 1994-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/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/file.h> +#include <sys/un.h> + +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> + +#include <errno.h> +#include <limits.h> +#include <resolv.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <time.h> + +#include <isc/eventlib.h> +#include <isc/logging.h> +#include <isc/memcluster.h> + +#include <isc/dst.h> + +#include "port_after.h" + +#include "named.h" + +#ifdef BIND_NOTIFY + +/* Types. */ + +struct notify { + char * name; + ns_class class; + ns_type type; + evTimerID timer; + LINK(struct notify) link; +}; + +/* Forward. */ + +static void sysnotify(const char *, ns_class, ns_type); +static void sysnotify_slaves(const char *, const char *, + ns_class, ns_type, int, int *, int *); +static void sysnotify_ns(const char *, const char *, + ns_class, ns_type, int, int *, int *); +static void free_notify(struct notify *); +static void notify_timer(evContext, void *, + struct timespec, struct timespec); + +/* Local. */ + +static LIST(struct notify) pending_notifies; + +/* Public. */ + +/* + * ns_notify(dname, class, type) + * call this when a zone has changed and its slaves need to know. + */ +void +ns_notify(const char *dname, ns_class class, ns_type type) { + static const char no_room[] = "%s failed, cannot notify for zone %s"; + int delay, max_delay; + struct zoneinfo *zp; + struct notify *ni; + + zp = find_auth_zone(dname, class); + if (zp == NULL) { + ns_warning(ns_log_notify, + "no zone found for notify (\"%s\" %s %s)", + (dname && *dname) ? dname : ".", + p_class(class), p_type(type)); + return; + } + if ((zp->z_flags & Z_NOTIFY) != 0) { + ns_info(ns_log_notify, + "suppressing duplicate notify (\"%s\" %s %s)", + (dname && *dname) ? dname : ".", + p_class(class), p_type(type)); + return; + } + ni = memget(sizeof *ni); + if (ni == NULL) { + ns_info(ns_log_notify, no_room, "memget", dname); + return; + } + ni->name = savestr(dname, 0); + if (ni->name == NULL) { + memput(ni, sizeof *ni); + ni = NULL; + ns_info(ns_log_notify, no_room, "memget", dname); + return; + } + ni->class = class; + ni->type = type; + evInitID(&ni->timer); + + /* Delay notification for from five seconds up to fifteen minutes. */ + max_delay = MIN(nzones/5, 895); + max_delay = MAX(max_delay, 25); + delay = 5 + (rand() % max_delay); + if (evSetTimer(ev, notify_timer, ni, + evAddTime(evNowTime(), evConsTime(delay, 0)), + evConsTime(0, 0), &ni->timer) < 0) { + ns_error(ns_log_notify, "evSetTimer() failed: %s", + strerror(errno)); + freestr(ni->name); + memput(ni, sizeof *ni); + return; + } + + zp->z_flags |= Z_NOTIFY; + APPEND(pending_notifies, ni, link); + ns_debug(ns_log_notify, 3, + "ns_notify(%s, %s, %s): ni %p, zp %p, delay %d", + (dname && *dname) ? dname : ".", + p_class(class), p_type(type), + ni, zp, delay); +} + +/* + * ns_unnotify() + * call this when all pending notifies are now considered junque. + */ +void +ns_unnotify(void) { + while (!EMPTY(pending_notifies)) { + struct notify *ni = HEAD(pending_notifies); + + INSIST(LINKED(ni, link)); + UNLINK(pending_notifies, ni, link); + free_notify(ni); + } +} + +/* Private. */ + +/* + * sysnotify(dname, class, type) + * cause a NOTIFY request to be sysquery()'d to each slave server + * of the zone that "dname" is within. + */ +static void +sysnotify(const char *dname, ns_class class, ns_type type) { + const char *zname, *fname; + int nns, na, i; + struct zoneinfo *zp; + struct in_addr *also_addr; + + ns_debug(ns_log_notify, 3, "sysnotify(%s, %s, %s)", + dname, p_class(class), p_type(type)); + zp = find_auth_zone(dname, class); + if (zp == NULL) { + ns_warning(ns_log_notify, "sysnotify: can't find \"%s\" (%s)", + dname, p_class(class)); + return; + } + if (ns_samename(dname, zp->z_origin) != 1) { + ns_warning(ns_log_notify, "sysnotify: not auth for zone %s", + dname); + return; + } + if (zp->z_notify == znotify_no || + (zp->z_notify == znotify_use_default && + NS_OPTION_P(OPTION_NONOTIFY))) + return; + if (zp->z_type != z_master && zp->z_type != z_slave) { + ns_warning(ns_log_notify, "sysnotify: %s not master or slave", + dname); + return; + } + zname = zp->z_origin; + nns = na = 0; + if (zp->z_type == z_master) + sysnotify_slaves(dname, zname, class, type, + zp - zones, &nns, &na); + + /* + * Handle any global or zone-specific also-notify clauses + */ + if (zp->z_notify_count != 0) { + /* zone-specific also notify */ + + ns_debug(ns_log_notify, 3, "zone notify ns = %d", + zp->z_notify_count); + + also_addr = zp->z_also_notify; + for (i = 0; i < zp->z_notify_count; i++) { + ns_debug(ns_log_notify, 4, "notifying %s", + inet_ntoa(*also_addr)); + sysquery(dname, class, type, also_addr, 1, ns_port, + NS_NOTIFY_OP); + also_addr++; + } + nns += zp->z_notify_count; + na += zp->z_notify_count; + } else if (server_options->notify_count != 0) { + ns_debug(ns_log_notify, 4, "global notify ns = %d", + server_options->notify_count); + also_addr = server_options->also_notify; + for (i = 0; i < server_options->notify_count; i++) { + ns_debug(ns_log_notify, 3, "notifying %s", + inet_ntoa(*also_addr)); + sysquery(dname, class, type, also_addr, + 1, ns_port, ns_o_notify); + also_addr++; + } + nns += server_options->notify_count; + na += server_options->notify_count; + } + + if (nns != 0 || na != 0) + ns_info(ns_log_notify, + "Sent NOTIFY for \"%s %s %s\" (%s); %d NS, %d A", + dname, p_class(class), p_type(type), zname, nns, na); +} + +static void +sysnotify_slaves(const char *dname, const char *zname, + ns_class class, ns_type type, + int zn, int *nns, int *na) +{ + const char *mname, *fname; + struct hashbuf *htp; + struct namebuf *np; + struct databuf *dp; + + /* + * Master. + */ + htp = hashtab; + np = nlookup(zname, &htp, &fname, 0); + if (np == NULL) { + ns_warning(ns_log_notify, + "sysnotify: found name \"%s\" but not zone", + dname); + return; + } + mname = NULL; + for (dp = np->n_data; dp != NULL; dp = dp->d_next) { + if (dp->d_zone == DB_Z_CACHE || !match(dp, class, ns_t_soa)) + continue; + if (dp->d_type == ns_t_sig) + continue; + if (mname) { + ns_notice(ns_log_notify, + "multiple SOA's for zone \"%s\"?", + zname); + return; + } + mname = (char *) dp->d_data; + } + if (mname == NULL) { + ns_notice(ns_log_notify, "no SOA found for zone \"%s\"", + zname); + return; + } + for (dp = np->n_data; dp != NULL; dp = dp->d_next) { + if (dp->d_zone == DB_Z_CACHE || !match(dp, class, ns_t_ns)) + continue; + if (dp->d_type == ns_t_sig) + continue; + if (ns_samename((char*)dp->d_data, mname) == 1) + continue; + sysnotify_ns(dname, (char *)dp->d_data, class, type, + zn, nns, na); + } +} + +static void +sysnotify_ns(const char *dname, const char *aname, + ns_class class, ns_type type, + int zn, int *nns, int *na) +{ + struct databuf *adp; + struct namebuf *anp; + const char *fname; + struct in_addr nss[NSMAX]; + struct hashbuf *htp; + int is_us, nsc; + + htp = hashtab; + anp = nlookup(aname, &htp, &fname, 0); + nsc = 0; + is_us = 0; + if (anp != NULL) + for (adp = anp->n_data; adp; adp = adp->d_next) { + struct in_addr ina; + + if (!match(adp, class, T_A)) + continue; + if (adp->d_type == ns_t_sig) + continue; + ina = ina_get(adp->d_data); + if (aIsUs(ina)) { + is_us = 1; + continue; + } + if (nsc < NSMAX) + nss[nsc++] = ina; + } /*next A*/ + if (nsc == 0) { + if (!is_us) { + struct qinfo *qp; + + qp = sysquery(aname, class, ns_t_a, 0, 0, ns_port, + ns_o_query); + if (qp != NULL) + qp->q_notifyzone = zn; + } + return; + } + sysquery(dname, class, type, nss, nsc, ns_port, ns_o_notify); + (*nns)++; + *na += nsc; +} + +static void +free_notify(struct notify *ni) { + struct zoneinfo *zp; + + INSIST(!LINKED(ni, link)); + zp = find_auth_zone(ni->name, ni->class); + if (zp != NULL) { + INSIST((zp->z_flags & Z_NOTIFY) != 0); + zp->z_flags &= ~Z_NOTIFY; + } + if (evTestID(ni->timer)) { + evClearTimer(ev, ni->timer); + evInitID(&ni->timer); + } + freestr(ni->name); + memput(ni, sizeof *ni); +} + +static void +notify_timer(evContext ctx, void *uap, + struct timespec due, + struct timespec inter) +{ + struct notify *ni = uap; + + INSIST(evTestID(ni->timer)); + evInitID(&ni->timer); + INSIST(LINKED(ni, link)); + UNLINK(pending_notifies, ni, link); + sysnotify(ni->name, ni->class, ni->type); + free_notify(ni); +} + +#endif /*BIND_NOTIFY*/ diff --git a/contrib/bind/bin/named/ns_parser.c b/contrib/bind/bin/named/ns_parser.c index 47944ea..03d0a84 100644 --- a/contrib/bind/bin/named/ns_parser.c +++ b/contrib/bind/bin/named/ns_parser.c @@ -13,11 +13,11 @@ static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93 (BSDI)"; #define YYPREFIX "yy" #line 2 "ns_parser.y" #if !defined(lint) && !defined(SABER) -static char rcsid[] = "$Id: ns_parser.y,v 8.11 1997/12/04 07:03:05 halley Exp $"; +static char rcsid[] = "$Id: ns_parser.y,v 8.51 1999/11/12 05:29:18 vixie Exp $"; #endif /* not lint */ /* - * Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -38,6 +38,8 @@ static char rcsid[] = "$Id: ns_parser.y,v 8.11 1997/12/04 07:03:05 halley Exp $" #include "port_before.h" #include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -45,6 +47,7 @@ static char rcsid[] = "$Id: ns_parser.y,v 8.11 1997/12/04 07:03:05 halley Exp $" #include <ctype.h> #include <limits.h> +#include <resolv.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -54,6 +57,8 @@ static char rcsid[] = "$Id: ns_parser.y,v 8.11 1997/12/04 07:03:05 halley Exp $" #include <isc/eventlib.h> #include <isc/logging.h> +#include <isc/dst.h> + #include "port_after.h" #include "named.h" @@ -74,11 +79,13 @@ static symbol_table symtab; static symbol_table authtab = NULL; static zone_config current_zone; -static int seen_zone; +static int should_install; static options current_options; static int seen_options; +static controls current_controls; + static topology_config current_topology; static int seen_topology; @@ -103,8 +110,8 @@ static void define_channel(char *, log_channel); static char *canonical_name(char *); int yyparse(); - -#line 96 "ns_parser.y" + +#line 103 "ns_parser.y" typedef union { char * cp; int s_int; @@ -114,10 +121,12 @@ typedef union { struct in_addr ip_addr; ip_match_element ime; ip_match_list iml; - key_info keyi; + rrset_order_list rol; + rrset_order_element roe; + struct dst_key * keyi; enum axfr_format axfr_fmt; } YYSTYPE; -#line 121 "y.tab.c" +#line 130 "y.tab.c" #define L_EOS 257 #define L_IPADDR 258 #define L_NUMBER 259 @@ -139,230 +148,316 @@ typedef union { #define T_LISTEN_ON 275 #define T_PORT 276 #define T_ADDRESS 277 -#define T_DATASIZE 278 -#define T_STACKSIZE 279 -#define T_CORESIZE 280 -#define T_DEFAULT 281 -#define T_UNLIMITED 282 -#define T_FILES 283 -#define T_HOSTSTATS 284 -#define T_DEALLOC_ON_EXIT 285 -#define T_TRANSFERS_IN 286 -#define T_TRANSFERS_OUT 287 -#define T_TRANSFERS_PER_NS 288 -#define T_TRANSFER_FORMAT 289 -#define T_MAX_TRANSFER_TIME_IN 290 -#define T_ONE_ANSWER 291 -#define T_MANY_ANSWERS 292 -#define T_NOTIFY 293 -#define T_AUTH_NXDOMAIN 294 -#define T_MULTIPLE_CNAMES 295 -#define T_CLEAN_INTERVAL 296 -#define T_INTERFACE_INTERVAL 297 -#define T_STATS_INTERVAL 298 -#define T_LOGGING 299 -#define T_CATEGORY 300 -#define T_CHANNEL 301 -#define T_SEVERITY 302 -#define T_DYNAMIC 303 -#define T_FILE 304 -#define T_VERSIONS 305 -#define T_SIZE 306 -#define T_SYSLOG 307 -#define T_DEBUG 308 -#define T_NULL_OUTPUT 309 -#define T_PRINT_TIME 310 -#define T_PRINT_CATEGORY 311 -#define T_PRINT_SEVERITY 312 -#define T_TOPOLOGY 313 -#define T_SERVER 314 -#define T_LONG_AXFR 315 -#define T_BOGUS 316 -#define T_TRANSFERS 317 -#define T_KEYS 318 -#define T_ZONE 319 -#define T_IN 320 -#define T_CHAOS 321 -#define T_HESIOD 322 -#define T_TYPE 323 -#define T_MASTER 324 -#define T_SLAVE 325 -#define T_STUB 326 -#define T_RESPONSE 327 -#define T_HINT 328 -#define T_MASTERS 329 -#define T_TRANSFER_SOURCE 330 -#define T_ALSO_NOTIFY 331 -#define T_ACL 332 -#define T_ALLOW_UPDATE 333 -#define T_ALLOW_QUERY 334 -#define T_ALLOW_TRANSFER 335 -#define T_SEC_KEY 336 -#define T_ALGID 337 -#define T_SECRET 338 -#define T_CHECK_NAMES 339 -#define T_WARN 340 -#define T_FAIL 341 -#define T_IGNORE 342 -#define T_FORWARD 343 -#define T_FORWARDERS 344 -#define T_ONLY 345 -#define T_FIRST 346 -#define T_IF_NO_ANSWER 347 -#define T_IF_NO_DOMAIN 348 -#define T_YES 349 -#define T_TRUE 350 -#define T_NO 351 -#define T_FALSE 352 +#define T_RRSET_ORDER 278 +#define T_ORDER 279 +#define T_NAME 280 +#define T_CLASS 281 +#define T_CONTROLS 282 +#define T_INET 283 +#define T_UNIX 284 +#define T_PERM 285 +#define T_OWNER 286 +#define T_GROUP 287 +#define T_ALLOW 288 +#define T_DATASIZE 289 +#define T_STACKSIZE 290 +#define T_CORESIZE 291 +#define T_DEFAULT 292 +#define T_UNLIMITED 293 +#define T_FILES 294 +#define T_VERSION 295 +#define T_HOSTSTATS 296 +#define T_DEALLOC_ON_EXIT 297 +#define T_TRANSFERS_IN 298 +#define T_TRANSFERS_OUT 299 +#define T_TRANSFERS_PER_NS 300 +#define T_TRANSFER_FORMAT 301 +#define T_MAX_TRANSFER_TIME_IN 302 +#define T_SERIAL_QUERIES 303 +#define T_ONE_ANSWER 304 +#define T_MANY_ANSWERS 305 +#define T_NOTIFY 306 +#define T_AUTH_NXDOMAIN 307 +#define T_MULTIPLE_CNAMES 308 +#define T_USE_IXFR 309 +#define T_MAINTAIN_IXFR_BASE 310 +#define T_CLEAN_INTERVAL 311 +#define T_INTERFACE_INTERVAL 312 +#define T_STATS_INTERVAL 313 +#define T_MAX_LOG_SIZE_IXFR 314 +#define T_HEARTBEAT 315 +#define T_USE_ID_POOL 316 +#define T_MAX_NCACHE_TTL 317 +#define T_HAS_OLD_CLIENTS 318 +#define T_RFC2308_TYPE1 319 +#define T_LAME_TTL 320 +#define T_MIN_ROOTS 321 +#define T_TREAT_CR_AS_SPACE 322 +#define T_LOGGING 323 +#define T_CATEGORY 324 +#define T_CHANNEL 325 +#define T_SEVERITY 326 +#define T_DYNAMIC 327 +#define T_FILE 328 +#define T_VERSIONS 329 +#define T_SIZE 330 +#define T_SYSLOG 331 +#define T_DEBUG 332 +#define T_NULL_OUTPUT 333 +#define T_PRINT_TIME 334 +#define T_PRINT_CATEGORY 335 +#define T_PRINT_SEVERITY 336 +#define T_SORTLIST 337 +#define T_TOPOLOGY 338 +#define T_SERVER 339 +#define T_LONG_AXFR 340 +#define T_BOGUS 341 +#define T_TRANSFERS 342 +#define T_KEYS 343 +#define T_SUPPORT_IXFR 344 +#define T_ZONE 345 +#define T_IN 346 +#define T_CHAOS 347 +#define T_HESIOD 348 +#define T_TYPE 349 +#define T_MASTER 350 +#define T_SLAVE 351 +#define T_STUB 352 +#define T_RESPONSE 353 +#define T_HINT 354 +#define T_MASTERS 355 +#define T_TRANSFER_SOURCE 356 +#define T_PUBKEY 357 +#define T_ALSO_NOTIFY 358 +#define T_DIALUP 359 +#define T_FILE_IXFR 360 +#define T_IXFR_TMP 361 +#define T_TRUSTED_KEYS 362 +#define T_ACL 363 +#define T_ALLOW_UPDATE 364 +#define T_ALLOW_QUERY 365 +#define T_ALLOW_TRANSFER 366 +#define T_ALLOW_RECURSION 367 +#define T_BLACKHOLE 368 +#define T_SEC_KEY 369 +#define T_ALGID 370 +#define T_SECRET 371 +#define T_CHECK_NAMES 372 +#define T_WARN 373 +#define T_FAIL 374 +#define T_IGNORE 375 +#define T_FORWARD 376 +#define T_FORWARDERS 377 +#define T_ONLY 378 +#define T_FIRST 379 +#define T_IF_NO_ANSWER 380 +#define T_IF_NO_DOMAIN 381 +#define T_YES 382 +#define T_TRUE 383 +#define T_NO 384 +#define T_FALSE 385 #define YYERRCODE 256 short yylhs[] = { -1, - 0, 25, 25, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 27, 34, 28, 35, 35, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 38, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 5, 5, 4, 4, 3, 3, 43, 44, 40, 40, - 40, 40, 2, 2, 23, 23, 23, 23, 23, 21, - 21, 21, 22, 22, 22, 37, 37, 37, 37, 41, - 41, 41, 41, 20, 20, 20, 20, 42, 42, 42, - 39, 39, 45, 45, 46, 47, 29, 48, 48, 48, - 50, 49, 52, 49, 54, 54, 54, 54, 55, 55, - 56, 57, 57, 57, 57, 57, 58, 9, 9, 10, - 10, 59, 60, 60, 60, 60, 60, 60, 60, 53, - 53, 53, 8, 8, 61, 51, 51, 51, 7, 7, - 7, 6, 62, 30, 63, 63, 64, 64, 64, 64, - 64, 14, 14, 12, 12, 11, 11, 11, 11, 11, - 13, 17, 66, 65, 65, 65, 67, 33, 68, 68, - 68, 18, 19, 32, 70, 31, 69, 69, 15, 15, - 16, 16, 16, 16, 71, 71, 72, 72, 72, 72, - 72, 72, 72, 72, 72, 72, 72, 72, 73, 73, - 75, 74, 74, 76, 76, 77, 1, 24, 24, + 0, 31, 31, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 33, 42, 34, 43, 43, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 46, 44, 44, 44, 44, 44, + 44, 44, 49, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 35, 53, 53, 54, 54, 54, 54, + 15, 15, 12, 12, 13, 13, 14, 14, 16, 6, + 6, 5, 5, 4, 4, 55, 56, 48, 48, 48, + 48, 2, 2, 3, 3, 29, 29, 29, 29, 29, + 27, 27, 27, 28, 28, 28, 45, 45, 45, 45, + 51, 51, 51, 51, 26, 26, 26, 26, 52, 52, + 52, 47, 47, 57, 57, 58, 50, 50, 59, 59, + 60, 61, 36, 62, 62, 62, 64, 63, 66, 63, + 68, 68, 68, 68, 69, 69, 70, 71, 71, 71, + 71, 71, 72, 10, 10, 11, 11, 73, 74, 74, + 74, 74, 74, 74, 74, 67, 67, 67, 9, 9, + 75, 65, 65, 65, 8, 8, 8, 7, 76, 37, + 77, 77, 78, 78, 78, 78, 78, 78, 20, 20, + 18, 18, 18, 17, 17, 17, 17, 17, 19, 23, + 80, 79, 79, 79, 81, 41, 82, 82, 82, 24, + 25, 40, 84, 38, 83, 83, 21, 21, 22, 22, + 22, 22, 22, 85, 85, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 89, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 87, 87, 92, + 91, 91, 93, 93, 94, 88, 88, 90, 90, 95, + 95, 96, 39, 97, 97, 98, 98, 1, 30, 30, }; short yylen[] = { 2, 1, 1, 2, 1, 2, 2, 2, 2, 2, 2, - 1, 2, 2, 3, 0, 5, 2, 3, 0, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 3, 5, 2, 0, 5, 2, 4, - 4, 4, 1, 1, 2, 2, 2, 2, 2, 1, - 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, - 2, 2, 0, 2, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, - 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, - 0, 1, 2, 3, 1, 0, 5, 2, 3, 1, - 0, 6, 0, 6, 1, 1, 2, 1, 2, 2, - 2, 0, 1, 1, 2, 2, 3, 1, 1, 0, - 1, 2, 1, 1, 1, 2, 2, 2, 2, 2, - 3, 1, 1, 1, 1, 2, 3, 1, 1, 1, - 1, 1, 0, 6, 2, 3, 2, 2, 2, 4, - 1, 2, 3, 1, 2, 1, 3, 3, 1, 3, - 1, 1, 1, 2, 3, 1, 0, 6, 2, 2, - 1, 3, 3, 5, 0, 5, 0, 3, 0, 1, - 1, 1, 1, 1, 2, 3, 2, 2, 4, 2, - 2, 4, 4, 4, 2, 2, 4, 1, 2, 3, - 1, 0, 1, 2, 3, 1, 1, 1, 1, + 2, 2, 1, 2, 2, 3, 0, 5, 2, 3, + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, + 2, 2, 5, 2, 0, 5, 2, 2, 4, 4, + 4, 4, 0, 5, 4, 4, 1, 1, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, + 2, 2, 1, 4, 2, 3, 0, 8, 8, 1, + 2, 3, 0, 2, 0, 2, 0, 2, 5, 1, + 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, + 2, 0, 2, 0, 2, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, + 2, 0, 1, 2, 3, 1, 0, 1, 2, 3, + 1, 0, 5, 2, 3, 1, 0, 6, 0, 6, + 1, 1, 2, 1, 2, 2, 2, 0, 1, 1, + 2, 2, 3, 1, 1, 0, 1, 2, 1, 1, + 1, 2, 2, 2, 2, 2, 3, 1, 1, 1, + 1, 2, 3, 1, 1, 1, 1, 1, 0, 6, + 2, 3, 2, 2, 2, 2, 4, 1, 2, 3, + 1, 2, 2, 1, 3, 3, 1, 3, 1, 1, + 1, 2, 3, 1, 0, 6, 2, 2, 1, 3, + 3, 5, 0, 5, 0, 3, 0, 1, 1, 1, + 1, 1, 1, 2, 3, 2, 2, 2, 2, 5, + 2, 2, 4, 4, 4, 2, 0, 5, 2, 2, + 2, 2, 5, 5, 4, 2, 1, 2, 3, 1, + 0, 1, 2, 3, 1, 1, 1, 0, 1, 2, + 3, 1, 4, 2, 3, 5, 5, 1, 1, 1, }; short yydefred[] = { 0, - 0, 11, 0, 15, 96, 0, 0, 0, 167, 0, - 0, 2, 4, 0, 0, 0, 0, 0, 0, 12, - 13, 0, 0, 0, 143, 0, 208, 209, 0, 0, - 3, 5, 6, 7, 8, 9, 10, 14, 0, 0, - 0, 175, 180, 0, 0, 50, 0, 0, 0, 0, + 0, 13, 0, 17, 0, 142, 0, 0, 0, 0, + 215, 0, 0, 2, 4, 0, 0, 0, 0, 0, + 0, 0, 0, 14, 15, 0, 0, 0, 0, 189, + 0, 0, 279, 280, 0, 0, 3, 5, 6, 7, + 8, 9, 10, 11, 12, 16, 0, 80, 0, 0, + 0, 0, 0, 0, 223, 228, 0, 0, 0, 0, + 0, 73, 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, 37, - 0, 0, 43, 44, 100, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 154, 0, 159, 0, 161, - 0, 20, 22, 21, 25, 23, 24, 69, 65, 66, - 67, 68, 26, 27, 28, 0, 0, 39, 0, 0, - 0, 0, 85, 86, 87, 80, 84, 81, 82, 83, - 30, 31, 88, 89, 90, 51, 52, 45, 46, 29, - 32, 33, 47, 48, 49, 0, 0, 0, 70, 71, - 72, 0, 76, 77, 78, 79, 36, 0, 16, 0, - 17, 140, 141, 101, 142, 139, 134, 103, 133, 97, - 0, 98, 151, 0, 0, 0, 0, 0, 0, 0, - 176, 0, 0, 0, 155, 152, 174, 0, 171, 0, - 0, 0, 0, 0, 207, 56, 55, 58, 53, 54, - 57, 61, 62, 64, 0, 0, 0, 0, 73, 74, - 75, 34, 0, 18, 0, 0, 99, 149, 147, 148, - 0, 144, 0, 145, 198, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 157, 158, - 160, 153, 0, 0, 169, 170, 168, 0, 42, 40, - 41, 95, 0, 0, 0, 0, 0, 166, 163, 162, - 0, 0, 146, 195, 196, 188, 181, 182, 184, 183, - 187, 0, 190, 0, 0, 0, 0, 191, 178, 0, - 185, 172, 173, 35, 38, 0, 93, 138, 135, 0, - 0, 132, 0, 0, 0, 125, 0, 0, 0, 0, - 123, 124, 0, 150, 0, 164, 201, 0, 0, 206, - 0, 0, 0, 0, 0, 0, 186, 94, 102, 0, - 136, 108, 0, 105, 126, 0, 119, 121, 122, 118, - 127, 128, 129, 104, 0, 130, 165, 189, 0, 199, - 197, 0, 204, 192, 193, 194, 137, 107, 0, 0, - 0, 0, 117, 131, 200, 205, 109, 110, 111, 115, - 116, + 0, 0, 0, 0, 0, 0, 0, 53, 0, 0, + 0, 0, 0, 0, 0, 45, 0, 0, 57, 58, + 92, 93, 0, 0, 74, 0, 75, 146, 0, 0, + 0, 0, 0, 0, 0, 0, 273, 0, 274, 0, + 0, 0, 0, 0, 201, 0, 207, 0, 209, 0, + 23, 25, 24, 28, 26, 27, 110, 106, 107, 108, + 109, 29, 30, 31, 0, 0, 47, 0, 0, 0, + 0, 0, 126, 127, 128, 121, 125, 122, 123, 124, + 22, 33, 34, 129, 130, 131, 90, 91, 59, 60, + 61, 32, 38, 39, 35, 36, 62, 63, 64, 65, + 68, 41, 66, 37, 42, 67, 72, 71, 0, 0, + 48, 0, 69, 0, 0, 0, 0, 111, 112, 113, + 0, 117, 118, 119, 120, 44, 0, 18, 0, 19, + 0, 0, 76, 186, 187, 147, 188, 185, 180, 149, + 179, 143, 0, 144, 198, 0, 0, 0, 0, 0, + 0, 0, 0, 224, 0, 0, 275, 0, 0, 203, + 0, 202, 199, 222, 0, 219, 0, 0, 0, 0, + 0, 278, 95, 94, 97, 96, 100, 101, 103, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 114, 115, 116, 40, 0, 20, 0, 0, 0, + 0, 145, 196, 193, 195, 0, 194, 190, 0, 191, + 257, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, + 0, 0, 0, 0, 205, 206, 208, 200, 0, 0, + 217, 218, 216, 0, 84, 0, 0, 70, 0, 81, + 52, 56, 141, 0, 0, 0, 49, 51, 50, 55, + 136, 0, 0, 0, 0, 0, 0, 0, 214, 211, + 210, 0, 0, 192, 249, 251, 252, 250, 237, 229, + 230, 232, 231, 233, 236, 0, 0, 241, 0, 0, + 0, 256, 238, 239, 0, 0, 0, 242, 266, 267, + 246, 0, 226, 0, 234, 276, 277, 220, 221, 43, + 86, 0, 0, 82, 54, 0, 139, 46, 0, 134, + 0, 0, 184, 181, 0, 0, 178, 0, 0, 0, + 171, 0, 0, 0, 0, 169, 170, 0, 197, 0, + 212, 105, 0, 0, 0, 265, 0, 0, 0, 0, + 0, 0, 0, 235, 88, 0, 140, 135, 0, 0, + 148, 0, 182, 154, 0, 151, 172, 0, 165, 167, + 168, 164, 173, 174, 175, 150, 0, 176, 213, 260, + 0, 0, 0, 0, 255, 0, 263, 243, 244, 245, + 272, 0, 0, 0, 89, 78, 79, 183, 153, 0, + 0, 0, 0, 163, 177, 240, 0, 258, 253, 254, + 264, 248, 0, 270, 155, 156, 157, 161, 162, 259, + 271, }; -short yydgoto[] = { 10, - 197, 122, 198, 201, 138, 164, 165, 289, 328, 329, - 96, 97, 98, 99, 42, 271, 259, 192, 193, 126, - 152, 212, 113, 100, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 23, 81, 82, 157, 158, 253, 118, - 83, 84, 119, 120, 254, 255, 24, 88, 89, 215, - 290, 216, 300, 325, 351, 352, 353, 301, 302, 303, - 291, 41, 178, 179, 261, 262, 30, 194, 181, 91, - 237, 238, 308, 311, 309, 312, 313, +short yydgoto[] = { 12, + 274, 171, 387, 275, 123, 189, 236, 237, 424, 470, + 471, 282, 347, 413, 283, 284, 145, 146, 147, 148, + 55, 385, 370, 269, 270, 176, 221, 295, 162, 149, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 27, 117, 118, 226, 227, 362, 167, 212, 354, + 119, 120, 51, 52, 168, 169, 363, 364, 355, 356, + 29, 131, 132, 300, 425, 301, 435, 467, 502, 503, + 504, 436, 437, 438, 426, 54, 251, 252, 372, 373, + 36, 271, 254, 134, 331, 332, 481, 401, 402, 492, + 447, 482, 448, 449, 493, 494, 58, 59, }; -short yysindex[] = { 122, - -200, 0, -238, 0, 0, -227, -228, -188, 0, 0, - 122, 0, 0, -220, -176, -164, -158, -155, -149, 0, - 0, -147, -88, -4, 0, -188, 0, 0, 4, -188, - 0, 0, 0, 0, 0, 0, 0, 0, 79, -240, - 11, 0, 0, 16, 20, 0, -218, -60, -40, -34, - -24, -14, -53, -53, -53, -193, -95, -190, -190, -190, - -190, -53, -53, -98, -56, -41, -162, -31, -53, -53, - -53, 6, 19, 22, 102, 161, 163, -204, -57, 0, - -120, 36, 0, 0, 0, -73, -205, -115, 38, -241, - 177, 257, 258, 16, -69, 0, 49, 0, -29, 0, - -226, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, -33, -36, 0, 31, 32, - 51, 185, 0, 0, 0, 0, 0, 0, 0, 0, +short yysindex[] = { 419, + -172, 0, -236, 0, -91, 0, -224, -211, -71, -178, + 0, 0, 419, 0, 0, -166, -160, -158, -156, -154, + -144, -139, -128, 0, 0, -126, -49, -195, 10, 0, + -178, -198, 0, 0, 12, -178, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 349, 0, -7, -123, + -112, -115, -238, 23, 0, 0, -189, -110, -105, 43, + 31, 0, -98, -96, -94, -85, -76, -73, -190, -190, + -190, -86, -106, 33, -81, -81, -81, -81, -58, -190, + -190, -59, -50, -45, -121, -34, -32, -190, -190, -190, + -190, -190, 51, 56, 63, 64, 66, -190, 68, -190, + -190, 69, 71, -190, 123, 136, -7, 0, -190, 212, + 219, 220, 222, -258, -182, 0, 168, 89, 0, 0, + 0, 0, 73, 62, 0, 93, 0, 0, -181, -216, + -69, 94, -220, 230, 95, 96, 0, 99, 0, 312, + 313, 104, 43, -100, 0, 108, 0, -29, 0, -196, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, -31, -7, 0, 100, 92, 111, + 254, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, - 0, -277, 0, 0, 0, 0, 0, 188, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 57, 0, 0, -162, -53, 56, 193, -118, 60, 104, - 0, 59, 63, -25, 0, 0, 0, 69, 0, -188, - -188, -11, -7, 203, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 16, -20, -16, -9, 0, 0, - 0, 0, 73, 0, 209, 210, 0, 0, 0, 0, - -143, 0, 77, 0, 0, 78, -53, 75, -184, 215, - -36, 216, 217, 218, 232, -277, -10, 99, 0, 0, - 0, 0, 113, 114, 0, 0, 0, -1, 0, 0, - 0, 0, 236, 73, 123, -214, -222, 0, 0, 0, - -81, 124, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 121, 0, 125, 16, 16, 16, 0, 0, 130, - 0, 0, 0, 0, 0, 131, 0, 0, 0, -104, - 132, 0, -202, 129, -221, 0, -53, -53, -53, -100, - 0, 0, 134, 0, 136, 0, 0, -96, 138, 0, - 271, 125, 141, 3, 8, 12, 0, 0, 0, 142, - 0, 0, 143, 0, 0, -89, 0, 0, 0, 0, - 0, 0, 0, 0, 144, 0, 0, 0, 146, 0, - 0, 147, 0, 0, 0, 0, 0, 0, -185, -190, - 76, 100, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 43, 43, + 0, 257, 0, 43, 43, 43, 43, 0, 0, 0, + -68, 0, 0, 0, 0, 0, 258, 0, 127, 0, + 111, 126, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 129, 0, 0, -121, -190, 130, 265, -190, + -120, 133, 374, 0, 134, 135, 0, 137, 138, 0, + -25, 0, 0, 0, 141, 0, -178, -178, 21, 32, + 275, 0, 0, 0, 0, 0, 0, 0, 0, 43, + -178, 52, -108, 146, -21, -17, 147, -11, 5, 9, + 14, 0, 0, 0, 0, 148, 0, 116, 121, 286, + 287, 0, 0, 0, 0, -151, 0, 0, 154, 0, + 0, 155, -190, -190, 157, 152, -13, 143, -7, 35, + 294, -190, 160, 161, 300, 302, 304, -68, -70, 0, + 236, 171, 169, 170, 0, 0, 0, 0, 172, 175, + 0, 0, 0, 18, 0, -178, 164, 0, 188, 0, + 0, 0, 0, 322, 147, 191, 0, 0, 0, 0, + 0, 324, 148, 193, 328, 194, -207, -2, 0, 0, + 0, -92, 195, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 111, 331, 0, 196, 197, + 202, 0, 0, 0, 43, 43, 43, 0, 0, 0, + 0, 338, 0, 215, 0, 0, 0, 0, 0, 0, + 0, 232, 216, 0, 0, 237, 0, 0, 239, 0, + 43, 186, 0, 0, -41, 243, 0, -145, 240, -183, + 0, -190, -190, -190, -118, 0, 0, 245, 0, 246, + 0, 0, 249, 250, 251, 0, 379, 202, 255, 22, + 26, 30, 253, 0, 0, 248, 0, 0, 39, 256, + 0, 259, 0, 0, 260, 0, 0, -16, 0, 0, + 0, 0, 0, 0, 0, 0, 261, 0, 0, 0, + -101, 263, 252, 264, 0, 271, 0, 0, 0, 0, + 0, 389, 253, 272, 0, 0, 0, 0, 0, -218, + -81, 187, 192, 0, 0, 0, 273, 0, 0, 0, + 0, 0, 274, 0, 0, 0, 0, 0, 0, 0, 0, }; short yyrindex[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 400, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, -85, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 149, 0, + 0, 0, 522, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 280, 0, 0, + -117, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 282, 0, 0, 0, + 280, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 409, 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, 284, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 282, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 149, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 155, 158, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 284, 0, 0, 0, 0, 0, 290, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 159, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 291, 292, 0, + 0, -222, 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, @@ -371,137 +466,214 @@ short yyrindex[] = { 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, 294, 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, 41, -222, 0, 0, 0, 418, 0, 0, 0, + 0, 0, 0, 0, 0, 426, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 295, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 429, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 299, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 168, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 276, 0, 0, 0, + 0, 0, 0, 0, 428, 0, 0, 0, 0, 0, + 0, 0, 431, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 301, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 171, 0, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 432, 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, 297, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 433, 0, 0, + 0, 0, 434, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 303, 0, 0, 305, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 436, 0, 0, 0, 0, 0, 0, 0, + 0, 306, 308, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 173, 174, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; short yygindex[] = { 0, - 311, 0, 0, 211, 266, 0, 0, 357, 0, 0, - 350, 95, 0, -80, 0, 0, 0, 253, 255, -58, - 0, 212, -43, -8, 0, 438, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 369, 0, 0, 0, 0, - 0, 0, 331, 333, 0, 199, 0, 0, 367, 0, - 0, 0, 0, 0, 105, 108, 0, 0, 0, 156, - 170, 0, 0, 283, 0, 201, 0, 0, 0, 0, - 0, 226, 0, 0, 157, 0, 152, + -124, 0, 0, 0, -93, 320, 0, 0, 437, 0, + 0, 0, 0, 0, 0, 285, 425, -84, 0, 102, + 0, 0, 0, 301, 307, -75, 0, 242, -61, -10, + 0, 559, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 456, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 523, 406, 410, 0, 214, 0, 224, + 0, 0, 449, 0, 0, 0, 0, 0, 78, 80, + 0, 0, 0, 149, 158, 0, 0, 335, 0, 217, + 0, 0, 0, 0, 0, 267, 0, 0, 0, 0, + 0, 106, 0, 140, 0, 97, 0, 541, }; -#define YYTABLESIZE 465 -short yytable[] = { 29, - 128, 129, 130, 95, 159, 200, 222, 95, 196, 170, - 114, 115, 95, 184, 173, 85, 95, 43, 131, 132, - 319, 45, 22, 95, 334, 140, 141, 142, 338, 189, - 25, 95, 26, 292, 39, 95, 32, 179, 27, 28, - 95, 288, 102, 304, 95, 27, 28, 174, 95, 127, - 127, 127, 127, 94, 27, 28, 20, 27, 28, 86, - 87, 21, 209, 210, 211, 206, 207, 208, 123, 27, - 28, 27, 28, 357, 175, 176, 177, 166, 169, 293, - 33, 294, 116, 117, 295, 327, 296, 297, 298, 299, - 124, 125, 34, 94, 167, 187, 358, 94, 35, 241, - 322, 36, 94, 167, 249, 323, 94, 37, 250, 38, - 190, 191, 258, 94, 279, 251, 27, 28, 40, 149, - 150, 94, 151, 284, 248, 94, 44, 344, 136, 137, - 94, 219, 345, 90, 94, 46, 346, 173, 94, 267, - 268, 269, 101, 270, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 27, 28, 58, 59, 60, - 133, 307, 61, 62, 63, 64, 65, 66, 67, 68, - 174, 179, 69, 70, 71, 72, 73, 74, 27, 28, - 121, 243, 244, 265, 86, 87, 27, 28, 92, 93, - 27, 28, 75, 188, 314, 315, 316, 175, 176, 177, - 103, 293, 134, 294, 167, 108, 295, 162, 296, 297, - 298, 299, 260, 76, 77, 349, 350, 135, 78, 163, - 104, 199, 79, 80, 146, 195, 105, 139, 92, 93, - 27, 28, 92, 93, 27, 28, 106, 92, 93, 27, - 28, 92, 93, 27, 28, 225, 107, 169, 92, 93, - 27, 28, 260, 331, 332, 333, 92, 93, 27, 28, - 92, 93, 27, 28, 143, 92, 93, 27, 28, 92, - 93, 27, 28, 92, 93, 27, 28, 144, 188, 226, - 145, 169, 227, 147, 324, 148, 330, 153, 154, 155, - 156, 359, 161, 228, 172, 109, 110, 111, 112, 180, - 188, 188, 188, 182, 183, 186, 116, 205, 117, 195, - 213, 214, 229, 217, 220, 221, 224, 239, 230, 231, - 232, 240, 233, 234, 235, 242, 191, 247, 236, 190, - 252, 256, 257, 263, 46, 266, 264, 272, 274, 275, - 276, 127, 188, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 57, 277, 281, 58, 59, 60, 225, - 285, 61, 62, 63, 64, 65, 66, 67, 68, 282, - 283, 69, 70, 71, 72, 73, 74, 1, 307, 287, - 306, 350, 310, 2, 3, 4, 317, 318, 321, 326, - 336, 75, 337, 226, 340, 341, 227, 343, 347, 1, - 354, 348, 355, 356, 349, 19, 63, 228, 188, 188, - 188, 177, 76, 77, 156, 59, 60, 78, 91, 92, - 5, 79, 80, 202, 120, 203, 229, 106, 112, 113, - 114, 204, 230, 231, 232, 6, 233, 234, 235, 218, - 7, 273, 236, 168, 185, 246, 245, 278, 31, 160, - 203, 202, 286, 8, 171, 335, 361, 9, 360, 320, - 223, 305, 280, 342, 339, +#define YYTABLESIZE 788 +short yytable[] = { 35, + 178, 179, 180, 144, 308, 227, 476, 144, 163, 164, + 273, 144, 125, 211, 137, 144, 348, 128, 182, 183, + 56, 144, 143, 506, 26, 61, 192, 193, 194, 195, + 196, 28, 439, 30, 122, 245, 202, 144, 204, 205, + 515, 144, 208, 33, 34, 279, 144, 213, 423, 31, + 144, 32, 33, 34, 144, 242, 83, 83, 144, 266, + 48, 57, 144, 265, 177, 177, 177, 177, 157, 135, + 136, 144, 276, 47, 516, 144, 33, 34, 33, 34, + 246, 33, 34, 461, 24, 129, 130, 49, 50, 25, + 38, 218, 219, 143, 220, 264, 39, 143, 40, 337, + 41, 143, 42, 351, 369, 143, 298, 352, 33, 34, + 234, 143, 43, 357, 33, 34, 239, 44, 238, 241, + 247, 248, 249, 250, 235, 239, 83, 143, 45, 358, + 46, 143, 53, 359, 60, 245, 143, 124, 360, 227, + 143, 127, 410, 48, 143, 133, 488, 469, 143, 57, + 489, 139, 143, 150, 490, 172, 480, 140, 141, 33, + 34, 143, 151, 496, 152, 143, 153, 33, 34, 170, + 49, 50, 281, 267, 268, 154, 265, 173, 33, 34, + 246, 464, 187, 188, 155, 304, 465, 156, 307, 165, + 166, 158, 159, 160, 161, 222, 223, 224, 225, 184, + 265, 265, 181, 265, 265, 265, 265, 428, 185, 429, + 174, 175, 430, 186, 431, 432, 433, 434, 33, 34, + 247, 248, 249, 250, 190, 388, 191, 272, 140, 141, + 33, 34, 140, 141, 33, 34, 140, 141, 33, 34, + 140, 141, 33, 34, 261, 209, 140, 141, 33, 34, + 121, 376, 377, 427, 129, 130, 339, 340, 210, 265, + 392, 442, 140, 141, 33, 34, 140, 141, 33, 34, + 345, 140, 141, 33, 34, 140, 141, 33, 34, 140, + 141, 33, 34, 140, 141, 33, 34, 140, 141, 33, + 34, 239, 228, 389, 390, 371, 140, 141, 33, 34, + 140, 141, 33, 34, 292, 293, 294, 399, 400, 197, + 285, 286, 500, 501, 198, 288, 289, 290, 291, 85, + 85, 199, 200, 428, 201, 429, 203, 206, 430, 207, + 431, 432, 433, 434, 214, 411, 380, 381, 382, 142, + 383, 215, 216, 142, 217, 230, 232, 142, 231, 233, + 244, 142, 253, 255, 256, 257, 241, 142, 258, 259, + 403, 371, 384, 260, 263, 265, 265, 265, 166, 272, + 473, 474, 475, 142, 265, 165, 280, 142, 281, 287, + 296, 344, 142, 297, 299, 302, 142, 306, 305, 310, + 142, 268, 333, 334, 142, 335, 336, 338, 142, 343, + 346, 267, 350, 365, 353, 361, 366, 142, 367, 368, + 374, 142, 379, 375, 241, 378, 391, 466, 386, 472, + 393, 394, 395, 62, 396, 517, 397, 405, 408, 406, + 407, 409, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 412, 414, 74, 415, 417, 418, 420, + 421, 441, 422, 443, 444, 445, 75, 76, 77, 446, + 453, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 454, 460, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 177, 311, 455, 457, 456, 458, 450, 451, 452, 463, + 468, 478, 479, 485, 105, 106, 480, 495, 483, 484, + 491, 487, 509, 512, 497, 498, 501, 505, 499, 508, + 500, 1, 459, 107, 510, 108, 109, 511, 514, 520, + 521, 102, 110, 111, 112, 113, 77, 312, 21, 114, + 225, 313, 137, 115, 116, 314, 204, 98, 99, 315, + 132, 104, 138, 166, 87, 133, 261, 262, 268, 152, + 269, 158, 159, 316, 160, 303, 240, 349, 262, 398, + 342, 37, 229, 126, 278, 341, 419, 277, 416, 243, + 519, 518, 462, 477, 317, 309, 507, 486, 440, 513, + 318, 319, 320, 321, 322, 323, 324, 404, 138, 325, + 326, 327, 0, 0, 62, 0, 0, 328, 0, 0, + 0, 329, 330, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 0, 0, 74, 0, 0, 311, + 0, 0, 0, 0, 0, 0, 0, 75, 76, 77, + 0, 0, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 0, 0, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, + 104, 0, 0, 0, 1, 312, 0, 0, 0, 313, + 2, 3, 4, 314, 0, 105, 106, 315, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 316, 0, 0, 107, 0, 108, 109, 0, 0, + 0, 0, 0, 110, 111, 112, 113, 0, 0, 0, + 114, 0, 317, 0, 115, 116, 0, 0, 318, 319, + 320, 321, 322, 323, 324, 0, 0, 325, 326, 327, + 0, 6, 0, 0, 0, 328, 0, 0, 0, 329, + 330, 0, 0, 0, 0, 0, 0, 7, 0, 0, + 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 9, 10, 0, 0, 0, 0, 0, 11, }; -short yycheck[] = { 8, - 59, 60, 61, 33, 125, 42, 125, 33, 42, 125, - 54, 55, 33, 94, 256, 256, 33, 26, 62, 63, - 125, 30, 261, 33, 125, 69, 70, 71, 125, 256, - 258, 33, 261, 256, 123, 33, 257, 123, 260, 261, - 33, 256, 261, 125, 33, 260, 261, 289, 33, 58, - 59, 60, 61, 123, 260, 261, 257, 260, 261, 300, - 301, 262, 340, 341, 342, 146, 147, 148, 259, 260, - 261, 260, 261, 259, 316, 317, 318, 86, 87, 302, - 257, 304, 276, 277, 307, 307, 309, 310, 311, 312, - 281, 282, 257, 123, 309, 125, 282, 123, 257, 125, - 303, 257, 123, 309, 125, 308, 123, 257, 125, 257, - 337, 338, 256, 123, 125, 125, 260, 261, 123, 324, - 325, 123, 327, 125, 205, 123, 123, 125, 291, 292, - 123, 175, 125, 123, 123, 256, 125, 256, 123, 324, - 325, 326, 123, 328, 265, 266, 267, 268, 269, 270, - 271, 272, 273, 274, 275, 260, 261, 278, 279, 280, - 259, 258, 283, 284, 285, 286, 287, 288, 289, 290, - 289, 257, 293, 294, 295, 296, 297, 298, 260, 261, - 276, 190, 191, 227, 300, 301, 260, 261, 258, 259, - 260, 261, 313, 99, 275, 276, 277, 316, 317, 318, - 261, 302, 259, 304, 309, 259, 307, 281, 309, 310, - 311, 312, 221, 334, 335, 305, 306, 259, 339, 293, - 261, 258, 343, 344, 123, 259, 261, 259, 258, 259, - 260, 261, 258, 259, 260, 261, 261, 258, 259, 260, - 261, 258, 259, 260, 261, 256, 261, 256, 258, 259, - 260, 261, 261, 297, 298, 299, 258, 259, 260, 261, - 258, 259, 260, 261, 259, 258, 259, 260, 261, 258, - 259, 260, 261, 258, 259, 260, 261, 259, 184, 290, - 259, 290, 293, 123, 293, 123, 295, 345, 346, 347, - 348, 350, 257, 304, 257, 349, 350, 351, 352, 123, - 206, 207, 208, 47, 47, 257, 276, 123, 277, 259, - 123, 257, 323, 257, 259, 123, 257, 259, 329, 330, - 331, 259, 333, 334, 335, 257, 338, 125, 339, 337, - 258, 123, 123, 257, 256, 261, 259, 123, 123, 123, - 123, 350, 248, 265, 266, 267, 268, 269, 270, 271, - 272, 273, 274, 275, 123, 257, 278, 279, 280, 256, - 125, 283, 284, 285, 286, 287, 288, 289, 290, 257, - 257, 293, 294, 295, 296, 297, 298, 256, 258, 257, - 257, 306, 258, 262, 263, 264, 257, 257, 257, 261, - 257, 313, 257, 290, 257, 125, 293, 257, 257, 0, - 257, 259, 257, 257, 305, 257, 123, 304, 314, 315, - 316, 257, 334, 335, 257, 257, 257, 339, 125, 125, - 299, 343, 344, 125, 257, 125, 323, 257, 257, 257, - 257, 121, 329, 330, 331, 314, 333, 334, 335, 174, - 319, 231, 339, 87, 95, 193, 192, 236, 11, 81, - 120, 119, 254, 332, 88, 300, 352, 336, 351, 290, - 178, 261, 237, 312, 308, +short yycheck[] = { 10, + 76, 77, 78, 33, 125, 123, 125, 33, 70, 71, + 42, 33, 125, 107, 125, 33, 125, 256, 80, 81, + 31, 33, 123, 125, 261, 36, 88, 89, 90, 91, + 92, 123, 125, 258, 42, 256, 98, 33, 100, 101, + 259, 33, 104, 260, 261, 170, 33, 109, 256, 261, + 33, 123, 260, 261, 33, 125, 279, 280, 33, 256, + 256, 260, 33, 148, 75, 76, 77, 78, 259, 259, + 260, 33, 166, 123, 293, 33, 260, 261, 260, 261, + 301, 260, 261, 125, 257, 324, 325, 283, 284, 262, + 257, 350, 351, 123, 353, 125, 257, 123, 257, 125, + 257, 123, 257, 125, 256, 123, 231, 125, 260, 261, + 292, 123, 257, 125, 260, 261, 333, 257, 129, 130, + 341, 342, 343, 344, 306, 333, 349, 123, 257, 125, + 257, 123, 123, 125, 123, 256, 123, 261, 125, 257, + 123, 257, 125, 256, 123, 123, 125, 331, 123, 260, + 125, 257, 123, 123, 125, 123, 258, 258, 259, 260, + 261, 123, 261, 125, 261, 123, 261, 260, 261, 276, + 283, 284, 281, 370, 371, 261, 261, 259, 260, 261, + 301, 327, 304, 305, 261, 247, 332, 261, 250, 276, + 277, 382, 383, 384, 385, 378, 379, 380, 381, 259, + 285, 286, 261, 288, 289, 290, 291, 326, 259, 328, + 292, 293, 331, 259, 333, 334, 335, 336, 260, 261, + 341, 342, 343, 344, 259, 319, 259, 259, 258, 259, + 260, 261, 258, 259, 260, 261, 258, 259, 260, 261, + 258, 259, 260, 261, 143, 123, 258, 259, 260, 261, + 258, 313, 314, 256, 324, 325, 267, 268, 123, 344, + 322, 386, 258, 259, 260, 261, 258, 259, 260, 261, + 281, 258, 259, 260, 261, 258, 259, 260, 261, 258, + 259, 260, 261, 258, 259, 260, 261, 258, 259, 260, + 261, 333, 125, 259, 260, 306, 258, 259, 260, 261, + 258, 259, 260, 261, 373, 374, 375, 378, 379, 259, + 209, 210, 329, 330, 259, 214, 215, 216, 217, 279, + 280, 259, 259, 326, 259, 328, 259, 259, 331, 259, + 333, 334, 335, 336, 123, 346, 350, 351, 352, 369, + 354, 123, 123, 369, 123, 257, 285, 369, 276, 257, + 257, 369, 123, 259, 259, 257, 367, 369, 47, 47, + 125, 372, 376, 260, 257, 450, 451, 452, 277, 259, + 432, 433, 434, 369, 459, 276, 123, 369, 281, 123, + 123, 280, 369, 257, 259, 257, 369, 123, 259, 257, + 369, 371, 259, 259, 369, 259, 259, 257, 369, 125, + 349, 370, 257, 288, 258, 258, 286, 369, 123, 123, + 257, 369, 261, 259, 425, 259, 123, 428, 276, 430, + 261, 261, 123, 256, 123, 501, 123, 257, 257, 261, + 261, 257, 265, 266, 267, 268, 269, 270, 271, 272, + 273, 274, 275, 280, 257, 278, 125, 257, 125, 257, + 123, 257, 259, 123, 259, 259, 289, 290, 291, 258, + 123, 294, 295, 296, 297, 298, 299, 300, 301, 302, + 303, 257, 287, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, + 501, 256, 261, 257, 279, 257, 395, 396, 397, 257, + 261, 257, 257, 125, 337, 338, 258, 260, 259, 259, + 258, 257, 261, 125, 259, 257, 330, 257, 259, 257, + 329, 0, 421, 356, 261, 358, 359, 257, 257, 257, + 257, 123, 365, 366, 367, 368, 257, 302, 257, 372, + 257, 306, 125, 376, 377, 310, 257, 257, 257, 314, + 125, 123, 125, 257, 279, 125, 125, 125, 125, 257, + 125, 257, 257, 328, 257, 246, 130, 283, 144, 328, + 270, 13, 117, 51, 169, 269, 363, 168, 355, 131, + 503, 502, 425, 435, 349, 251, 481, 448, 372, 493, + 355, 356, 357, 358, 359, 360, 361, 331, 58, 364, + 365, 366, -1, -1, 256, -1, -1, 372, -1, -1, + -1, 376, 377, 265, 266, 267, 268, 269, 270, 271, + 272, 273, 274, 275, -1, -1, 278, -1, -1, 256, + -1, -1, -1, -1, -1, -1, -1, 289, 290, 291, + -1, -1, 294, 295, 296, 297, 298, 299, 300, 301, + 302, 303, -1, -1, 306, 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 322, -1, -1, -1, 256, 302, -1, -1, -1, 306, + 262, 263, 264, 310, -1, 337, 338, 314, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 282, 328, -1, -1, 356, -1, 358, 359, -1, -1, + -1, -1, -1, 365, 366, 367, 368, -1, -1, -1, + 372, -1, 349, -1, 376, 377, -1, -1, 355, 356, + 357, 358, 359, 360, 361, -1, -1, 364, 365, 366, + -1, 323, -1, -1, -1, 372, -1, -1, -1, 376, + 377, -1, -1, -1, -1, -1, -1, 339, -1, -1, + -1, -1, -1, 345, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 362, 363, -1, -1, -1, -1, -1, 369, }; -#define YYFINAL 10 +#define YYFINAL 12 #ifndef YYDEBUG #define YYDEBUG 0 #endif -#define YYMAXTOKEN 352 +#define YYMAXTOKEN 385 #if YYDEBUG char *yyname[] = { "end-of-file",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, @@ -514,18 +686,25 @@ char *yyname[] = { "L_IPADDR","L_NUMBER","L_STRING","L_QSTRING","L_END_INCLUDE","T_INCLUDE", "T_OPTIONS","T_DIRECTORY","T_PIDFILE","T_NAMED_XFER","T_DUMP_FILE", "T_STATS_FILE","T_MEMSTATS_FILE","T_FAKE_IQUERY","T_RECURSION","T_FETCH_GLUE", -"T_QUERY_SOURCE","T_LISTEN_ON","T_PORT","T_ADDRESS","T_DATASIZE","T_STACKSIZE", -"T_CORESIZE","T_DEFAULT","T_UNLIMITED","T_FILES","T_HOSTSTATS", -"T_DEALLOC_ON_EXIT","T_TRANSFERS_IN","T_TRANSFERS_OUT","T_TRANSFERS_PER_NS", -"T_TRANSFER_FORMAT","T_MAX_TRANSFER_TIME_IN","T_ONE_ANSWER","T_MANY_ANSWERS", -"T_NOTIFY","T_AUTH_NXDOMAIN","T_MULTIPLE_CNAMES","T_CLEAN_INTERVAL", -"T_INTERFACE_INTERVAL","T_STATS_INTERVAL","T_LOGGING","T_CATEGORY","T_CHANNEL", +"T_QUERY_SOURCE","T_LISTEN_ON","T_PORT","T_ADDRESS","T_RRSET_ORDER","T_ORDER", +"T_NAME","T_CLASS","T_CONTROLS","T_INET","T_UNIX","T_PERM","T_OWNER","T_GROUP", +"T_ALLOW","T_DATASIZE","T_STACKSIZE","T_CORESIZE","T_DEFAULT","T_UNLIMITED", +"T_FILES","T_VERSION","T_HOSTSTATS","T_DEALLOC_ON_EXIT","T_TRANSFERS_IN", +"T_TRANSFERS_OUT","T_TRANSFERS_PER_NS","T_TRANSFER_FORMAT", +"T_MAX_TRANSFER_TIME_IN","T_SERIAL_QUERIES","T_ONE_ANSWER","T_MANY_ANSWERS", +"T_NOTIFY","T_AUTH_NXDOMAIN","T_MULTIPLE_CNAMES","T_USE_IXFR", +"T_MAINTAIN_IXFR_BASE","T_CLEAN_INTERVAL","T_INTERFACE_INTERVAL", +"T_STATS_INTERVAL","T_MAX_LOG_SIZE_IXFR","T_HEARTBEAT","T_USE_ID_POOL", +"T_MAX_NCACHE_TTL","T_HAS_OLD_CLIENTS","T_RFC2308_TYPE1","T_LAME_TTL", +"T_MIN_ROOTS","T_TREAT_CR_AS_SPACE","T_LOGGING","T_CATEGORY","T_CHANNEL", "T_SEVERITY","T_DYNAMIC","T_FILE","T_VERSIONS","T_SIZE","T_SYSLOG","T_DEBUG", "T_NULL_OUTPUT","T_PRINT_TIME","T_PRINT_CATEGORY","T_PRINT_SEVERITY", -"T_TOPOLOGY","T_SERVER","T_LONG_AXFR","T_BOGUS","T_TRANSFERS","T_KEYS","T_ZONE", -"T_IN","T_CHAOS","T_HESIOD","T_TYPE","T_MASTER","T_SLAVE","T_STUB","T_RESPONSE", -"T_HINT","T_MASTERS","T_TRANSFER_SOURCE","T_ALSO_NOTIFY","T_ACL", -"T_ALLOW_UPDATE","T_ALLOW_QUERY","T_ALLOW_TRANSFER","T_SEC_KEY","T_ALGID", +"T_SORTLIST","T_TOPOLOGY","T_SERVER","T_LONG_AXFR","T_BOGUS","T_TRANSFERS", +"T_KEYS","T_SUPPORT_IXFR","T_ZONE","T_IN","T_CHAOS","T_HESIOD","T_TYPE", +"T_MASTER","T_SLAVE","T_STUB","T_RESPONSE","T_HINT","T_MASTERS", +"T_TRANSFER_SOURCE","T_PUBKEY","T_ALSO_NOTIFY","T_DIALUP","T_FILE_IXFR", +"T_IXFR_TMP","T_TRUSTED_KEYS","T_ACL","T_ALLOW_UPDATE","T_ALLOW_QUERY", +"T_ALLOW_TRANSFER","T_ALLOW_RECURSION","T_BLACKHOLE","T_SEC_KEY","T_ALGID", "T_SECRET","T_CHECK_NAMES","T_WARN","T_FAIL","T_IGNORE","T_FORWARD", "T_FORWARDERS","T_ONLY","T_FIRST","T_IF_NO_ANSWER","T_IF_NO_DOMAIN","T_YES", "T_TRUE","T_NO","T_FALSE", @@ -537,9 +716,11 @@ char *yyrule[] = { "statement_list : statement_list statement", "statement : include_stmt", "statement : options_stmt L_EOS", +"statement : controls_stmt L_EOS", "statement : logging_stmt L_EOS", "statement : server_stmt L_EOS", "statement : zone_stmt L_EOS", +"statement : trusted_keys_stmt L_EOS", "statement : acl_stmt L_EOS", "statement : key_stmt L_EOS", "statement : L_END_INCLUDE", @@ -551,6 +732,7 @@ char *yyrule[] = { "options : option L_EOS", "options : options option L_EOS", "option :", +"option : T_VERSION L_QSTRING", "option : T_DIRECTORY L_QSTRING", "option : T_NAMED_XFER L_QSTRING", "option : T_PIDFILE L_QSTRING", @@ -563,25 +745,61 @@ char *yyrule[] = { "option : T_NOTIFY yea_or_nay", "option : T_HOSTSTATS yea_or_nay", "option : T_DEALLOC_ON_EXIT yea_or_nay", +"option : T_USE_IXFR yea_or_nay", +"option : T_MAINTAIN_IXFR_BASE yea_or_nay", +"option : T_HAS_OLD_CLIENTS yea_or_nay", "option : T_AUTH_NXDOMAIN yea_or_nay", "option : T_MULTIPLE_CNAMES yea_or_nay", "option : T_CHECK_NAMES check_names_type check_names_opt", +"option : T_USE_ID_POOL yea_or_nay", +"option : T_RFC2308_TYPE1 yea_or_nay", "option : T_LISTEN_ON maybe_port '{' address_match_list '}'", "option : T_FORWARD forward_opt", "$$2 :", "option : T_FORWARDERS $$2 '{' opt_forwarders_list '}'", "option : T_QUERY_SOURCE query_source", +"option : T_TRANSFER_SOURCE maybe_wild_addr", "option : T_ALLOW_QUERY '{' address_match_list '}'", +"option : T_ALLOW_RECURSION '{' address_match_list '}'", "option : T_ALLOW_TRANSFER '{' address_match_list '}'", +"option : T_SORTLIST '{' address_match_list '}'", +"$$3 :", +"option : T_ALSO_NOTIFY $$3 '{' opt_also_notify_list '}'", +"option : T_BLACKHOLE '{' address_match_list '}'", "option : T_TOPOLOGY '{' address_match_list '}'", "option : size_clause", "option : transfer_clause", "option : T_TRANSFER_FORMAT transfer_format", "option : T_MAX_TRANSFER_TIME_IN L_NUMBER", +"option : T_SERIAL_QUERIES L_NUMBER", "option : T_CLEAN_INTERVAL L_NUMBER", "option : T_INTERFACE_INTERVAL L_NUMBER", "option : T_STATS_INTERVAL L_NUMBER", +"option : T_MAX_LOG_SIZE_IXFR L_NUMBER", +"option : T_MAX_NCACHE_TTL L_NUMBER", +"option : T_LAME_TTL L_NUMBER", +"option : T_HEARTBEAT L_NUMBER", +"option : T_DIALUP yea_or_nay", +"option : T_RRSET_ORDER '{' rrset_ordering_list '}'", +"option : T_TREAT_CR_AS_SPACE yea_or_nay", +"option : T_MIN_ROOTS L_NUMBER", "option : error", +"controls_stmt : T_CONTROLS '{' controls '}'", +"controls : control L_EOS", +"controls : controls control L_EOS", +"control :", +"control : T_INET maybe_wild_addr T_PORT in_port T_ALLOW '{' address_match_list '}'", +"control : T_UNIX L_QSTRING T_PERM L_NUMBER T_OWNER L_NUMBER T_GROUP L_NUMBER", +"control : error", +"rrset_ordering_list : rrset_ordering_element L_EOS", +"rrset_ordering_list : rrset_ordering_list rrset_ordering_element L_EOS", +"ordering_class :", +"ordering_class : T_CLASS any_string", +"ordering_type :", +"ordering_type : T_TYPE any_string", +"ordering_name :", +"ordering_name : T_NAME L_QSTRING", +"rrset_ordering_element : ordering_class ordering_type ordering_name T_ORDER L_STRING", "transfer_format : T_ONE_ANSWER", "transfer_format : T_MANY_ANSWERS", "maybe_wild_addr : L_IPADDR", @@ -596,6 +814,8 @@ char *yyrule[] = { "query_source : query_source_port query_source_address", "maybe_port :", "maybe_port : T_PORT in_port", +"maybe_zero_port :", +"maybe_zero_port : T_PORT in_port", "yea_or_nay : T_YES", "yea_or_nay : T_TRUE", "yea_or_nay : T_NO", @@ -627,15 +847,20 @@ char *yyrule[] = { "forwarders_in_addr_list : forwarders_in_addr L_EOS", "forwarders_in_addr_list : forwarders_in_addr_list forwarders_in_addr L_EOS", "forwarders_in_addr : L_IPADDR", -"$$3 :", -"logging_stmt : T_LOGGING $$3 '{' logging_opts_list '}'", +"opt_also_notify_list :", +"opt_also_notify_list : also_notify_in_addr_list", +"also_notify_in_addr_list : also_notify_in_addr L_EOS", +"also_notify_in_addr_list : also_notify_in_addr_list also_notify_in_addr L_EOS", +"also_notify_in_addr : L_IPADDR", +"$$4 :", +"logging_stmt : T_LOGGING $$4 '{' logging_opts_list '}'", "logging_opts_list : logging_opt L_EOS", "logging_opts_list : logging_opts_list logging_opt L_EOS", "logging_opts_list : error", -"$$4 :", -"logging_opt : T_CATEGORY category $$4 '{' channel_list '}'", "$$5 :", -"logging_opt : T_CHANNEL channel_name $$5 '{' channel_opt_list '}'", +"logging_opt : T_CATEGORY category $$5 '{' channel_list '}'", +"$$6 :", +"logging_opt : T_CHANNEL channel_name $$6 '{' channel_opt_list '}'", "channel_severity : any_string", "channel_severity : T_DEBUG", "channel_severity : T_DEBUG L_NUMBER", @@ -674,11 +899,12 @@ char *yyrule[] = { "category_name : T_DEFAULT", "category_name : T_NOTIFY", "category : category_name", -"$$6 :", -"server_stmt : T_SERVER L_IPADDR $$6 '{' server_info_list '}'", +"$$7 :", +"server_stmt : T_SERVER L_IPADDR $$7 '{' server_info_list '}'", "server_info_list : server_info L_EOS", "server_info_list : server_info_list server_info L_EOS", "server_info : T_BOGUS yea_or_nay", +"server_info : T_SUPPORT_IXFR yea_or_nay", "server_info : T_TRANSFERS L_NUMBER", "server_info : T_TRANSFER_FORMAT transfer_format", "server_info : T_KEYS '{' key_list '}'", @@ -687,6 +913,7 @@ char *yyrule[] = { "address_match_list : address_match_list address_match_element L_EOS", "address_match_element : address_match_simple", "address_match_element : '!' address_match_simple", +"address_match_element : T_SEC_KEY L_STRING", "address_match_simple : L_IPADDR", "address_match_simple : L_IPADDR '/' L_NUMBER", "address_match_simple : L_NUMBER '/' L_NUMBER", @@ -698,16 +925,16 @@ char *yyrule[] = { "key_list : key_list_element L_EOS", "key_list : key_list key_list_element L_EOS", "key_list : error", -"$$7 :", -"key_stmt : T_SEC_KEY $$7 any_string '{' key_definition '}'", +"$$8 :", +"key_stmt : T_SEC_KEY $$8 any_string '{' key_definition '}'", "key_definition : algorithm_id secret", "key_definition : secret algorithm_id", "key_definition : error", "algorithm_id : T_ALGID any_string L_EOS", "secret : T_SECRET any_string L_EOS", "acl_stmt : T_ACL any_string '{' address_match_list '}'", -"$$8 :", -"zone_stmt : T_ZONE L_QSTRING optional_class $$8 optional_zone_options_list", +"$$9 :", +"zone_stmt : T_ZONE L_QSTRING optional_class $$9 optional_zone_options_list", "optional_zone_options_list :", "optional_zone_options_list : '{' zone_option_list '}'", "optional_class :", @@ -716,19 +943,30 @@ char *yyrule[] = { "zone_type : T_SLAVE", "zone_type : T_HINT", "zone_type : T_STUB", +"zone_type : T_FORWARD", "zone_option_list : zone_option L_EOS", "zone_option_list : zone_option_list zone_option L_EOS", "zone_option : T_TYPE zone_type", "zone_option : T_FILE L_QSTRING", -"zone_option : T_MASTERS '{' master_in_addr_list '}'", +"zone_option : T_FILE_IXFR L_QSTRING", +"zone_option : T_IXFR_TMP L_QSTRING", +"zone_option : T_MASTERS maybe_zero_port '{' master_in_addr_list '}'", "zone_option : T_TRANSFER_SOURCE maybe_wild_addr", "zone_option : T_CHECK_NAMES check_names_opt", "zone_option : T_ALLOW_UPDATE '{' address_match_list '}'", "zone_option : T_ALLOW_QUERY '{' address_match_list '}'", "zone_option : T_ALLOW_TRANSFER '{' address_match_list '}'", +"zone_option : T_FORWARD zone_forward_opt", +"$$10 :", +"zone_option : T_FORWARDERS $$10 '{' opt_zone_forwarders_list '}'", "zone_option : T_MAX_TRANSFER_TIME_IN L_NUMBER", +"zone_option : T_MAX_LOG_SIZE_IXFR L_NUMBER", "zone_option : T_NOTIFY yea_or_nay", +"zone_option : T_MAINTAIN_IXFR_BASE yea_or_nay", +"zone_option : T_PUBKEY L_NUMBER L_NUMBER L_NUMBER L_QSTRING", +"zone_option : T_PUBKEY L_STRING L_NUMBER L_NUMBER L_QSTRING", "zone_option : T_ALSO_NOTIFY '{' opt_notify_in_addr_list '}'", +"zone_option : T_DIALUP yea_or_nay", "zone_option : error", "master_in_addr_list : master_in_addr L_EOS", "master_in_addr_list : master_in_addr_list master_in_addr L_EOS", @@ -738,6 +976,18 @@ char *yyrule[] = { "notify_in_addr_list : notify_in_addr L_EOS", "notify_in_addr_list : notify_in_addr_list notify_in_addr L_EOS", "notify_in_addr : L_IPADDR", +"zone_forward_opt : T_ONLY", +"zone_forward_opt : T_FIRST", +"opt_zone_forwarders_list :", +"opt_zone_forwarders_list : zone_forwarders_in_addr_list", +"zone_forwarders_in_addr_list : zone_forwarders_in_addr L_EOS", +"zone_forwarders_in_addr_list : zone_forwarders_in_addr_list zone_forwarders_in_addr L_EOS", +"zone_forwarders_in_addr : L_IPADDR", +"trusted_keys_stmt : T_TRUSTED_KEYS '{' trusted_keys_list '}'", +"trusted_keys_list : trusted_key L_EOS", +"trusted_keys_list : trusted_keys_list trusted_key L_EOS", +"trusted_key : L_STRING L_NUMBER L_NUMBER L_NUMBER L_QSTRING", +"trusted_key : L_STRING L_STRING L_NUMBER L_NUMBER L_QSTRING", "in_port : L_NUMBER", "any_string : L_STRING", "any_string : L_QSTRING", @@ -768,7 +1018,7 @@ struct yystack { int yychar; /* some people use this, so we copy it in & out */ int yyerrflag; /* must be global for yyerrok & YYRECOVERING */ YYSTYPE yylval; -#line 1282 "ns_parser.y" +#line 1776 "ns_parser.y" static char * canonical_name(char *name) { @@ -873,6 +1123,7 @@ parser_setup() { authtab = new_symbol_table(AUTH_TABLE_SIZE, free_sym_value); init_acls(); define_builtin_channels(); + INIT_LIST(current_controls); } static void @@ -913,25 +1164,25 @@ define_acl(char *name, ip_match_list iml) { dprint_ip_match_list(ns_log_parser, iml, 2, "allow ", "deny "); } -key_info +struct dst_key * lookup_key(char *name) { symbol_value value; if (lookup_symbol(authtab, name, SYM_KEY, &value)) - return ((key_info)(value.pointer)); + return ((struct dst_key *)(value.pointer)); return (NULL); } void -define_key(char *name, key_info ki) { +define_key(char *name, struct dst_key *dst_key) { symbol_value value; INSIST(name != NULL); - INSIST(ki != NULL); + INSIST(dst_key != NULL); - value.pointer = ki; + value.pointer = dst_key; define_symbol(authtab, name, SYM_KEY, value, SYMBOL_FREE_VALUE); - dprint_key_info(ki); + dprint_key_info(dst_key); } void @@ -961,7 +1212,7 @@ parser_shutdown(void) { free_symbol_table(authtab); lexer_shutdown(); } -#line 965 "y.tab.c" +#line 1216 "y.tab.c" /* allocate initial stack */ #if defined(__STDC__) || defined(__cplusplus) static int yyinitstack(struct yystack *sp) @@ -1157,25 +1408,27 @@ yyreduce: switch (yyn) { case 1: -#line 206 "ns_parser.y" +#line 241 "ns_parser.y" { - /* nothing */ + if (EMPTY(current_controls)) + ns_ctl_defaults(¤t_controls); + ns_ctl_install(¤t_controls); } break; -case 14: -#line 227 "ns_parser.y" +case 16: +#line 266 "ns_parser.y" { lexer_begin_file(yyvsp[-1].cp, NULL); } break; -case 15: -#line 235 "ns_parser.y" +case 17: +#line 274 "ns_parser.y" { if (seen_options) parser_error(0, "cannot redefine options"); current_options = new_options(); } break; -case 16: -#line 241 "ns_parser.y" +case 18: +#line 280 "ns_parser.y" { if (!seen_options) set_options(current_options, 0); @@ -1185,113 +1438,164 @@ case 16: seen_options = 1; } break; -case 20: -#line 257 "ns_parser.y" +case 22: +#line 296 "ns_parser.y" +{ + if (current_options->version != NULL) + freestr(current_options->version); + current_options->version = yyvsp[0].cp; + } +break; +case 23: +#line 302 "ns_parser.y" { if (current_options->directory != NULL) freestr(current_options->directory); current_options->directory = yyvsp[0].cp; } break; -case 21: -#line 263 "ns_parser.y" +case 24: +#line 308 "ns_parser.y" { if (current_options->named_xfer != NULL) freestr(current_options->named_xfer); current_options->named_xfer = yyvsp[0].cp; } break; -case 22: -#line 269 "ns_parser.y" +case 25: +#line 314 "ns_parser.y" { if (current_options->pid_filename != NULL) freestr(current_options->pid_filename); current_options->pid_filename = yyvsp[0].cp; } break; -case 23: -#line 275 "ns_parser.y" +case 26: +#line 320 "ns_parser.y" { if (current_options->stats_filename != NULL) freestr(current_options->stats_filename); current_options->stats_filename = yyvsp[0].cp; } break; -case 24: -#line 281 "ns_parser.y" +case 27: +#line 326 "ns_parser.y" { if (current_options->memstats_filename != NULL) freestr(current_options->memstats_filename); current_options->memstats_filename = yyvsp[0].cp; } break; -case 25: -#line 287 "ns_parser.y" +case 28: +#line 332 "ns_parser.y" { if (current_options->dump_filename != NULL) freestr(current_options->dump_filename); current_options->dump_filename = yyvsp[0].cp; } break; -case 26: -#line 293 "ns_parser.y" +case 29: +#line 338 "ns_parser.y" { - set_boolean_option(current_options, OPTION_FAKE_IQUERY, yyvsp[0].num); + set_global_boolean_option(current_options, + OPTION_FAKE_IQUERY, yyvsp[0].num); } break; -case 27: -#line 297 "ns_parser.y" +case 30: +#line 343 "ns_parser.y" { - set_boolean_option(current_options, OPTION_NORECURSE, !yyvsp[0].num); + set_global_boolean_option(current_options, + OPTION_NORECURSE, !yyvsp[0].num); } break; -case 28: -#line 301 "ns_parser.y" +case 31: +#line 348 "ns_parser.y" { - set_boolean_option(current_options, OPTION_NOFETCHGLUE, !yyvsp[0].num); + set_global_boolean_option(current_options, + OPTION_NOFETCHGLUE, !yyvsp[0].num); } break; -case 29: -#line 305 "ns_parser.y" +case 32: +#line 353 "ns_parser.y" { - set_boolean_option(current_options, OPTION_NONOTIFY, !yyvsp[0].num); + set_global_boolean_option(current_options, + OPTION_NONOTIFY, !yyvsp[0].num); } break; -case 30: -#line 309 "ns_parser.y" +case 33: +#line 358 "ns_parser.y" { - set_boolean_option(current_options, OPTION_HOSTSTATS, yyvsp[0].num); + set_global_boolean_option(current_options, + OPTION_HOSTSTATS, yyvsp[0].num); } break; -case 31: -#line 313 "ns_parser.y" +case 34: +#line 363 "ns_parser.y" { - set_boolean_option(current_options, OPTION_DEALLOC_ON_EXIT, - yyvsp[0].num); + set_global_boolean_option(current_options, + OPTION_DEALLOC_ON_EXIT, yyvsp[0].num); } break; -case 32: -#line 318 "ns_parser.y" +case 35: +#line 368 "ns_parser.y" { - set_boolean_option(current_options, OPTION_NONAUTH_NXDOMAIN, + set_global_boolean_option(current_options, OPTION_USE_IXFR, yyvsp[0].num); + } +break; +case 36: +#line 372 "ns_parser.y" +{ + set_global_boolean_option(current_options, + OPTION_MAINTAIN_IXFR_BASE, yyvsp[0].num); + } +break; +case 37: +#line 377 "ns_parser.y" +{ + set_global_boolean_option(current_options, + OPTION_MAINTAIN_IXFR_BASE, yyvsp[0].num); + set_global_boolean_option(current_options, + OPTION_NORFC2308_TYPE1, yyvsp[0].num); + set_global_boolean_option(current_options, + OPTION_NONAUTH_NXDOMAIN, !yyvsp[0].num); + } +break; +case 38: +#line 386 "ns_parser.y" +{ + set_global_boolean_option(current_options, OPTION_NONAUTH_NXDOMAIN, !yyvsp[0].num); } break; -case 33: -#line 323 "ns_parser.y" +case 39: +#line 391 "ns_parser.y" { - set_boolean_option(current_options, OPTION_MULTIPLE_CNAMES, - yyvsp[0].num); + set_global_boolean_option(current_options, + OPTION_MULTIPLE_CNAMES, yyvsp[0].num); } break; -case 34: -#line 328 "ns_parser.y" +case 40: +#line 396 "ns_parser.y" { - current_options->check_names[yyvsp[-1].s_int] = yyvsp[0].s_int; + current_options->check_names[yyvsp[-1].s_int] = (enum severity)yyvsp[0].s_int; } break; -case 35: -#line 332 "ns_parser.y" +case 41: +#line 400 "ns_parser.y" +{ + set_global_boolean_option(current_options, + OPTION_USE_ID_POOL, yyvsp[0].num); + } +break; +case 42: +#line 405 "ns_parser.y" +{ + set_global_boolean_option(current_options, + OPTION_NORFC2308_TYPE1, !yyvsp[0].num); + } +break; +case 43: +#line 410 "ns_parser.y" { char port_string[10]; symbol_value value; @@ -1310,8 +1614,8 @@ case 35: } break; -case 37: -#line 351 "ns_parser.y" +case 45: +#line 429 "ns_parser.y" { if (current_options->fwdtab) { free_forwarders(current_options->fwdtab); @@ -1319,140 +1623,386 @@ case 37: } } break; -case 40: -#line 360 "ns_parser.y" +case 48: +#line 438 "ns_parser.y" { - if (current_options->query_acl) - free_ip_match_list(current_options->query_acl); - current_options->query_acl = yyvsp[-1].iml; + current_options->axfr_src = yyvsp[0].ip_addr; } break; -case 41: -#line 366 "ns_parser.y" +case 49: +#line 442 "ns_parser.y" { - if (current_options->transfer_acl) - free_ip_match_list(current_options->transfer_acl); - current_options->transfer_acl = yyvsp[-1].iml; + if (current_options->query_acl) { + parser_warning(0, + "options allow-query acl already set; skipping"); + free_ip_match_list(yyvsp[-1].iml); + } else + current_options->query_acl = yyvsp[-1].iml; } break; -case 42: -#line 372 "ns_parser.y" +case 50: +#line 451 "ns_parser.y" { - if (current_options->topology) - free_ip_match_list(current_options->topology); - current_options->topology = yyvsp[-1].iml; + if (current_options->recursion_acl) { + parser_warning(0, + "options allow-recursion acl already set; skipping"); + free_ip_match_list(yyvsp[-1].iml); + } else + current_options->recursion_acl = yyvsp[-1].iml; } break; -case 43: -#line 378 "ns_parser.y" +case 51: +#line 460 "ns_parser.y" +{ + if (current_options->transfer_acl) { + parser_warning(0, + "options allow-transfer acl already set; skipping"); + free_ip_match_list(yyvsp[-1].iml); + } else + current_options->transfer_acl = yyvsp[-1].iml; + } +break; +case 52: +#line 469 "ns_parser.y" +{ + if (current_options->sortlist) { + parser_warning(0, + "options sortlist already set; skipping"); + free_ip_match_list(yyvsp[-1].iml); + } else + current_options->sortlist = yyvsp[-1].iml; + } +break; +case 53: +#line 478 "ns_parser.y" +{ + if (current_options->also_notify) { + parser_warning(0, + "duplicate also-notify clause: overwriting"); + free_also_notify(current_options); + current_options->also_notify = NULL; + } + } +break; +case 55: +#line 488 "ns_parser.y" +{ + if (current_options->blackhole_acl) { + parser_warning(0, + "options blackhole already set; skipping"); + free_ip_match_list(yyvsp[-1].iml); + } else + current_options->blackhole_acl = yyvsp[-1].iml; + } +break; +case 56: +#line 497 "ns_parser.y" +{ + if (current_options->topology) { + parser_warning(0, + "options topology already set; skipping"); + free_ip_match_list(yyvsp[-1].iml); + } else + current_options->topology = yyvsp[-1].iml; + } +break; +case 57: +#line 506 "ns_parser.y" { /* To get around the $$ = $1 default rule. */ } break; -case 45: -#line 383 "ns_parser.y" +case 59: +#line 511 "ns_parser.y" { current_options->transfer_format = yyvsp[0].axfr_fmt; } break; -case 46: -#line 387 "ns_parser.y" +case 60: +#line 515 "ns_parser.y" { current_options->max_transfer_time_in = yyvsp[0].num * 60; } break; -case 47: -#line 391 "ns_parser.y" +case 61: +#line 519 "ns_parser.y" +{ + current_options->serial_queries = yyvsp[0].num; + } +break; +case 62: +#line 523 "ns_parser.y" { current_options->clean_interval = yyvsp[0].num * 60; } break; -case 48: -#line 395 "ns_parser.y" +case 63: +#line 527 "ns_parser.y" { current_options->interface_interval = yyvsp[0].num * 60; } break; -case 49: -#line 399 "ns_parser.y" +case 64: +#line 531 "ns_parser.y" { current_options->stats_interval = yyvsp[0].num * 60; } break; -case 51: -#line 406 "ns_parser.y" +case 65: +#line 535 "ns_parser.y" +{ + current_options->max_log_size_ixfr = yyvsp[0].num; + } +break; +case 66: +#line 539 "ns_parser.y" +{ + current_options->max_ncache_ttl = yyvsp[0].num; + } +break; +case 67: +#line 543 "ns_parser.y" +{ + current_options->lame_ttl = yyvsp[0].num; + } +break; +case 68: +#line 547 "ns_parser.y" +{ + current_options->heartbeat_interval = yyvsp[0].num * 60; + } +break; +case 69: +#line 551 "ns_parser.y" +{ + set_global_boolean_option(current_options, + OPTION_NODIALUP, !yyvsp[0].num); + } +break; +case 70: +#line 556 "ns_parser.y" +{ + if (current_options->ordering) + free_rrset_order_list(current_options->ordering); + current_options->ordering = yyvsp[-1].rol; + } +break; +case 71: +#line 562 "ns_parser.y" +{ + set_global_boolean_option(current_options, + OPTION_TREAT_CR_AS_SPACE, yyvsp[0].num); + } +break; +case 72: +#line 567 "ns_parser.y" +{ + if (yyvsp[0].num >= 1) + current_options->minroots = yyvsp[0].num; + } +break; +case 78: +#line 587 "ns_parser.y" +{ + ns_ctl_add(¤t_controls, ns_ctl_new_inet(yyvsp[-6].ip_addr, yyvsp[-4].us_int, yyvsp[-1].iml)); + } +break; +case 79: +#line 591 "ns_parser.y" +{ + ns_ctl_add(¤t_controls, ns_ctl_new_unix(yyvsp[-6].cp, yyvsp[-4].num, yyvsp[-2].num, yyvsp[0].num)); + } +break; +case 81: +#line 598 "ns_parser.y" +{ + rrset_order_list rol; + + rol = new_rrset_order_list(); + if (yyvsp[-1].roe != NULL) { + add_to_rrset_order_list(rol, yyvsp[-1].roe); + } + + yyval.rol = rol; + } +break; +case 82: +#line 609 "ns_parser.y" +{ + if (yyvsp[-1].roe != NULL) { + add_to_rrset_order_list(yyvsp[-2].rol, yyvsp[-1].roe); + } + yyval.rol = yyvsp[-2].rol; + } +break; +case 83: +#line 618 "ns_parser.y" +{ + yyval.s_int = C_ANY; + } +break; +case 84: +#line 622 "ns_parser.y" +{ + symbol_value value; + + if (lookup_symbol(constants, yyvsp[0].cp, SYM_CLASS, &value)) + yyval.s_int = value.integer; + else { + parser_error(0, "unknown class '%s'; using ANY", yyvsp[0].cp); + yyval.s_int = C_ANY; + } + freestr(yyvsp[0].cp); + } +break; +case 85: +#line 636 "ns_parser.y" +{ + yyval.s_int = ns_t_any; + } +break; +case 86: +#line 640 "ns_parser.y" +{ + int success; + + if (strcmp(yyvsp[0].cp, "*") == 0) { + yyval.s_int = ns_t_any; + } else { + yyval.s_int = __sym_ston(__p_type_syms, yyvsp[0].cp, &success); + if (success == 0) { + yyval.s_int = ns_t_any; + parser_error(0, + "unknown type '%s'; assuming ANY", + yyvsp[0].cp); + } + } + freestr(yyvsp[0].cp); + } +break; +case 87: +#line 658 "ns_parser.y" +{ + yyval.cp = savestr("*", 1); + } +break; +case 88: +#line 662 "ns_parser.y" +{ + if (strcmp(".",yyvsp[0].cp) == 0 || strcmp("*.",yyvsp[0].cp) == 0) { + yyval.cp = savestr("*", 1); + freestr(yyvsp[0].cp); + } else { + yyval.cp = yyvsp[0].cp ; + } + /* XXX Should do any more name validation here? */ + } +break; +case 89: +#line 674 "ns_parser.y" +{ + enum ordering o; + + if (strlen(yyvsp[0].cp) == 0) { + parser_error(0, "null order name"); + yyval.roe = NULL ; + } else { + o = lookup_ordering(yyvsp[0].cp); + if (o == unknown_order) { + o = (enum ordering)DEFAULT_ORDERING; + parser_error(0, + "invalid order name '%s'; using %s", + yyvsp[0].cp, p_order(o)); + } + + freestr(yyvsp[0].cp); + + yyval.roe = new_rrset_order_element(yyvsp[-4].s_int, yyvsp[-3].s_int, yyvsp[-2].cp, o); + } + } +break; +case 90: +#line 697 "ns_parser.y" { yyval.axfr_fmt = axfr_one_answer; } break; -case 52: -#line 410 "ns_parser.y" +case 91: +#line 701 "ns_parser.y" { yyval.axfr_fmt = axfr_many_answers; } break; -case 53: -#line 415 "ns_parser.y" +case 92: +#line 706 "ns_parser.y" { yyval.ip_addr = yyvsp[0].ip_addr; } break; -case 54: -#line 416 "ns_parser.y" +case 93: +#line 707 "ns_parser.y" { yyval.ip_addr.s_addr = htonl(INADDR_ANY); } break; -case 55: -#line 419 "ns_parser.y" +case 94: +#line 710 "ns_parser.y" { yyval.us_int = yyvsp[0].us_int; } break; -case 56: -#line 420 "ns_parser.y" +case 95: +#line 711 "ns_parser.y" { yyval.us_int = htons(0); } break; -case 57: -#line 424 "ns_parser.y" +case 96: +#line 715 "ns_parser.y" { current_options->query_source.sin_addr = yyvsp[0].ip_addr; } break; -case 58: -#line 430 "ns_parser.y" +case 97: +#line 721 "ns_parser.y" { current_options->query_source.sin_port = yyvsp[0].us_int; } break; -case 63: -#line 441 "ns_parser.y" +case 102: +#line 732 "ns_parser.y" { yyval.us_int = htons(NS_DEFAULTPORT); } break; -case 64: -#line 442 "ns_parser.y" +case 103: +#line 733 "ns_parser.y" { yyval.us_int = yyvsp[0].us_int; } break; -case 65: -#line 446 "ns_parser.y" +case 104: +#line 736 "ns_parser.y" +{ yyval.us_int = htons(0); } +break; +case 105: +#line 737 "ns_parser.y" +{ yyval.us_int = yyvsp[0].us_int; } +break; +case 106: +#line 742 "ns_parser.y" { yyval.num = 1; } break; -case 66: -#line 450 "ns_parser.y" +case 107: +#line 746 "ns_parser.y" { yyval.num = 1; } break; -case 67: -#line 454 "ns_parser.y" +case 108: +#line 750 "ns_parser.y" { yyval.num = 0; } break; -case 68: -#line 458 "ns_parser.y" +case 109: +#line 754 "ns_parser.y" { yyval.num = 0; } break; -case 69: -#line 462 "ns_parser.y" +case 110: +#line 758 "ns_parser.y" { if (yyvsp[0].num == 1 || yyvsp[0].num == 0) { yyval.num = yyvsp[0].num; @@ -1463,92 +2013,94 @@ case 69: } } break; -case 70: -#line 474 "ns_parser.y" +case 111: +#line 770 "ns_parser.y" { yyval.s_int = primary_trans; } break; -case 71: -#line 478 "ns_parser.y" +case 112: +#line 774 "ns_parser.y" { yyval.s_int = secondary_trans; } break; -case 72: -#line 482 "ns_parser.y" +case 113: +#line 778 "ns_parser.y" { yyval.s_int = response_trans; } break; -case 73: -#line 488 "ns_parser.y" +case 114: +#line 784 "ns_parser.y" { yyval.s_int = warn; } break; -case 74: -#line 492 "ns_parser.y" +case 115: +#line 788 "ns_parser.y" { yyval.s_int = fail; } break; -case 75: -#line 496 "ns_parser.y" +case 116: +#line 792 "ns_parser.y" { yyval.s_int = ignore; } break; -case 76: -#line 502 "ns_parser.y" +case 117: +#line 798 "ns_parser.y" { - set_boolean_option(current_options, OPTION_FORWARD_ONLY, 1); + set_global_boolean_option(current_options, + OPTION_FORWARD_ONLY, 1); } break; -case 77: -#line 506 "ns_parser.y" +case 118: +#line 803 "ns_parser.y" { - set_boolean_option(current_options, OPTION_FORWARD_ONLY, 0); + set_global_boolean_option(current_options, + OPTION_FORWARD_ONLY, 0); } break; -case 78: -#line 510 "ns_parser.y" +case 119: +#line 808 "ns_parser.y" { parser_warning(0, "forward if-no-answer is unimplemented"); } break; -case 79: -#line 514 "ns_parser.y" +case 120: +#line 812 "ns_parser.y" { parser_warning(0, "forward if-no-domain is unimplemented"); } break; -case 80: -#line 520 "ns_parser.y" +case 121: +#line 818 "ns_parser.y" { current_options->data_size = yyvsp[0].ul_int; } break; -case 81: -#line 524 "ns_parser.y" +case 122: +#line 822 "ns_parser.y" { current_options->stack_size = yyvsp[0].ul_int; } break; -case 82: -#line 528 "ns_parser.y" +case 123: +#line 826 "ns_parser.y" { current_options->core_size = yyvsp[0].ul_int; } break; -case 83: -#line 532 "ns_parser.y" +case 124: +#line 830 "ns_parser.y" { current_options->files = yyvsp[0].ul_int; } break; -case 84: -#line 538 "ns_parser.y" +case 125: +#line 836 "ns_parser.y" { u_long result; @@ -1562,89 +2114,107 @@ case 84: freestr(yyvsp[0].cp); } break; -case 85: -#line 551 "ns_parser.y" +case 126: +#line 849 "ns_parser.y" { yyval.ul_int = (u_long)yyvsp[0].num; } break; -case 86: -#line 555 "ns_parser.y" +case 127: +#line 853 "ns_parser.y" { yyval.ul_int = 0; } break; -case 87: -#line 559 "ns_parser.y" +case 128: +#line 857 "ns_parser.y" { yyval.ul_int = ULONG_MAX; } break; -case 88: -#line 565 "ns_parser.y" +case 129: +#line 863 "ns_parser.y" { current_options->transfers_in = (u_long) yyvsp[0].num; } break; -case 89: -#line 569 "ns_parser.y" +case 130: +#line 867 "ns_parser.y" { current_options->transfers_out = (u_long) yyvsp[0].num; } break; -case 90: -#line 573 "ns_parser.y" +case 131: +#line 871 "ns_parser.y" { current_options->transfers_per_ns = (u_long) yyvsp[0].num; } break; -case 93: -#line 583 "ns_parser.y" +case 134: +#line 881 "ns_parser.y" { /* nothing */ } break; -case 94: -#line 587 "ns_parser.y" +case 135: +#line 885 "ns_parser.y" { /* nothing */ } break; -case 95: -#line 593 "ns_parser.y" +case 136: +#line 891 "ns_parser.y" { - add_forwarder(current_options, yyvsp[0].ip_addr); + add_global_forwarder(current_options, yyvsp[0].ip_addr); } break; -case 96: -#line 603 "ns_parser.y" +case 139: +#line 901 "ns_parser.y" +{ + /* nothing */ + } +break; +case 140: +#line 905 "ns_parser.y" +{ + /* nothing */ + } +break; +case 141: +#line 911 "ns_parser.y" +{ + add_global_also_notify(current_options, yyvsp[0].ip_addr); + } +break; +case 142: +#line 921 "ns_parser.y" { current_logging = begin_logging(); } break; -case 97: -#line 607 "ns_parser.y" +case 143: +#line 925 "ns_parser.y" { end_logging(current_logging, 1); current_logging = NULL; } break; -case 101: -#line 619 "ns_parser.y" +case 147: +#line 937 "ns_parser.y" { current_category = yyvsp[0].s_int; } break; -case 103: -#line 624 "ns_parser.y" +case 149: +#line 942 "ns_parser.y" { chan_type = log_null; chan_flags = 0; chan_level = log_info; } break; -case 104: -#line 630 "ns_parser.y" +case 150: +#line 948 "ns_parser.y" { log_channel current_channel = NULL; @@ -1684,8 +2254,8 @@ case 104: } } break; -case 105: -#line 671 "ns_parser.y" +case 151: +#line 989 "ns_parser.y" { symbol_value value; @@ -1698,86 +2268,84 @@ case 105: freestr(yyvsp[0].cp); } break; -case 106: -#line 683 "ns_parser.y" +case 152: +#line 1001 "ns_parser.y" { chan_level = log_debug(1); } break; -case 107: -#line 687 "ns_parser.y" +case 153: +#line 1005 "ns_parser.y" { chan_level = yyvsp[0].num; } break; -case 108: -#line 691 "ns_parser.y" +case 154: +#line 1009 "ns_parser.y" { chan_level = 0; chan_flags |= LOG_USE_CONTEXT_LEVEL|LOG_REQUIRE_DEBUG; } break; -case 109: -#line 698 "ns_parser.y" +case 155: +#line 1016 "ns_parser.y" { chan_versions = yyvsp[0].num; - chan_flags |= LOG_TRUNCATE; } break; -case 110: -#line 703 "ns_parser.y" +case 156: +#line 1020 "ns_parser.y" { chan_versions = LOG_MAX_VERSIONS; - chan_flags |= LOG_TRUNCATE; } break; -case 111: -#line 710 "ns_parser.y" +case 157: +#line 1026 "ns_parser.y" { chan_max_size = yyvsp[0].ul_int; } break; -case 112: -#line 716 "ns_parser.y" +case 158: +#line 1032 "ns_parser.y" { chan_versions = 0; chan_max_size = ULONG_MAX; } break; -case 113: -#line 721 "ns_parser.y" +case 159: +#line 1037 "ns_parser.y" { chan_max_size = ULONG_MAX; } break; -case 114: -#line 725 "ns_parser.y" +case 160: +#line 1041 "ns_parser.y" { chan_versions = 0; } break; -case 117: -#line 733 "ns_parser.y" +case 163: +#line 1049 "ns_parser.y" { chan_flags |= LOG_CLOSE_STREAM; chan_type = log_file; chan_name = yyvsp[-1].cp; } break; -case 118: -#line 741 "ns_parser.y" +case 164: +#line 1057 "ns_parser.y" { yyval.cp = yyvsp[0].cp; } break; -case 119: -#line 742 "ns_parser.y" +case 165: +#line 1058 "ns_parser.y" { yyval.cp = savestr("syslog", 1); } break; -case 120: -#line 745 "ns_parser.y" +case 166: +#line 1061 "ns_parser.y" { yyval.s_int = LOG_DAEMON; } break; -case 121: -#line 747 "ns_parser.y" +case 167: +#line 1063 "ns_parser.y" { symbol_value value; @@ -1790,33 +2358,33 @@ case 121: freestr(yyvsp[0].cp); } break; -case 122: -#line 761 "ns_parser.y" +case 168: +#line 1077 "ns_parser.y" { chan_type = log_syslog; chan_facility = yyvsp[0].s_int; } break; -case 123: -#line 767 "ns_parser.y" +case 169: +#line 1083 "ns_parser.y" { /* nothing to do */ } break; -case 124: -#line 768 "ns_parser.y" +case 170: +#line 1084 "ns_parser.y" { /* nothing to do */ } break; -case 125: -#line 770 "ns_parser.y" +case 171: +#line 1086 "ns_parser.y" { chan_type = log_null; } break; -case 126: -#line 773 "ns_parser.y" +case 172: +#line 1089 "ns_parser.y" { /* nothing to do */ } break; -case 127: -#line 775 "ns_parser.y" +case 173: +#line 1091 "ns_parser.y" { if (yyvsp[0].num) chan_flags |= LOG_TIMESTAMP; @@ -1824,8 +2392,8 @@ case 127: chan_flags &= ~LOG_TIMESTAMP; } break; -case 128: -#line 782 "ns_parser.y" +case 174: +#line 1098 "ns_parser.y" { if (yyvsp[0].num) chan_flags |= LOG_PRINT_CATEGORY; @@ -1833,8 +2401,8 @@ case 128: chan_flags &= ~LOG_PRINT_CATEGORY; } break; -case 129: -#line 789 "ns_parser.y" +case 175: +#line 1105 "ns_parser.y" { if (yyvsp[0].num) chan_flags |= LOG_PRINT_LEVEL; @@ -1842,12 +2410,12 @@ case 129: chan_flags &= ~LOG_PRINT_LEVEL; } break; -case 134: -#line 803 "ns_parser.y" +case 180: +#line 1119 "ns_parser.y" { yyval.cp = savestr("null", 1); } break; -case 135: -#line 807 "ns_parser.y" +case 181: +#line 1123 "ns_parser.y" { log_channel channel; symbol_value value; @@ -1863,16 +2431,16 @@ case 135: freestr(yyvsp[0].cp); } break; -case 140: -#line 829 "ns_parser.y" +case 186: +#line 1145 "ns_parser.y" { yyval.cp = savestr("default", 1); } break; -case 141: -#line 830 "ns_parser.y" +case 187: +#line 1146 "ns_parser.y" { yyval.cp = savestr("notify", 1); } break; -case 142: -#line 834 "ns_parser.y" +case 188: +#line 1150 "ns_parser.y" { symbol_value value; @@ -1886,10 +2454,10 @@ case 142: freestr(yyvsp[0].cp); } break; -case 143: -#line 853 "ns_parser.y" +case 189: +#line 1169 "ns_parser.y" { - char *ip_printable; + const char *ip_printable; symbol_value value; ip_printable = inet_ntoa(yyvsp[0].ip_addr); @@ -1908,32 +2476,38 @@ case 143: current_server = begin_server(yyvsp[0].ip_addr); } break; -case 144: -#line 873 "ns_parser.y" +case 190: +#line 1189 "ns_parser.y" { end_server(current_server, !seen_server); } break; -case 147: -#line 883 "ns_parser.y" +case 193: +#line 1199 "ns_parser.y" { set_server_option(current_server, SERVER_INFO_BOGUS, yyvsp[0].num); } break; -case 148: -#line 887 "ns_parser.y" +case 194: +#line 1203 "ns_parser.y" +{ + set_server_option(current_server, SERVER_INFO_SUPPORT_IXFR, yyvsp[0].num); + } +break; +case 195: +#line 1207 "ns_parser.y" { set_server_transfers(current_server, (int)yyvsp[0].num); } break; -case 149: -#line 891 "ns_parser.y" +case 196: +#line 1211 "ns_parser.y" { set_server_transfer_format(current_server, yyvsp[0].axfr_fmt); } break; -case 152: -#line 903 "ns_parser.y" +case 199: +#line 1223 "ns_parser.y" { ip_match_list iml; @@ -1943,30 +2517,51 @@ case 152: yyval.iml = iml; } break; -case 153: -#line 912 "ns_parser.y" +case 200: +#line 1232 "ns_parser.y" { if (yyvsp[-1].ime != NULL) add_to_ip_match_list(yyvsp[-2].iml, yyvsp[-1].ime); yyval.iml = yyvsp[-2].iml; } break; -case 155: -#line 921 "ns_parser.y" +case 202: +#line 1241 "ns_parser.y" { if (yyvsp[0].ime != NULL) ip_match_negate(yyvsp[0].ime); yyval.ime = yyvsp[0].ime; } break; -case 156: -#line 929 "ns_parser.y" +case 203: +#line 1247 "ns_parser.y" +{ + char *key_name; + struct dst_key *dst_key; + + key_name = canonical_name(yyvsp[0].cp); + if (key_name == NULL) { + parser_error(0, "can't make key name '%s' canonical", + yyvsp[0].cp); + key_name = savestr("__bad_key__", 1); + } + dst_key = find_key(key_name, NULL); + if (dst_key == NULL) { + parser_error(0, "key \"%s\" not found", key_name); + yyval.ime = NULL; + } + else + yyval.ime = new_ip_match_key(dst_key); + } +break; +case 204: +#line 1268 "ns_parser.y" { yyval.ime = new_ip_match_pattern(yyvsp[0].ip_addr, 32); } break; -case 157: -#line 933 "ns_parser.y" +case 205: +#line 1272 "ns_parser.y" { if (yyvsp[0].num < 0 || yyvsp[0].num > 32) { parser_error(0, "mask bits out of range; skipping"); @@ -1979,8 +2574,8 @@ case 157: } } break; -case 158: -#line 945 "ns_parser.y" +case 206: +#line 1284 "ns_parser.y" { struct in_addr ia; @@ -2002,8 +2597,8 @@ case 158: } } break; -case 160: -#line 967 "ns_parser.y" +case 208: +#line 1306 "ns_parser.y" { char name[256]; @@ -2016,8 +2611,8 @@ case 160: yyval.ime = new_ip_match_indirect(yyvsp[-1].iml); } break; -case 161: -#line 981 "ns_parser.y" +case 209: +#line 1320 "ns_parser.y" { ip_match_list iml; @@ -2030,22 +2625,31 @@ case 161: freestr(yyvsp[0].cp); } break; -case 162: -#line 999 "ns_parser.y" +case 210: +#line 1338 "ns_parser.y" { - key_info ki; + struct dst_key *dst_key; + char *key_name; - ki = lookup_key(yyvsp[0].cp); - if (ki == NULL) { - parser_error(0, "unknown key '%s'", yyvsp[0].cp); + key_name = canonical_name(yyvsp[0].cp); + if (key_name == NULL) { + parser_error(0, "can't make key name '%s' canonical", + yyvsp[0].cp); yyval.keyi = NULL; - } else - yyval.keyi = ki; + } else { + dst_key = lookup_key(key_name); + if (dst_key == NULL) { + parser_error(0, "unknown key '%s'", key_name); + yyval.keyi = NULL; + } else + yyval.keyi = dst_key; + freestr(key_name); + } freestr(yyvsp[0].cp); } break; -case 163: -#line 1013 "ns_parser.y" +case 211: +#line 1361 "ns_parser.y" { if (yyvsp[0].keyi == NULL) parser_error(0, "empty key not added to server list "); @@ -2053,64 +2657,80 @@ case 163: add_server_key_info(current_server, yyvsp[0].keyi); } break; -case 167: -#line 1027 "ns_parser.y" +case 215: +#line 1375 "ns_parser.y" { current_algorithm = NULL; current_secret = NULL; } break; -case 168: -#line 1032 "ns_parser.y" +case 216: +#line 1380 "ns_parser.y" { - key_info ki; + struct dst_key *dst_key; + char *key_name; - if (lookup_key(yyvsp[-3].cp) != NULL) { - parser_error(0, "can't redefine key '%s'", yyvsp[-3].cp); - freestr(yyvsp[-3].cp); + key_name = canonical_name(yyvsp[-3].cp); + if (key_name == NULL) { + parser_error(0, "can't make key name '%s' canonical", + yyvsp[-3].cp); + } else if (lookup_key(key_name) != NULL) { + parser_error(0, "can't redefine key '%s'", key_name); + freestr(key_name); } else { if (current_algorithm == NULL || - current_secret == NULL) - parser_error(0, "skipping bad key '%s'", yyvsp[-3].cp); - else { - ki = new_key_info(yyvsp[-3].cp, current_algorithm, - current_secret); - define_key(yyvsp[-3].cp, ki); + current_secret == NULL) { + parser_error(0, "skipping bad key '%s'", + key_name); + freestr(key_name); + } else { + dst_key = new_key_info(key_name, + current_algorithm, + current_secret); + if (dst_key != NULL) { + define_key(key_name, dst_key); + if (secretkey_info == NULL) + secretkey_info = + new_key_info_list(); + add_to_key_info_list(secretkey_info, + dst_key); + } } } + freestr(yyvsp[-3].cp); } break; -case 169: -#line 1052 "ns_parser.y" +case 217: +#line 1416 "ns_parser.y" { current_algorithm = yyvsp[-1].cp; current_secret = yyvsp[0].cp; } break; -case 170: -#line 1057 "ns_parser.y" +case 218: +#line 1421 "ns_parser.y" { current_algorithm = yyvsp[0].cp; current_secret = yyvsp[-1].cp; } break; -case 171: -#line 1062 "ns_parser.y" +case 219: +#line 1426 "ns_parser.y" { current_algorithm = NULL; current_secret = NULL; } break; -case 172: -#line 1068 "ns_parser.y" +case 220: +#line 1432 "ns_parser.y" { yyval.cp = yyvsp[-1].cp; } break; -case 173: -#line 1071 "ns_parser.y" +case 221: +#line 1435 "ns_parser.y" { yyval.cp = yyvsp[-1].cp; } break; -case 174: -#line 1079 "ns_parser.y" +case 222: +#line 1443 "ns_parser.y" { if (lookup_acl(yyvsp[-3].cp) != NULL) { parser_error(0, "can't redefine ACL '%s'", yyvsp[-3].cp); @@ -2119,8 +2739,8 @@ case 174: define_acl(yyvsp[-3].cp, yyvsp[-1].iml); } break; -case 175: -#line 1093 "ns_parser.y" +case 223: +#line 1457 "ns_parser.y" { int sym_type; symbol_value value; @@ -2135,35 +2755,40 @@ case 175: if (zone_name == NULL) { parser_error(0, "can't make zone name '%s' canonical", yyvsp[-1].cp); - seen_zone = 1; + should_install = 0; zone_name = savestr("__bad_zone__", 1); } else { - seen_zone = lookup_symbol(symtab, zone_name, sym_type, - NULL); - if (seen_zone) { + if (lookup_symbol(symtab, zone_name, sym_type, NULL)) { + should_install = 0; parser_error(0, - "cannot redefine zone '%s' class %d", - zone_name, yyvsp[0].num); - } else - define_symbol(symtab, zone_name, sym_type, - value, 0); + "cannot redefine zone '%s' class %s", + *zone_name ? zone_name : ".", + p_class(yyvsp[0].num)); + } else { + should_install = 1; + define_symbol(symtab, savestr(zone_name, 1), + sym_type, value, + SYMBOL_FREE_KEY); + } } freestr(yyvsp[-1].cp); current_zone = begin_zone(zone_name, yyvsp[0].num); } break; -case 176: -#line 1124 "ns_parser.y" -{ end_zone(current_zone, !seen_zone); } +case 224: +#line 1491 "ns_parser.y" +{ + end_zone(current_zone, should_install); + } break; -case 179: -#line 1132 "ns_parser.y" +case 227: +#line 1501 "ns_parser.y" { yyval.num = C_IN; } break; -case 180: -#line 1136 "ns_parser.y" +case 228: +#line 1505 "ns_parser.y" { symbol_value value; @@ -2176,135 +2801,284 @@ case 180: freestr(yyvsp[0].cp); } break; -case 181: -#line 1150 "ns_parser.y" +case 229: +#line 1519 "ns_parser.y" { yyval.s_int = Z_MASTER; } break; -case 182: -#line 1154 "ns_parser.y" +case 230: +#line 1523 "ns_parser.y" { yyval.s_int = Z_SLAVE; } break; -case 183: -#line 1158 "ns_parser.y" +case 231: +#line 1527 "ns_parser.y" { yyval.s_int = Z_HINT; } break; -case 184: -#line 1162 "ns_parser.y" +case 232: +#line 1531 "ns_parser.y" { yyval.s_int = Z_STUB; } break; -case 187: -#line 1172 "ns_parser.y" +case 233: +#line 1535 "ns_parser.y" +{ + yyval.s_int = Z_FORWARD; + } +break; +case 236: +#line 1545 "ns_parser.y" { if (!set_zone_type(current_zone, yyvsp[0].s_int)) parser_warning(0, "zone type already set; skipping"); } break; -case 188: -#line 1177 "ns_parser.y" +case 237: +#line 1550 "ns_parser.y" { if (!set_zone_filename(current_zone, yyvsp[0].cp)) parser_warning(0, "zone filename already set; skipping"); } break; -case 190: -#line 1184 "ns_parser.y" +case 238: +#line 1556 "ns_parser.y" +{ + if (!set_zone_ixfr_file(current_zone, yyvsp[0].cp)) + parser_warning(0, + "zone ixfr data base already set; skipping"); + } +break; +case 239: +#line 1562 "ns_parser.y" +{ + if (!set_zone_ixfr_tmp(current_zone, yyvsp[0].cp)) + parser_warning(0, + "zone ixfr temp filename already set; skipping"); + } +break; +case 240: +#line 1568 "ns_parser.y" +{ + set_zone_master_port(current_zone, yyvsp[-3].us_int); + } +break; +case 241: +#line 1572 "ns_parser.y" { set_zone_transfer_source(current_zone, yyvsp[0].ip_addr); } break; -case 191: -#line 1188 "ns_parser.y" +case 242: +#line 1576 "ns_parser.y" { - if (!set_zone_checknames(current_zone, yyvsp[0].s_int)) + if (!set_zone_checknames(current_zone, (enum severity)yyvsp[0].s_int)) parser_warning(0, "zone checknames already set; skipping"); } break; -case 192: -#line 1194 "ns_parser.y" +case 243: +#line 1582 "ns_parser.y" { if (!set_zone_update_acl(current_zone, yyvsp[-1].iml)) parser_warning(0, "zone update acl already set; skipping"); } break; -case 193: -#line 1200 "ns_parser.y" +case 244: +#line 1588 "ns_parser.y" { if (!set_zone_query_acl(current_zone, yyvsp[-1].iml)) parser_warning(0, "zone query acl already set; skipping"); } break; -case 194: -#line 1206 "ns_parser.y" +case 245: +#line 1594 "ns_parser.y" { if (!set_zone_transfer_acl(current_zone, yyvsp[-1].iml)) parser_warning(0, "zone transfer acl already set; skipping"); } break; -case 195: -#line 1212 "ns_parser.y" +case 247: +#line 1601 "ns_parser.y" +{ + struct zoneinfo *zp = current_zone.opaque; + if (zp->z_fwdtab) { + free_forwarders(zp->z_fwdtab); + zp->z_fwdtab = NULL; + } + + } +break; +case 249: +#line 1611 "ns_parser.y" { if (!set_zone_transfer_time_in(current_zone, yyvsp[0].num*60)) parser_warning(0, "zone max transfer time (in) already set; skipping"); } break; -case 196: -#line 1218 "ns_parser.y" +case 250: +#line 1617 "ns_parser.y" +{ + set_zone_max_log_size_ixfr(current_zone, yyvsp[0].num); + } +break; +case 251: +#line 1621 "ns_parser.y" { set_zone_notify(current_zone, yyvsp[0].num); } break; -case 199: -#line 1226 "ns_parser.y" +case 252: +#line 1625 "ns_parser.y" +{ + set_zone_maintain_ixfr_base(current_zone, yyvsp[0].num); + } +break; +case 253: +#line 1629 "ns_parser.y" +{ + /* flags proto alg key */ + set_zone_pubkey(current_zone, yyvsp[-3].num, yyvsp[-2].num, yyvsp[-1].num, yyvsp[0].cp); + } +break; +case 254: +#line 1634 "ns_parser.y" +{ + /* flags proto alg key */ + char *endp; + int flags = (int) strtol(yyvsp[-3].cp, &endp, 0); + if (*endp != '\0') + ns_panic(ns_log_parser, 1, + "Invalid flags string: %s", yyvsp[-3].cp); + set_zone_pubkey(current_zone, flags, yyvsp[-2].num, yyvsp[-1].num, yyvsp[0].cp); + + } +break; +case 256: +#line 1646 "ns_parser.y" +{ + set_zone_dialup(current_zone, yyvsp[0].num); + } +break; +case 258: +#line 1653 "ns_parser.y" { /* nothing */ } break; -case 200: -#line 1230 "ns_parser.y" +case 259: +#line 1657 "ns_parser.y" { /* nothing */ } break; -case 201: -#line 1236 "ns_parser.y" +case 260: +#line 1663 "ns_parser.y" { add_zone_master(current_zone, yyvsp[0].ip_addr); } break; -case 204: -#line 1246 "ns_parser.y" +case 263: +#line 1673 "ns_parser.y" { /* nothing */ } break; -case 205: -#line 1250 "ns_parser.y" +case 264: +#line 1677 "ns_parser.y" { /* nothing */ } break; -case 206: -#line 1256 "ns_parser.y" +case 265: +#line 1683 "ns_parser.y" { add_zone_notify(current_zone, yyvsp[0].ip_addr); } break; -case 207: -#line 1266 "ns_parser.y" +case 266: +#line 1689 "ns_parser.y" +{ + set_zone_boolean_option(current_zone, OPTION_FORWARD_ONLY, 1); + } +break; +case 267: +#line 1693 "ns_parser.y" +{ + set_zone_boolean_option(current_zone, OPTION_FORWARD_ONLY, 0); + } +break; +case 268: +#line 1699 "ns_parser.y" +{ + set_zone_forward(current_zone); + } +break; +case 270: +#line 1706 "ns_parser.y" +{ + /* nothing */ + } +break; +case 271: +#line 1710 "ns_parser.y" +{ + /* nothing */ + } +break; +case 272: +#line 1716 "ns_parser.y" +{ + add_zone_forwarder(current_zone, yyvsp[0].ip_addr); + } +break; +case 273: +#line 1726 "ns_parser.y" +{ + } +break; +case 274: +#line 1730 "ns_parser.y" +{ + /* nothing */ + } +break; +case 275: +#line 1734 "ns_parser.y" +{ + /* nothing */ + } +break; +case 276: +#line 1739 "ns_parser.y" +{ + /* name flags proto alg key */ + set_trusted_key(yyvsp[-4].cp, yyvsp[-3].num, yyvsp[-2].num, yyvsp[-1].num, yyvsp[0].cp); + } +break; +case 277: +#line 1744 "ns_parser.y" +{ + /* name flags proto alg key */ + char *endp; + int flags = (int) strtol(yyvsp[-3].cp, &endp, 0); + if (*endp != '\0') + ns_panic(ns_log_parser, 1, + "Invalid flags string: %s", yyvsp[-3].cp); + set_trusted_key(yyvsp[-4].cp, flags, yyvsp[-2].num, yyvsp[-1].num, yyvsp[0].cp); + } +break; +case 278: +#line 1760 "ns_parser.y" { if (yyvsp[0].num < 0 || yyvsp[0].num > 65535) { parser_warning(0, @@ -2315,7 +3089,7 @@ case 207: yyval.us_int = htons(yyvsp[0].num); } break; -#line 2319 "y.tab.c" +#line 3093 "y.tab.c" } yystk.ssp -= yym; yystate = *yystk.ssp; diff --git a/contrib/bind/bin/named/ns_parser.h b/contrib/bind/bin/named/ns_parser.h index 1d23613..571fb47 100644 --- a/contrib/bind/bin/named/ns_parser.h +++ b/contrib/bind/bin/named/ns_parser.h @@ -20,81 +20,114 @@ #define T_LISTEN_ON 275 #define T_PORT 276 #define T_ADDRESS 277 -#define T_DATASIZE 278 -#define T_STACKSIZE 279 -#define T_CORESIZE 280 -#define T_DEFAULT 281 -#define T_UNLIMITED 282 -#define T_FILES 283 -#define T_HOSTSTATS 284 -#define T_DEALLOC_ON_EXIT 285 -#define T_TRANSFERS_IN 286 -#define T_TRANSFERS_OUT 287 -#define T_TRANSFERS_PER_NS 288 -#define T_TRANSFER_FORMAT 289 -#define T_MAX_TRANSFER_TIME_IN 290 -#define T_ONE_ANSWER 291 -#define T_MANY_ANSWERS 292 -#define T_NOTIFY 293 -#define T_AUTH_NXDOMAIN 294 -#define T_MULTIPLE_CNAMES 295 -#define T_CLEAN_INTERVAL 296 -#define T_INTERFACE_INTERVAL 297 -#define T_STATS_INTERVAL 298 -#define T_LOGGING 299 -#define T_CATEGORY 300 -#define T_CHANNEL 301 -#define T_SEVERITY 302 -#define T_DYNAMIC 303 -#define T_FILE 304 -#define T_VERSIONS 305 -#define T_SIZE 306 -#define T_SYSLOG 307 -#define T_DEBUG 308 -#define T_NULL_OUTPUT 309 -#define T_PRINT_TIME 310 -#define T_PRINT_CATEGORY 311 -#define T_PRINT_SEVERITY 312 -#define T_TOPOLOGY 313 -#define T_SERVER 314 -#define T_LONG_AXFR 315 -#define T_BOGUS 316 -#define T_TRANSFERS 317 -#define T_KEYS 318 -#define T_ZONE 319 -#define T_IN 320 -#define T_CHAOS 321 -#define T_HESIOD 322 -#define T_TYPE 323 -#define T_MASTER 324 -#define T_SLAVE 325 -#define T_STUB 326 -#define T_RESPONSE 327 -#define T_HINT 328 -#define T_MASTERS 329 -#define T_TRANSFER_SOURCE 330 -#define T_ALSO_NOTIFY 331 -#define T_ACL 332 -#define T_ALLOW_UPDATE 333 -#define T_ALLOW_QUERY 334 -#define T_ALLOW_TRANSFER 335 -#define T_SEC_KEY 336 -#define T_ALGID 337 -#define T_SECRET 338 -#define T_CHECK_NAMES 339 -#define T_WARN 340 -#define T_FAIL 341 -#define T_IGNORE 342 -#define T_FORWARD 343 -#define T_FORWARDERS 344 -#define T_ONLY 345 -#define T_FIRST 346 -#define T_IF_NO_ANSWER 347 -#define T_IF_NO_DOMAIN 348 -#define T_YES 349 -#define T_TRUE 350 -#define T_NO 351 -#define T_FALSE 352 +#define T_RRSET_ORDER 278 +#define T_ORDER 279 +#define T_NAME 280 +#define T_CLASS 281 +#define T_CONTROLS 282 +#define T_INET 283 +#define T_UNIX 284 +#define T_PERM 285 +#define T_OWNER 286 +#define T_GROUP 287 +#define T_ALLOW 288 +#define T_DATASIZE 289 +#define T_STACKSIZE 290 +#define T_CORESIZE 291 +#define T_DEFAULT 292 +#define T_UNLIMITED 293 +#define T_FILES 294 +#define T_VERSION 295 +#define T_HOSTSTATS 296 +#define T_DEALLOC_ON_EXIT 297 +#define T_TRANSFERS_IN 298 +#define T_TRANSFERS_OUT 299 +#define T_TRANSFERS_PER_NS 300 +#define T_TRANSFER_FORMAT 301 +#define T_MAX_TRANSFER_TIME_IN 302 +#define T_SERIAL_QUERIES 303 +#define T_ONE_ANSWER 304 +#define T_MANY_ANSWERS 305 +#define T_NOTIFY 306 +#define T_AUTH_NXDOMAIN 307 +#define T_MULTIPLE_CNAMES 308 +#define T_USE_IXFR 309 +#define T_MAINTAIN_IXFR_BASE 310 +#define T_CLEAN_INTERVAL 311 +#define T_INTERFACE_INTERVAL 312 +#define T_STATS_INTERVAL 313 +#define T_MAX_LOG_SIZE_IXFR 314 +#define T_HEARTBEAT 315 +#define T_USE_ID_POOL 316 +#define T_MAX_NCACHE_TTL 317 +#define T_HAS_OLD_CLIENTS 318 +#define T_RFC2308_TYPE1 319 +#define T_LAME_TTL 320 +#define T_MIN_ROOTS 321 +#define T_TREAT_CR_AS_SPACE 322 +#define T_LOGGING 323 +#define T_CATEGORY 324 +#define T_CHANNEL 325 +#define T_SEVERITY 326 +#define T_DYNAMIC 327 +#define T_FILE 328 +#define T_VERSIONS 329 +#define T_SIZE 330 +#define T_SYSLOG 331 +#define T_DEBUG 332 +#define T_NULL_OUTPUT 333 +#define T_PRINT_TIME 334 +#define T_PRINT_CATEGORY 335 +#define T_PRINT_SEVERITY 336 +#define T_SORTLIST 337 +#define T_TOPOLOGY 338 +#define T_SERVER 339 +#define T_LONG_AXFR 340 +#define T_BOGUS 341 +#define T_TRANSFERS 342 +#define T_KEYS 343 +#define T_SUPPORT_IXFR 344 +#define T_ZONE 345 +#define T_IN 346 +#define T_CHAOS 347 +#define T_HESIOD 348 +#define T_TYPE 349 +#define T_MASTER 350 +#define T_SLAVE 351 +#define T_STUB 352 +#define T_RESPONSE 353 +#define T_HINT 354 +#define T_MASTERS 355 +#define T_TRANSFER_SOURCE 356 +#define T_PUBKEY 357 +#define T_ALSO_NOTIFY 358 +#define T_DIALUP 359 +#define T_FILE_IXFR 360 +#define T_IXFR_TMP 361 +#define T_TRUSTED_KEYS 362 +#define T_ACL 363 +#define T_ALLOW_UPDATE 364 +#define T_ALLOW_QUERY 365 +#define T_ALLOW_TRANSFER 366 +#define T_ALLOW_RECURSION 367 +#define T_BLACKHOLE 368 +#define T_SEC_KEY 369 +#define T_ALGID 370 +#define T_SECRET 371 +#define T_CHECK_NAMES 372 +#define T_WARN 373 +#define T_FAIL 374 +#define T_IGNORE 375 +#define T_FORWARD 376 +#define T_FORWARDERS 377 +#define T_ONLY 378 +#define T_FIRST 379 +#define T_IF_NO_ANSWER 380 +#define T_IF_NO_DOMAIN 381 +#define T_YES 382 +#define T_TRUE 383 +#define T_NO 384 +#define T_FALSE 385 typedef union { char * cp; int s_int; @@ -104,7 +137,9 @@ typedef union { struct in_addr ip_addr; ip_match_element ime; ip_match_list iml; - key_info keyi; + rrset_order_list rol; + rrset_order_element roe; + struct dst_key * keyi; enum axfr_format axfr_fmt; } YYSTYPE; extern YYSTYPE yylval; diff --git a/contrib/bind/bin/named/ns_parser.y b/contrib/bind/bin/named/ns_parser.y index 77dee0b..b381083 100644 --- a/contrib/bind/bin/named/ns_parser.y +++ b/contrib/bind/bin/named/ns_parser.y @@ -1,10 +1,10 @@ %{ #if !defined(lint) && !defined(SABER) -static char rcsid[] = "$Id: ns_parser.y,v 8.11 1997/12/04 07:03:05 halley Exp $"; +static char rcsid[] = "$Id: ns_parser.y,v 8.51 1999/11/12 05:29:18 vixie Exp $"; #endif /* not lint */ /* - * Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -25,6 +25,8 @@ static char rcsid[] = "$Id: ns_parser.y,v 8.11 1997/12/04 07:03:05 halley Exp $" #include "port_before.h" #include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -32,6 +34,7 @@ static char rcsid[] = "$Id: ns_parser.y,v 8.11 1997/12/04 07:03:05 halley Exp $" #include <ctype.h> #include <limits.h> +#include <resolv.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -41,6 +44,8 @@ static char rcsid[] = "$Id: ns_parser.y,v 8.11 1997/12/04 07:03:05 halley Exp $" #include <isc/eventlib.h> #include <isc/logging.h> +#include <isc/dst.h> + #include "port_after.h" #include "named.h" @@ -61,11 +66,13 @@ static symbol_table symtab; static symbol_table authtab = NULL; static zone_config current_zone; -static int seen_zone; +static int should_install; static options current_options; static int seen_options; +static controls current_controls; + static topology_config current_topology; static int seen_topology; @@ -90,7 +97,7 @@ static void define_channel(char *, log_channel); static char *canonical_name(char *); int yyparse(); - + %} %union { @@ -102,7 +109,9 @@ int yyparse(); struct in_addr ip_addr; ip_match_element ime; ip_match_list iml; - key_info keyi; + rrset_order_list rol; + rrset_order_element roe; + struct dst_key * keyi; enum axfr_format axfr_fmt; } @@ -121,22 +130,29 @@ int yyparse(); %token T_OPTIONS %token T_DIRECTORY T_PIDFILE T_NAMED_XFER %token T_DUMP_FILE T_STATS_FILE T_MEMSTATS_FILE -%token T_FAKE_IQUERY T_RECURSION T_FETCH_GLUE +%token T_FAKE_IQUERY T_RECURSION T_FETCH_GLUE %token T_QUERY_SOURCE T_LISTEN_ON T_PORT T_ADDRESS +%token T_RRSET_ORDER T_ORDER T_NAME T_CLASS +%token T_CONTROLS T_INET T_UNIX T_PERM T_OWNER T_GROUP T_ALLOW %type <us_int> in_port %type <us_int> maybe_port +%type <us_int> maybe_zero_port %type <us_int> maybe_wild_port %type <ip_addr> maybe_wild_addr %token T_DATASIZE T_STACKSIZE T_CORESIZE %token T_DEFAULT T_UNLIMITED -%token T_FILES +%token T_FILES T_VERSION %token T_HOSTSTATS T_DEALLOC_ON_EXIT %token T_TRANSFERS_IN T_TRANSFERS_OUT T_TRANSFERS_PER_NS %token T_TRANSFER_FORMAT T_MAX_TRANSFER_TIME_IN -%token T_ONE_ANSWER T_MANY_ANSWERS +%token T_SERIAL_QUERIES T_ONE_ANSWER T_MANY_ANSWERS %type <axfr_fmt> transfer_format -%token T_NOTIFY T_AUTH_NXDOMAIN T_MULTIPLE_CNAMES -%token T_CLEAN_INTERVAL T_INTERFACE_INTERVAL T_STATS_INTERVAL +%token T_NOTIFY T_AUTH_NXDOMAIN T_MULTIPLE_CNAMES T_USE_IXFR T_MAINTAIN_IXFR_BASE +%token T_CLEAN_INTERVAL T_INTERFACE_INTERVAL T_STATS_INTERVAL T_MAX_LOG_SIZE_IXFR +%token T_HEARTBEAT T_USE_ID_POOL +%token T_MAX_NCACHE_TTL T_HAS_OLD_CLIENTS T_RFC2308_TYPE1 +%token T_LAME_TTL T_MIN_ROOTS +%token T_TREAT_CR_AS_SPACE /* Items used for the "logging" statement: */ %token T_LOGGING T_CATEGORY T_CHANNEL T_SEVERITY T_DYNAMIC @@ -147,9 +163,18 @@ int yyparse(); %type <cp> category_name channel_name facility_name %type <s_int> maybe_syslog_facility +/* Items used for the "sortlist" statement: */ +%token T_SORTLIST + /* Items used for the "topology" statement: */ %token T_TOPOLOGY +%type <s_int> ordering_class +%type <s_int> ordering_type +%type <cp> ordering_name +%type <rol> rrset_ordering_list +%type <roe> rrset_ordering_element + /* ip_match_list */ %type <ime> address_match_simple address_match_element address_name %type <iml> address_match_list @@ -160,6 +185,7 @@ int yyparse(); %token T_BOGUS %token T_TRANSFERS %token T_KEYS +%token T_SUPPORT_IXFR /* Items used for "zone" statements: */ %token T_ZONE @@ -170,11 +196,20 @@ int yyparse(); %token T_MASTER T_SLAVE T_STUB T_RESPONSE %token T_HINT %token T_MASTERS T_TRANSFER_SOURCE +%token T_PUBKEY %token T_ALSO_NOTIFY +%token T_DIALUP +%token T_FILE_IXFR +%token T_IXFR_TMP + +/* Items used for "trusted-keys" statements: */ +%token T_TRUSTED_KEYS /* Items used for access control lists and "allow" clauses: */ %token T_ACL %token T_ALLOW_UPDATE T_ALLOW_QUERY T_ALLOW_TRANSFER +%token T_ALLOW_RECURSION +%token T_BLACKHOLE /* Items related to the "key" statement: */ %token T_SEC_KEY T_ALGID T_SECRET @@ -204,7 +239,9 @@ int yyparse(); %% config_file: statement_list { - /* nothing */ + if (EMPTY(current_controls)) + ns_ctl_defaults(¤t_controls); + ns_ctl_install(¤t_controls); } ; @@ -214,9 +251,11 @@ statement_list: statement statement: include_stmt | options_stmt L_EOS + | controls_stmt L_EOS | logging_stmt L_EOS | server_stmt L_EOS | zone_stmt L_EOS + | trusted_keys_stmt L_EOS | acl_stmt L_EOS | key_stmt L_EOS | L_END_INCLUDE @@ -253,6 +292,12 @@ options: option L_EOS ; option: /* Empty */ + | T_VERSION L_QSTRING + { + if (current_options->version != NULL) + freestr(current_options->version); + current_options->version = $2; + } | T_DIRECTORY L_QSTRING { if (current_options->directory != NULL) @@ -291,42 +336,75 @@ option: /* Empty */ } | T_FAKE_IQUERY yea_or_nay { - set_boolean_option(current_options, OPTION_FAKE_IQUERY, $2); + set_global_boolean_option(current_options, + OPTION_FAKE_IQUERY, $2); } | T_RECURSION yea_or_nay { - set_boolean_option(current_options, OPTION_NORECURSE, !$2); + set_global_boolean_option(current_options, + OPTION_NORECURSE, !$2); } | T_FETCH_GLUE yea_or_nay { - set_boolean_option(current_options, OPTION_NOFETCHGLUE, !$2); + set_global_boolean_option(current_options, + OPTION_NOFETCHGLUE, !$2); } | T_NOTIFY yea_or_nay { - set_boolean_option(current_options, OPTION_NONOTIFY, !$2); + set_global_boolean_option(current_options, + OPTION_NONOTIFY, !$2); } | T_HOSTSTATS yea_or_nay { - set_boolean_option(current_options, OPTION_HOSTSTATS, $2); + set_global_boolean_option(current_options, + OPTION_HOSTSTATS, $2); } | T_DEALLOC_ON_EXIT yea_or_nay { - set_boolean_option(current_options, OPTION_DEALLOC_ON_EXIT, - $2); + set_global_boolean_option(current_options, + OPTION_DEALLOC_ON_EXIT, $2); + } + | T_USE_IXFR yea_or_nay + { + set_global_boolean_option(current_options, OPTION_USE_IXFR, $2); + } + | T_MAINTAIN_IXFR_BASE yea_or_nay + { + set_global_boolean_option(current_options, + OPTION_MAINTAIN_IXFR_BASE, $2); + } + | T_HAS_OLD_CLIENTS yea_or_nay + { + set_global_boolean_option(current_options, + OPTION_MAINTAIN_IXFR_BASE, $2); + set_global_boolean_option(current_options, + OPTION_NORFC2308_TYPE1, $2); + set_global_boolean_option(current_options, + OPTION_NONAUTH_NXDOMAIN, !$2); } | T_AUTH_NXDOMAIN yea_or_nay { - set_boolean_option(current_options, OPTION_NONAUTH_NXDOMAIN, + set_global_boolean_option(current_options, OPTION_NONAUTH_NXDOMAIN, !$2); } | T_MULTIPLE_CNAMES yea_or_nay { - set_boolean_option(current_options, OPTION_MULTIPLE_CNAMES, - $2); + set_global_boolean_option(current_options, + OPTION_MULTIPLE_CNAMES, $2); } | T_CHECK_NAMES check_names_type check_names_opt { - current_options->check_names[$2] = $3; + current_options->check_names[$2] = (enum severity)$3; + } + | T_USE_ID_POOL yea_or_nay + { + set_global_boolean_option(current_options, + OPTION_USE_ID_POOL, $2); + } + | T_RFC2308_TYPE1 yea_or_nay + { + set_global_boolean_option(current_options, + OPTION_NORFC2308_TYPE1, !$2); } | T_LISTEN_ON maybe_port '{' address_match_list '}' { @@ -356,23 +434,73 @@ option: /* Empty */ } '{' opt_forwarders_list '}' | T_QUERY_SOURCE query_source + | T_TRANSFER_SOURCE maybe_wild_addr + { + current_options->axfr_src = $2; + } | T_ALLOW_QUERY '{' address_match_list '}' { - if (current_options->query_acl) - free_ip_match_list(current_options->query_acl); - current_options->query_acl = $3; + if (current_options->query_acl) { + parser_warning(0, + "options allow-query acl already set; skipping"); + free_ip_match_list($3); + } else + current_options->query_acl = $3; + } + | T_ALLOW_RECURSION '{' address_match_list '}' + { + if (current_options->recursion_acl) { + parser_warning(0, + "options allow-recursion acl already set; skipping"); + free_ip_match_list($3); + } else + current_options->recursion_acl = $3; } | T_ALLOW_TRANSFER '{' address_match_list '}' { - if (current_options->transfer_acl) - free_ip_match_list(current_options->transfer_acl); - current_options->transfer_acl = $3; + if (current_options->transfer_acl) { + parser_warning(0, + "options allow-transfer acl already set; skipping"); + free_ip_match_list($3); + } else + current_options->transfer_acl = $3; + } + | T_SORTLIST '{' address_match_list '}' + { + if (current_options->sortlist) { + parser_warning(0, + "options sortlist already set; skipping"); + free_ip_match_list($3); + } else + current_options->sortlist = $3; + } + | T_ALSO_NOTIFY + { + if (current_options->also_notify) { + parser_warning(0, + "duplicate also-notify clause: overwriting"); + free_also_notify(current_options); + current_options->also_notify = NULL; + } + } + '{' opt_also_notify_list '}' + | T_BLACKHOLE '{' address_match_list '}' + { + if (current_options->blackhole_acl) { + parser_warning(0, + "options blackhole already set; skipping"); + free_ip_match_list($3); + } else + current_options->blackhole_acl = $3; } | T_TOPOLOGY '{' address_match_list '}' { - if (current_options->topology) - free_ip_match_list(current_options->topology); - current_options->topology = $3; + if (current_options->topology) { + parser_warning(0, + "options topology already set; skipping"); + free_ip_match_list($3); + } else + current_options->topology = $3; } | size_clause { @@ -387,6 +515,10 @@ option: /* Empty */ { current_options->max_transfer_time_in = $2 * 60; } + | T_SERIAL_QUERIES L_NUMBER + { + current_options->serial_queries = $2; + } | T_CLEAN_INTERVAL L_NUMBER { current_options->clean_interval = $2 * 60; @@ -399,9 +531,168 @@ option: /* Empty */ { current_options->stats_interval = $2 * 60; } + | T_MAX_LOG_SIZE_IXFR L_NUMBER + { + current_options->max_log_size_ixfr = $2; + } + | T_MAX_NCACHE_TTL L_NUMBER + { + current_options->max_ncache_ttl = $2; + } + | T_LAME_TTL L_NUMBER + { + current_options->lame_ttl = $2; + } + | T_HEARTBEAT L_NUMBER + { + current_options->heartbeat_interval = $2 * 60; + } + | T_DIALUP yea_or_nay + { + set_global_boolean_option(current_options, + OPTION_NODIALUP, !$2); + } + | T_RRSET_ORDER '{' rrset_ordering_list '}' + { + if (current_options->ordering) + free_rrset_order_list(current_options->ordering); + current_options->ordering = $3; + } + | T_TREAT_CR_AS_SPACE yea_or_nay + { + set_global_boolean_option(current_options, + OPTION_TREAT_CR_AS_SPACE, $2); + } + | T_MIN_ROOTS L_NUMBER + { + if ($2 >= 1) + current_options->minroots = $2; + } + | error + ; + +/* + * Controls. + */ +controls_stmt: T_CONTROLS '{' controls '}' + ; + +controls: control L_EOS + | controls control L_EOS + ; + +control: /* Empty */ + | T_INET maybe_wild_addr T_PORT in_port + T_ALLOW '{' address_match_list '}' + { + ns_ctl_add(¤t_controls, ns_ctl_new_inet($2, $4, $7)); + } + | T_UNIX L_QSTRING T_PERM L_NUMBER T_OWNER L_NUMBER T_GROUP L_NUMBER + { + ns_ctl_add(¤t_controls, ns_ctl_new_unix($2, $4, $6, $8)); + } | error ; +rrset_ordering_list: rrset_ordering_element L_EOS + { + rrset_order_list rol; + + rol = new_rrset_order_list(); + if ($1 != NULL) { + add_to_rrset_order_list(rol, $1); + } + + $$ = rol; + } + | rrset_ordering_list rrset_ordering_element L_EOS + { + if ($2 != NULL) { + add_to_rrset_order_list($1, $2); + } + $$ = $1; + } + ; + +ordering_class: /* nothing */ + { + $$ = C_ANY; + } + | T_CLASS any_string + { + symbol_value value; + + if (lookup_symbol(constants, $2, SYM_CLASS, &value)) + $$ = value.integer; + else { + parser_error(0, "unknown class '%s'; using ANY", $2); + $$ = C_ANY; + } + freestr($2); + } + ; + +ordering_type: /* nothing */ + { + $$ = ns_t_any; + } + | T_TYPE any_string + { + int success; + + if (strcmp($2, "*") == 0) { + $$ = ns_t_any; + } else { + $$ = __sym_ston(__p_type_syms, $2, &success); + if (success == 0) { + $$ = ns_t_any; + parser_error(0, + "unknown type '%s'; assuming ANY", + $2); + } + } + freestr($2); + } + +ordering_name: /* nothing */ + { + $$ = savestr("*", 1); + } + | T_NAME L_QSTRING + { + if (strcmp(".",$2) == 0 || strcmp("*.",$2) == 0) { + $$ = savestr("*", 1); + freestr($2); + } else { + $$ = $2 ; + } + /* XXX Should do any more name validation here? */ + } + + +rrset_ordering_element: ordering_class ordering_type ordering_name T_ORDER L_STRING + { + enum ordering o; + + if (strlen($5) == 0) { + parser_error(0, "null order name"); + $$ = NULL ; + } else { + o = lookup_ordering($5); + if (o == unknown_order) { + o = (enum ordering)DEFAULT_ORDERING; + parser_error(0, + "invalid order name '%s'; using %s", + $5, p_order(o)); + } + + freestr($5); + + $$ = new_rrset_order_element($1, $2, $3, o); + } + } + + transfer_format: T_ONE_ANSWER { $$ = axfr_one_answer; @@ -442,6 +733,11 @@ maybe_port: /* nothing */ { $$ = htons(NS_DEFAULTPORT); } | T_PORT in_port { $$ = $2; } ; +maybe_zero_port: /* nothing */ { $$ = htons(0); } + | T_PORT in_port { $$ = $2; } + ; + + yea_or_nay: T_YES { $$ = 1; @@ -500,11 +796,13 @@ check_names_opt: T_WARN forward_opt: T_ONLY { - set_boolean_option(current_options, OPTION_FORWARD_ONLY, 1); + set_global_boolean_option(current_options, + OPTION_FORWARD_ONLY, 1); } | T_FIRST { - set_boolean_option(current_options, OPTION_FORWARD_ONLY, 0); + set_global_boolean_option(current_options, + OPTION_FORWARD_ONLY, 0); } | T_IF_NO_ANSWER { @@ -591,7 +889,27 @@ forwarders_in_addr_list: forwarders_in_addr L_EOS forwarders_in_addr: L_IPADDR { - add_forwarder(current_options, $1); + add_global_forwarder(current_options, $1); + } + ; + +opt_also_notify_list: /* nothing */ + | also_notify_in_addr_list + ; + +also_notify_in_addr_list: also_notify_in_addr L_EOS + { + /* nothing */ + } + | also_notify_in_addr_list also_notify_in_addr L_EOS + { + /* nothing */ + } + ; + +also_notify_in_addr: L_IPADDR + { + add_global_also_notify(current_options, $1); } ; @@ -697,12 +1015,10 @@ channel_severity: any_string version_modifier: T_VERSIONS L_NUMBER { chan_versions = $2; - chan_flags |= LOG_TRUNCATE; } | T_VERSIONS T_UNLIMITED { chan_versions = LOG_MAX_VERSIONS; - chan_flags |= LOG_TRUNCATE; } ; @@ -851,7 +1167,7 @@ category: category_name server_stmt: T_SERVER L_IPADDR { - char *ip_printable; + const char *ip_printable; symbol_value value; ip_printable = inet_ntoa($2); @@ -883,6 +1199,10 @@ server_info: T_BOGUS yea_or_nay { set_server_option(current_server, SERVER_INFO_BOGUS, $2); } + | T_SUPPORT_IXFR yea_or_nay + { + set_server_option(current_server, SERVER_INFO_SUPPORT_IXFR, $2); + } | T_TRANSFERS L_NUMBER { set_server_transfers(current_server, (int)$2); @@ -923,6 +1243,25 @@ address_match_element: address_match_simple ip_match_negate($2); $$ = $2; } + | T_SEC_KEY L_STRING + { + char *key_name; + struct dst_key *dst_key; + + key_name = canonical_name($2); + if (key_name == NULL) { + parser_error(0, "can't make key name '%s' canonical", + $2); + key_name = savestr("__bad_key__", 1); + } + dst_key = find_key(key_name, NULL); + if (dst_key == NULL) { + parser_error(0, "key \"%s\" not found", key_name); + $$ = NULL; + } + else + $$ = new_ip_match_key(dst_key); + } ; address_match_simple: L_IPADDR @@ -997,14 +1336,23 @@ address_name: any_string key_ref: any_string { - key_info ki; + struct dst_key *dst_key; + char *key_name; - ki = lookup_key($1); - if (ki == NULL) { - parser_error(0, "unknown key '%s'", $1); + key_name = canonical_name($1); + if (key_name == NULL) { + parser_error(0, "can't make key name '%s' canonical", + $1); $$ = NULL; - } else - $$ = ki; + } else { + dst_key = lookup_key(key_name); + if (dst_key == NULL) { + parser_error(0, "unknown key '%s'", key_name); + $$ = NULL; + } else + $$ = dst_key; + freestr(key_name); + } freestr($1); } ; @@ -1030,21 +1378,37 @@ key_stmt: T_SEC_KEY } any_string '{' key_definition '}' { - key_info ki; + struct dst_key *dst_key; + char *key_name; - if (lookup_key($3) != NULL) { - parser_error(0, "can't redefine key '%s'", $3); - freestr($3); + key_name = canonical_name($3); + if (key_name == NULL) { + parser_error(0, "can't make key name '%s' canonical", + $3); + } else if (lookup_key(key_name) != NULL) { + parser_error(0, "can't redefine key '%s'", key_name); + freestr(key_name); } else { if (current_algorithm == NULL || - current_secret == NULL) - parser_error(0, "skipping bad key '%s'", $3); - else { - ki = new_key_info($3, current_algorithm, - current_secret); - define_key($3, ki); + current_secret == NULL) { + parser_error(0, "skipping bad key '%s'", + key_name); + freestr(key_name); + } else { + dst_key = new_key_info(key_name, + current_algorithm, + current_secret); + if (dst_key != NULL) { + define_key(key_name, dst_key); + if (secretkey_info == NULL) + secretkey_info = + new_key_info_list(); + add_to_key_info_list(secretkey_info, + dst_key); + } } } + freestr($3); } ; @@ -1104,24 +1468,29 @@ zone_stmt: T_ZONE L_QSTRING optional_class if (zone_name == NULL) { parser_error(0, "can't make zone name '%s' canonical", $2); - seen_zone = 1; + should_install = 0; zone_name = savestr("__bad_zone__", 1); } else { - seen_zone = lookup_symbol(symtab, zone_name, sym_type, - NULL); - if (seen_zone) { + if (lookup_symbol(symtab, zone_name, sym_type, NULL)) { + should_install = 0; parser_error(0, - "cannot redefine zone '%s' class %d", - zone_name, $3); - } else - define_symbol(symtab, zone_name, sym_type, - value, 0); + "cannot redefine zone '%s' class %s", + *zone_name ? zone_name : ".", + p_class($3)); + } else { + should_install = 1; + define_symbol(symtab, savestr(zone_name, 1), + sym_type, value, + SYMBOL_FREE_KEY); + } } freestr($2); current_zone = begin_zone(zone_name, $3); } optional_zone_options_list - { end_zone(current_zone, !seen_zone); } + { + end_zone(current_zone, should_install); + } ; optional_zone_options_list: /* Empty */ @@ -1162,6 +1531,10 @@ zone_type: T_MASTER { $$ = Z_STUB; } + | T_FORWARD + { + $$ = Z_FORWARD; + } ; zone_option_list: zone_option L_EOS @@ -1179,14 +1552,29 @@ zone_option: T_TYPE zone_type parser_warning(0, "zone filename already set; skipping"); } - | T_MASTERS '{' master_in_addr_list '}' + | T_FILE_IXFR L_QSTRING + { + if (!set_zone_ixfr_file(current_zone, $2)) + parser_warning(0, + "zone ixfr data base already set; skipping"); + } + | T_IXFR_TMP L_QSTRING + { + if (!set_zone_ixfr_tmp(current_zone, $2)) + parser_warning(0, + "zone ixfr temp filename already set; skipping"); + } + | T_MASTERS maybe_zero_port '{' master_in_addr_list '}' + { + set_zone_master_port(current_zone, $2); + } | T_TRANSFER_SOURCE maybe_wild_addr { set_zone_transfer_source(current_zone, $2); } | T_CHECK_NAMES check_names_opt { - if (!set_zone_checknames(current_zone, $2)) + if (!set_zone_checknames(current_zone, (enum severity)$2)) parser_warning(0, "zone checknames already set; skipping"); } @@ -1208,17 +1596,56 @@ zone_option: T_TYPE zone_type parser_warning(0, "zone transfer acl already set; skipping"); } + | T_FORWARD zone_forward_opt + | T_FORWARDERS + { + struct zoneinfo *zp = current_zone.opaque; + if (zp->z_fwdtab) { + free_forwarders(zp->z_fwdtab); + zp->z_fwdtab = NULL; + } + + } + '{' opt_zone_forwarders_list '}' | T_MAX_TRANSFER_TIME_IN L_NUMBER { if (!set_zone_transfer_time_in(current_zone, $2*60)) parser_warning(0, "zone max transfer time (in) already set; skipping"); } + | T_MAX_LOG_SIZE_IXFR L_NUMBER + { + set_zone_max_log_size_ixfr(current_zone, $2); + } | T_NOTIFY yea_or_nay { set_zone_notify(current_zone, $2); } + | T_MAINTAIN_IXFR_BASE yea_or_nay + { + set_zone_maintain_ixfr_base(current_zone, $2); + } + | T_PUBKEY L_NUMBER L_NUMBER L_NUMBER L_QSTRING + { + /* flags proto alg key */ + set_zone_pubkey(current_zone, $2, $3, $4, $5); + } + | T_PUBKEY L_STRING L_NUMBER L_NUMBER L_QSTRING + { + /* flags proto alg key */ + char *endp; + int flags = (int) strtol($2, &endp, 0); + if (*endp != '\0') + ns_panic(ns_log_parser, 1, + "Invalid flags string: %s", $2); + set_zone_pubkey(current_zone, flags, $3, $4, $5); + + } | T_ALSO_NOTIFY '{' opt_notify_in_addr_list '}' + | T_DIALUP yea_or_nay + { + set_zone_dialup(current_zone, $2); + } | error ; @@ -1258,6 +1685,73 @@ notify_in_addr: L_IPADDR } ; +zone_forward_opt: T_ONLY + { + set_zone_boolean_option(current_zone, OPTION_FORWARD_ONLY, 1); + } + | T_FIRST + { + set_zone_boolean_option(current_zone, OPTION_FORWARD_ONLY, 0); + } + ; + +opt_zone_forwarders_list: /* nothing */ + { + set_zone_forward(current_zone); + } + | zone_forwarders_in_addr_list + ; + +zone_forwarders_in_addr_list: zone_forwarders_in_addr L_EOS + { + /* nothing */ + } + | zone_forwarders_in_addr_list zone_forwarders_in_addr L_EOS + { + /* nothing */ + } + ; + +zone_forwarders_in_addr: L_IPADDR + { + add_zone_forwarder(current_zone, $1); + } + ; + +/* + * Trusted Key statement + */ + +trusted_keys_stmt: T_TRUSTED_KEYS '{' trusted_keys_list '}' + { + } + ; +trusted_keys_list: trusted_key L_EOS + { + /* nothing */ + } + | trusted_keys_list trusted_key L_EOS + { + /* nothing */ + } + ; +trusted_key: L_STRING L_NUMBER L_NUMBER L_NUMBER L_QSTRING + { + /* name flags proto alg key */ + set_trusted_key($1, $2, $3, $4, $5); + } + | L_STRING L_STRING L_NUMBER L_NUMBER L_QSTRING + { + /* name flags proto alg key */ + char *endp; + int flags = (int) strtol($2, &endp, 0); + if (*endp != '\0') + ns_panic(ns_log_parser, 1, + "Invalid flags string: %s", $2); + set_trusted_key($1, flags, $3, $4, $5); + } + ; + /* * Misc. */ @@ -1383,6 +1877,7 @@ parser_setup() { authtab = new_symbol_table(AUTH_TABLE_SIZE, free_sym_value); init_acls(); define_builtin_channels(); + INIT_LIST(current_controls); } static void @@ -1423,25 +1918,25 @@ define_acl(char *name, ip_match_list iml) { dprint_ip_match_list(ns_log_parser, iml, 2, "allow ", "deny "); } -key_info +struct dst_key * lookup_key(char *name) { symbol_value value; if (lookup_symbol(authtab, name, SYM_KEY, &value)) - return ((key_info)(value.pointer)); + return ((struct dst_key *)(value.pointer)); return (NULL); } void -define_key(char *name, key_info ki) { +define_key(char *name, struct dst_key *dst_key) { symbol_value value; INSIST(name != NULL); - INSIST(ki != NULL); + INSIST(dst_key != NULL); - value.pointer = ki; + value.pointer = dst_key; define_symbol(authtab, name, SYM_KEY, value, SYMBOL_FREE_VALUE); - dprint_key_info(ki); + dprint_key_info(dst_key); } void diff --git a/contrib/bind/bin/named/ns_parseutil.c b/contrib/bind/bin/named/ns_parseutil.c index aed15af..60b189a 100644 --- a/contrib/bind/bin/named/ns_parseutil.c +++ b/contrib/bind/bin/named/ns_parseutil.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -21,6 +21,8 @@ #include "port_before.h" #include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -178,7 +180,7 @@ define_symbol(symbol_table st, char *key, int type, symbol_value value, void undefine_symbol(symbol_table st, char *key, int type) { int hash; - symbol_entry prev_ste, ste, next_ste; + symbol_entry prev_ste, ste; hash = symbol_hash(key, st->size); for (prev_ste = NULL, ste = st->table[hash]; diff --git a/contrib/bind/bin/named/ns_parseutil.h b/contrib/bind/bin/named/ns_parseutil.h index d241bea..78356f8 100644 --- a/contrib/bind/bin/named/ns_parseutil.h +++ b/contrib/bind/bin/named/ns_parseutil.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -15,8 +15,8 @@ * SOFTWARE. */ -#ifndef NS_PARSEUTIL_H -#define NS_PARSEUTIL_H +#ifndef _NS_PARSEUTIL_H +#define _NS_PARSEUTIL_H /* * Symbol Table @@ -62,4 +62,4 @@ void undefine_symbol(symbol_table, char *, int type); int unit_to_ulong(char *, u_long *); -#endif /* !NS_PARSEUTIL_H */ +#endif /* !_NS_PARSEUTIL_H */ diff --git a/contrib/bind/bin/named/ns_req.c b/contrib/bind/bin/named/ns_req.c index ee60ce4..d7ee0b5 100644 --- a/contrib/bind/bin/named/ns_req.c +++ b/contrib/bind/bin/named/ns_req.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)ns_req.c 4.47 (Berkeley) 7/1/91"; -static char rcsid[] = "$Id: ns_req.c,v 8.46 1998/03/27 00:21:03 halley Exp $"; +static const char sccsid[] = "@(#)ns_req.c 4.47 (Berkeley) 7/1/91"; +static const char rcsid[] = "$Id: ns_req.c,v 8.104 1999/10/15 19:49:04 vixie Exp $"; #endif /* not lint */ /* @@ -82,7 +82,7 @@ static char rcsid[] = "$Id: ns_req.c,v 8.46 1998/03/27 00:21:03 halley Exp $"; */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -105,6 +105,7 @@ static char rcsid[] = "$Id: ns_req.c,v 8.46 1998/03/27 00:21:03 halley Exp $"; #include <sys/uio.h> #include <sys/file.h> #include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -123,6 +124,8 @@ static char rcsid[] = "$Id: ns_req.c,v 8.46 1998/03/27 00:21:03 halley Exp $"; #include <isc/logging.h> #include <isc/memcluster.h> +#include <isc/dst.h> + #include "port_after.h" #include "named.h" @@ -131,7 +134,8 @@ struct addinfo { char *a_dname; /* domain name */ char *a_rname; /* referred by */ u_int16_t a_rtype; /* referred by */ - u_int16_t a_class; /* class for address */ + u_int16_t a_type; /* type for data */ + u_int16_t a_class; /* class for data */ }; #ifndef BIND_UPDATE @@ -140,14 +144,15 @@ enum req_action { Finish, Refuse, Return }; static struct addinfo addinfo[NADDRECS]; static void addname(const char *, const char *, - u_int16_t, u_int16_t); + u_int16_t, u_int16_t, u_int16_t); static void copyCharString(u_char **, const char *); static enum req_action req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, int *buflenp, int *msglenp, - u_char *msg, int dfd, - struct sockaddr_in from); + u_char *msg, int dfd, int *ra, + struct sockaddr_in from, + struct tsig_record *in_tsig); static enum req_action req_iquery(HEADER *hp, u_char **cpp, u_char *eom, int *buflenp, u_char *msg, @@ -168,14 +173,89 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp, HEADER *hp = (HEADER *) msg; u_char *cp, *eom; enum req_action action; - int n; + int n, ra, has_tsig, msglen_orig, tsig_size, siglen, sig2len; + u_char *tsigstart; + u_char sig[TSIG_SIG_SIZE], sig2[TSIG_SIG_SIZE]; + struct tsig_record *in_tsig = NULL; + int error = NOERROR; + DST_KEY *key; + time_t tsig_time; #ifdef DEBUG if (debug > 3) { ns_debug(ns_log_packet, 3, "ns_req(from %s)", sin_ntoa(from)); - fp_nquery(msg, msglen, log_get_stream(packet_channel)); + res_pquery(&res, msg, msglen, log_get_stream(packet_channel)); } #endif + msglen_orig = msglen; + siglen = sizeof(sig); + + tsigstart = ns_find_tsig(msg, msg + msglen); + if (tsigstart == NULL) + has_tsig = 0; + else { + char buf[MAXDNAME]; + + has_tsig = 1; + ns_name_ntop(tsigstart, buf, sizeof(buf)); + key = find_key(buf, NULL); + if (key == NULL) { + error = ns_r_badkey; + ns_debug(ns_log_default, 1, + "ns_req: TSIG verify failed - unknown key %s", + buf); + } + } + if (has_tsig && key != NULL) { + n = ns_verify(msg, &msglen, key, NULL, 0, sig, &siglen, + &tsig_time, 0); + if (n != 0) { + hp->rcode = ns_r_notauth; + /* A query should never have an error code set */ + if (n == ns_r_badsig || n == ns_r_badkey || + n == ns_r_badtime) { + ns_debug(ns_log_default, 1, + "ns_req: TSIG verify failed - query had error %s (%d) set", + p_rcode(n), n); + error = n; + action = Return; + } + /* If there's a processing error just respond */ + else if (n == -ns_r_badsig || n == -ns_r_badkey || + n == -ns_r_badtime) { + n = -n; + ns_debug(ns_log_default, 1, + "ns_req: TSIG verify failed - %s (%d)", + p_rcode(n), n); + error = n; + } else { + ns_debug(ns_log_default, 1, + "ns_req: TSIG verify failed - FORMERR"); + error = ns_r_formerr; + } + action = Finish; + } + in_tsig = memget(sizeof(struct tsig_record)); + if (in_tsig == NULL) + ns_panic(ns_log_default, 1, "memget failed"); + in_tsig->key = key; + in_tsig->siglen = siglen; + memcpy(in_tsig->sig, sig, siglen); + tsig_size = msglen_orig - msglen; + } else if (has_tsig) { + action = Finish; + in_tsig = memget(sizeof(struct tsig_record)); + if (in_tsig == NULL) + ns_panic(ns_log_default, 1, "memget failed"); + in_tsig->key = NULL; + in_tsig->siglen = 0; + tsig_size = msg + msglen - tsigstart; + msglen = tsigstart - msg; + } + + /* Hash some stuff so it's nice and random */ + nsid_hash((u_char *)&tt, sizeof(tt)); + nsid_hash(msg, (msglen > 512) ? 512 : msglen); /* * It's not a response so these bits have no business @@ -184,8 +264,10 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp, * comes in. */ hp->aa = hp->ra = 0; + ra = (NS_OPTION_P(OPTION_NORECURSE) == 0); - hp->rcode = NOERROR; + if (error == NOERROR) + hp->rcode = ns_r_noerror; cp = msg + HFIXEDSZ; eom = msg + msglen; buflen -= HFIXEDSZ; @@ -193,49 +275,58 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp, free_addinfo(); /* sets addcount to zero */ dnptrs[0] = NULL; - switch (hp->opcode) { - case ns_o_query: - action = req_query(hp, &cp, eom, qsp, - &buflen, &msglen, - msg, dfd, from); - break; + if (error == NOERROR) { + switch (hp->opcode) { + case ns_o_query: + action = req_query(hp, &cp, eom, qsp, + &buflen, &msglen, + msg, dfd, &ra, from, in_tsig); + break; - case ns_o_iquery: - action = req_iquery(hp, &cp, eom, &buflen, msg, from); - break; + case ns_o_iquery: + action = req_iquery(hp, &cp, eom, &buflen, msg, from); + break; #ifdef BIND_NOTIFY - case ns_o_notify: - action = req_notify(hp, &cp, eom, msg, from); - break; + case ns_o_notify: + action = req_notify(hp, &cp, eom, msg, from); + break; #endif #ifdef BIND_UPDATE - case ns_o_update: - action = req_update(hp, cp, eom, msg, qsp, dfd, from); - break; + case ns_o_update: + action = req_update(hp, cp, eom, msg, qsp, dfd, from, + in_tsig); + break; #endif /* BIND_UPDATE */ - default: - ns_debug(ns_log_default, 1, - "ns_req: Opcode %d not implemented", hp->opcode); - /* XXX - should syslog, limited by haveComplained */ - hp->qdcount = htons(0); - hp->ancount = htons(0); - hp->nscount = htons(0); - hp->arcount = htons(0); - hp->rcode = NOTIMP; - action = Finish; + default: + ns_debug(ns_log_default, 1, + "ns_req: Opcode %d not implemented", + hp->opcode); + /* XXX - should syslog, limited by haveComplained */ + hp->qdcount = htons(0); + hp->ancount = htons(0); + hp->nscount = htons(0); + hp->arcount = htons(0); + hp->rcode = ns_r_notimpl; + action = Finish; + } + } + + if (in_tsig != NULL) { + memput(in_tsig, sizeof(struct tsig_record)); + in_tsig = NULL; } /* - * vector via internal opcode. (yes, it was even uglier before.) + * Vector via internal opcode. */ switch (action) { case Return: return; case Refuse: - hp->rcode = REFUSED; + hp->rcode = ns_r_refused; cp = eom; /*FALLTHROUGH*/ case Finish: @@ -247,22 +338,73 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp, } /* - * apply final polish + * Apply final polish. */ hp->qr = 1; /* set Response flag */ - hp->ra = (NS_OPTION_P(OPTION_NORECURSE) == 0); + hp->ra = ra; /* init above, may be modified by req_query */ - n = doaddinfo(hp, cp, buflen); - cp += n; - buflen -= n; + if (!hp->tc && has_tsig > 0 && buflen < tsig_size) + hp->tc = 1; + + /* + * If there was a format error, then we don't know what the msg has. + */ + if (hp->rcode == ns_r_formerr) { + hp->qdcount = htons(0); + hp->ancount = htons(0); + hp->nscount = htons(0); + hp->arcount = htons(0); + } + + /* + * If the query had a TSIG and the message is truncated or there was + * a TSIG error, build a new message with no data and a TSIG. + */ + if ((hp->tc || error != NOERROR) && has_tsig > 0) { + hp->ancount = htons(0); + hp->nscount = htons(0); + hp->arcount = htons(0); + cp = msg + HFIXEDSZ; + cp += ns_skiprr(cp, msg + msglen, ns_s_qd, ntohs(hp->qdcount)); + sig2len = sizeof(sig2); + buflen += (msglen - (cp - msg)); + msglen = cp - msg; + n = ns_sign(msg, &msglen, msglen + buflen, error, key, + sig, siglen, sig2, &sig2len, tsig_time); + if (n != 0) { + INSIST(0); + } + cp = msg + msglen; + + } + /* Either the message is not truncated or there was no TSIG */ + else { + if (has_tsig > 0) + buflen -= tsig_size; + n = doaddinfo(hp, cp, buflen); + cp += n; + buflen -= n; + if (has_tsig > 0) { + buflen += tsig_size; + sig2len = sizeof(sig2); + msglen = cp - msg; + n = ns_sign(msg, &msglen, msglen + buflen, error, key, + sig, siglen, sig2, &sig2len, tsig_time); + if (n != 0) { + INSIST(0); + } + cp = msg + msglen; + } + } #ifdef DEBUG ns_debug(ns_log_default, 1, - "ns_req: answer -> %s fd=%d id=%d size=%d", + "ns_req: answer -> %s fd=%d id=%d size=%d rc=%d", sin_ntoa(from), (qsp == NULL) ? dfd : qsp->s_rfd, - ntohs(hp->id), cp - msg); + ntohs(hp->id), cp - msg, hp->rcode); if (debug >= 10) - fp_nquery(msg, cp - msg, log_get_stream(packet_channel)); + res_pquery(&res, msg, cp - msg, + log_get_stream(packet_channel)); #endif /*DEBUG*/ if (qsp == NULL) { if (sendto(dfd, (char*)msg, cp - msg, 0, @@ -276,7 +418,7 @@ ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp, nameserIncr(from.sin_addr, nssSendtoErr); } nameserIncr(from.sin_addr, nssSentAns); - if (hp->rcode == NXDOMAIN) + if (hp->rcode == ns_r_nxdomain) nameserIncr(from.sin_addr, nssSentNXD); if (!hp->aa) nameserIncr(from.sin_addr, nssSentNaAns); @@ -307,22 +449,13 @@ req_notify(HEADER *hp, u_char **cpp, u_char *eom, u_char *msg, { int n, type, class, zn; char dnbuf[MAXDNAME]; - struct namebuf *np; - const char *fname; - struct hashbuf *htp = hashtab; /* lookup relative to root */ + struct zoneinfo *zp; - /* valid notify's have one question and zero answers */ - if ((ntohs(hp->qdcount) != 1) - || ntohs(hp->ancount) != 0 - || ntohs(hp->nscount) != 0 - || ntohs(hp->arcount) != 0) { + /* valid notify's have one question */ + if (ntohs(hp->qdcount) != 1) { ns_debug(ns_log_notify, 1, "FORMERR Notify header counts wrong"); - hp->qdcount = htons(0); - hp->ancount = htons(0); - hp->nscount = htons(0); - hp->arcount = htons(0); - hp->rcode = FORMERR; + hp->rcode = ns_r_formerr; return (Finish); } @@ -330,14 +463,14 @@ req_notify(HEADER *hp, u_char **cpp, u_char *eom, u_char *msg, if (n < 0) { ns_debug(ns_log_notify, 1, "FORMERR Query expand name failed"); - hp->rcode = FORMERR; + hp->rcode = ns_r_formerr; return (Finish); } *cpp += n; if (*cpp + 2 * INT16SZ > eom) { ns_debug(ns_log_notify, 1, "FORMERR notify too short"); - hp->rcode = FORMERR; + hp->rcode = ns_r_formerr; return (Finish); } GETSHORT(type, *cpp); @@ -347,76 +480,95 @@ req_notify(HEADER *hp, u_char **cpp, u_char *eom, u_char *msg, /* XXX - when answers are allowed, we'll need to do compression * correctly here, and we will need to check for packet underflow. */ - np = nlookup(dnbuf, &htp, &fname, 0); - if (!np) { + /* Find the zone this NOTIFY refers to. */ + zp = find_auth_zone(dnbuf, class); + if (zp == NULL) { ns_info(ns_log_notify, - "rcvd NOTIFY for \"%s\", name not in cache", + "rcvd NOTIFY for \"%s\", name not one of our zones", dnbuf); - hp->rcode = SERVFAIL; + hp->rcode = ns_r_servfail; return (Finish); } - zn = findMyZone(np, class); - if (zn == DB_Z_CACHE || zones[zn].z_type != z_slave) { - /* this can come if a user did an AXFR of some zone somewhere - * and that zone's server now wants to tell us that the SOA - * has changed. AXFR's always come from nonpriv ports so it - * isn't possible to know whether it was the server or just - * "dig". this condition can be avoided by using secure zones - * since that way only real secondaries can AXFR from you. - */ - ns_info(ns_log_notify, - "NOTIFY for non-secondary name (%s), from %s", - dnbuf, sin_ntoa(from)); - goto refuse; - } - if (findZonePri(&zones[zn], from) == -1) { - ns_info(ns_log_notify, - "NOTIFY from non-master server (zone %s), from %s", - zones[zn].z_origin, sin_ntoa(from)); - goto refuse; - } + /* Access control. */ switch (type) { case T_SOA: - if (strcasecmp(dnbuf, zones[zn].z_origin) != 0) { + if (zp->z_type != z_slave) { + /* + * This can come if a user did an AXFR of some zone + * somewhere and that zone's server now wants to + * tell us that the SOA has changed. AXFR's always + * come from nonpriv ports so it isn't possible to + * know whether it was the server or just "dig". + * This condition can be avoided by using secure + * zones since that way only real secondaries can + * AXFR from you. + */ + ns_info(ns_log_notify, + "NOTIFY(SOA) for non-secondary name (%s), from %s", + dnbuf, sin_ntoa(from)); + goto refuse; + } + if (ns_samename(dnbuf, zp->z_origin) != 1) { ns_info(ns_log_notify, "NOTIFY(SOA) for non-origin (%s), from %s", dnbuf, sin_ntoa(from)); goto refuse; } - if (zones[zn].z_flags & + if (findZonePri(zp, from) == -1) { + ns_info(ns_log_notify, + "NOTIFY(SOA) from non-master server (zone %s), from %s", + zp->z_origin, sin_ntoa(from)); + goto refuse; + } + break; + default: + /* No access requirements defined for other types. */ + break; + } + /* The work occurs here. */ + switch (type) { + case T_SOA: + if (zp->z_flags & (Z_NEED_RELOAD|Z_NEED_XFER|Z_QSERIAL|Z_XFER_RUNNING)) { ns_info(ns_log_notify, "NOTIFY(SOA) for zone already xferring (%s)", dnbuf); goto noerror; } - zones[zn].z_time = tt.tv_sec; - qserial_query(&zones[zn]); - sched_zone_maint(&zones[zn]); + zp->z_time = tt.tv_sec; + qserial_query(zp); + sched_zone_maint(zp); break; default: - /* unimplemented, but it's not a protocol error, just + /* + * Unimplemented, but it's not a protocol error, just * something to be ignored. */ - break; + hp->rcode = ns_r_notimpl; + return (Finish); } noerror: - hp->rcode = NOERROR; + hp->rcode = ns_r_noerror; return (Finish); refuse: - hp->rcode = REFUSED; + hp->rcode = ns_r_refused; return (Finish); } #endif /*BIND_NOTIFY*/ static enum req_action req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, - int *buflenp, int *msglenp, u_char *msg, int dfd, - struct sockaddr_in from) + int *buflenp, int *msglenp, u_char *msg, int dfd, int *ra, + struct sockaddr_in from, struct tsig_record *in_tsig) { int n, class, type, count, zone, foundname, founddata, omsglen, cname; + int recursion_blocked_by_acl; u_int16_t id; - u_char **dpp, *omsg, *answers; + u_int32_t serial_ixfr; + int ixfr_found; + int ixfr_error = 0; + char dnbuf2[MAXDNAME]; + u_char **dpp, *omsg, *answers, *afterq; char dnbuf[MAXDNAME], *dname; const char *fname; struct hashbuf *htp; @@ -425,6 +577,7 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, struct qinfo *qp; struct zoneinfo *zp; struct databuf *dp; + DST_KEY *in_key = (in_tsig != NULL) ? in_tsig->key : NULL; nameserIncr(from.sin_addr, nssRcvdQ); @@ -438,19 +591,15 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, omsglen = 0; omsg = NULL; id = 0; + recursion_blocked_by_acl = 0; /* valid queries have one question and zero answers */ if ((ntohs(hp->qdcount) != 1) || ntohs(hp->ancount) != 0 - || ntohs(hp->nscount) != 0 || ntohs(hp->arcount) != 0) { ns_debug(ns_log_default, 1, "FORMERR Query header counts wrong"); - hp->qdcount = htons(0); - hp->ancount = htons(0); - hp->nscount = htons(0); - hp->arcount = htons(0); - hp->rcode = FORMERR; + hp->rcode = ns_r_formerr; return (Finish); } @@ -464,35 +613,101 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, if (n < 0) { ns_debug(ns_log_default, 1, "FORMERR Query expand name failed"); - hp->rcode = FORMERR; + hp->rcode = ns_r_formerr; return (Finish); } *cpp += n; + answers = *cpp; if (*cpp + 2 * INT16SZ > eom) { ns_debug(ns_log_default, 1, "FORMERR Query message length short"); - hp->rcode = FORMERR; + hp->rcode = ns_r_formerr; return (Finish); } GETSHORT(type, *cpp); GETSHORT(class, *cpp); - if (*cpp < eom) { + if (*cpp < eom && type != ns_t_ixfr) { ns_debug(ns_log_default, 6, "message length > received message"); *msglenp = *cpp - msg; } + if (((ntohs(hp->nscount) != 0) && (type != ns_t_ixfr)) || + ((ntohs(hp->nscount) != 1) && (type == ns_t_ixfr))) + { + ns_debug(ns_log_default, 1, "FORMERR Query nscount wrong"); + hp->rcode = ns_r_formerr; + return (Finish); + } + + afterq = *cpp; qtypeIncr(type); /* * Process query. */ - if (type == T_AXFR) { + if (type == ns_t_ixfr) { + hp->nscount = htons(0); + hp->rd = 0; /* Force IXFR queries to be non recursive. */ + n = dn_expand(msg, eom, *cpp, dnbuf2, sizeof dnbuf2); + if (n < 0) { + ns_debug(ns_log_default, 1, + "FORMERR Query expand name failed"); + hp->rcode = ns_r_formerr; + return (Finish); + } + *cpp += n; + if (*cpp + 3 * INT16SZ + INT32SZ > eom) { + ns_debug(ns_log_default, 1, + "ran out of data in IXFR query"); + hp->rcode = ns_r_formerr; + return (Finish); + } + GETSHORT(n, *cpp); + if (n != ns_t_soa || ns_samename(dnbuf, dnbuf2) != 1) { + ns_debug(ns_log_default, 1, + "FORMERR SOA record expected"); + hp->rcode = ns_r_formerr; + return (Finish); + } + *cpp += INT32SZ + INT16SZ * 2; /* skip class, ttl, dlen */ + if (0 >= (n = dn_skipname(*cpp, eom))) { + ns_debug(ns_log_default, 1, + "FORMERR Query expand name failed"); + hp->rcode = ns_r_formerr; + return (Finish); + } + *cpp += n; /* mname */ + if (0 >= (n = dn_skipname(*cpp, eom))) { + ns_debug(ns_log_default, 1, + "FORMERR Query expand name failed"); + hp->rcode = ns_r_formerr; + return (Finish); + } + *cpp += n; /* rname */ + if (*cpp + 5 * INT32SZ > eom) { + ns_debug(ns_log_default, 1, + "ran out of data in IXFR query"); + hp->rcode = ns_r_formerr; + return (Finish); + } + GETLONG(serial_ixfr, *cpp); + /* ignore other soa counters */ + if ((*cpp + (4 * INT32SZ)) < eom) + ns_debug(ns_log_default, 6, + "ixfr: message length > received message"); + /* Reset msglenp to cover just the question. */ + *msglenp = afterq - msg; + } + *cpp = afterq; + + if (!ns_t_udp_p(type)) { /* Refuse request if not a TCP connection. */ if (qsp == NULL) { ns_info(ns_log_default, - "rejected UDP AXFR from %s for \"%s\"", - sin_ntoa(from), *dnbuf ? dnbuf : "."); + "rejected UDP %s from %s for \"%s\"", + p_type(type), sin_ntoa(from), + *dnbuf ? dnbuf : "."); return (Refuse); } /* The position of this is subtle. */ @@ -507,10 +722,11 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, #ifdef QRYLOG if (qrylog) { - ns_info(ns_log_queries, "XX /%s/%s/%s", + ns_info(ns_log_queries, "%s/%s/%s/%s/%s", + (hp->rd) ? "XX+" : "XX ", inet_ntoa(from.sin_addr), (dname[0] == '\0') ? "." : dname, - p_type(type)); + p_type(type), p_class(class)); } #endif /*QRYLOG*/ @@ -542,7 +758,7 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, struct in_addr ina; if (inet_aton(dname, &ina)) { - hp->rcode = NXDOMAIN; + hp->rcode = ns_r_nxdomain; hp->aa = 1; ns_debug(ns_log_default, 3, "ypkludge: hit as '%s'", dname); @@ -582,10 +798,42 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, zp = &zones[zone]; + ixfr_found = 0; + if (type == ns_t_ixfr && zone != DB_Z_CACHE) { + if (SEQ_GT(serial_ixfr, zp->z_serial)) + ixfr_found = 0; + else { + ixfr_error = ixfr_have_log(zp, serial_ixfr, zp->z_serial); + if (ixfr_error < 0) { + ns_debug(ns_log_default, + 1, "ixfr_have_log(%d %d) failed %d", + serial_ixfr, zp->z_serial, ixfr_error); + ixfr_found = 0; + /* Refuse IXFR and send AXFR */ + type = ns_t_axfr; + } else + ixfr_found = 1; + } + } + /* + * If recursion is turned on, we need to check recursion ACL + * if it exists - and return result to caller. + */ + { + ip_match_list recursion_acl; + + recursion_acl = server_options->recursion_acl; + if (!NS_OPTION_P(OPTION_NORECURSE) && recursion_acl != NULL + && !ip_address_allowed(recursion_acl, from.sin_addr)) { + recursion_blocked_by_acl = 1; + *ra = 0; + } + } + /* * Are queries allowed from this host? */ - if (type != T_AXFR) { + if (!ns_t_xfr_p(type)) { ip_match_list query_acl; if (zp->z_query_acl != NULL) @@ -594,7 +842,52 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, query_acl = server_options->query_acl; if (query_acl != NULL - && !ip_address_allowed(query_acl, from.sin_addr)) { + && !ip_addr_or_key_allowed(query_acl, from.sin_addr, + in_key)) + { + /* + * If this is *not* a zone acl and we would not + * have recursed and we have some answer return + * what we have with a referral. + */ + if ((zp->z_query_acl == NULL) && + (!hp->rd || NS_OPTION_P(OPTION_NORECURSE) || + recursion_blocked_by_acl) && + (ntohs(hp->ancount) != 0)) { + goto fetchns; + } + + /* + * See if we would have made a referral from + * an enclosing zone if we are actually in the + * cache. + */ + if (zp->z_type == z_cache && np != NULL) { + struct namebuf *access_np; + + zone = DB_Z_CACHE; + for (access_np = np; access_np != NULL; + access_np = np_parent(access_np)) { + dp = access_np->n_data; + while (dp && (dp->d_class != class || + dp->d_zone == DB_Z_CACHE)) + dp = dp->d_next; + if (dp != NULL) { + zone = dp->d_zone; + np = access_np; + break; + } + } + zp = &zones[zone]; + if (zp->z_type != z_cache && + zp->z_query_acl != NULL && + ip_addr_or_key_allowed(zp->z_query_acl, + from.sin_addr, in_key) && + (!hp->rd || recursion_blocked_by_acl || + NS_OPTION_P(OPTION_NORECURSE))) { + goto fetchns; + } + } ns_notice(ns_log_security, "unapproved query from %s for \"%s\"", sin_ntoa(from), *dname ? dname : "."); @@ -611,10 +904,23 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, transfer_acl = server_options->transfer_acl; if (transfer_acl != NULL - && !ip_address_allowed(transfer_acl, from.sin_addr)) { + && !ip_addr_or_key_allowed(transfer_acl, from.sin_addr, + in_key)) + { ns_notice(ns_log_security, - "unapproved AXFR from %s for \"%s\" (acl)", - sin_ntoa(from), *dname ? dname : "."); + "unapproved %s from %s for \"%s\" (acl)", + p_type(type), sin_ntoa(from), + *dname ? dname : "."); + return (Refuse); + } + + /* Are we master or slave? */ + + if (zp->z_type != z_master && zp->z_type != z_slave) { + ns_notice(ns_log_security, + "unapproved %s from %s for \"%s\" (not master/slave)", + p_type(type), sin_ntoa(from), + *dname ? dname : "."); return (Refuse); } @@ -622,39 +928,40 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, if ((zp->z_flags & Z_AUTH) == 0) { ns_notice(ns_log_security, - "unapproved AXFR from %s for \"%s\" (not auth)", - sin_ntoa(from), *dname ? dname : "."); + "unapproved %s from %s for \"%s\" (not authoritative)", + p_type(type), sin_ntoa(from), + *dname ? dname : "."); return (Refuse); } /* Is the name at a zone cut? */ - if (strcasecmp(zp->z_origin, dname) != 0) { + if (ns_samename(zp->z_origin, dname) != 1) { ns_notice(ns_log_security, - "unapproved AXFR from %s for \"%s\" (not zone top)", - sin_ntoa(from), *dname ? dname : "."); + "unapproved %s from %s for \"%s\" (not zone top)", + p_type(type), sin_ntoa(from), + *dname ? dname : "."); return (Refuse); } - ns_info(ns_log_security, "approved AXFR from %s for \"%s\"", - sin_ntoa(from), *dname ? dname : "."); + ns_info(ns_log_security, "approved %s from %s for \"%s\"", + p_type(type), sin_ntoa(from), *dname ? dname : "."); } /* * End Access Control Point */ - /* * Yow! */ - if (!strcasecmp(dnbuf, "VERSION.BIND") && - class == C_CHAOS && type == T_TXT) { + if (class == ns_c_chaos && type == ns_t_txt && + ns_samename(dnbuf, "VERSION.BIND") == 1) { u_char *tp; hp->ancount = htons(1); hp->nscount = htons(0); hp->arcount = htons(0); - hp->rcode = NOERROR; + hp->rcode = ns_r_noerror; hp->aa = 1; hp->ra = 0; copyCharString(cpp, "VERSION"); /* Name */ @@ -665,7 +972,7 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, PUTLONG(0, *cpp); /* TTL */ tp = *cpp; /* Temp RdLength */ PUTSHORT(0, *cpp); - copyCharString(cpp, ShortVersion); + copyCharString(cpp, server_options->version); PUTSHORT((*cpp) - (tp + INT16SZ), tp); /* Real RdLength */ *msglenp = *cpp - msg; /* Total message length */ return (Finish); @@ -682,11 +989,14 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, answers = *cpp; count = *cpp - msg; + /* The response is authoritative until we add insecure data */ + hp->ad = 1; + /* Look for NXDOMAIN record with appropriate class * if found return immediately */ for (dp = np->n_data; dp; dp = dp->d_next) { - if (!stale(dp) && (dp->d_rcode == NXDOMAIN) && + if (!stale(dp) && (dp->d_rcode == ns_r_nxdomain) && (dp->d_class == class)) { #ifdef RETURNSOA n = finddata(np, class, T_SOA, hp, &dname, @@ -700,12 +1010,14 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, } if (hp->rcode == NOERROR_NODATA) { /* this should not occur */ - hp->rcode = NOERROR; + hp->rcode = ns_r_noerror; return (Finish); } } +#else + count = 0; #endif - hp->rcode = NXDOMAIN; + hp->rcode = ns_r_nxdomain; /* * XXX forcing AA all the time isn't right, but * we have to work that way by default @@ -715,7 +1027,10 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, hp->aa = 1; ns_debug(ns_log_default, 3, "NXDOMAIN aa = %d", hp->aa); - return (Finish); + if ((count == 0) || NS_OPTION_P(OPTION_NORFC2308_TYPE1)) + return (Finish); + founddata = 1; + goto fetchns; } } @@ -727,19 +1042,19 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, n = finddata(np, class, type, hp, &dname, buflenp, &count); if (n == 0) { /* - * NO data available. Refuse AXFR requests, or + * NO data available. Refuse transfer requests, or * look for better servers for other requests. */ - if (type == T_AXFR) { + if (ns_t_xfr_p(type)) { ns_debug(ns_log_default, 1, - "T_AXFR refused: no data"); + "transfer refused: no data"); return (Refuse); } goto fetchns; } if (hp->rcode == NOERROR_NODATA) { - hp->rcode = NOERROR; + hp->rcode = ns_r_noerror; #ifdef RETURNSOA if (count) { *cpp += n; @@ -749,7 +1064,10 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, } #endif founddata = 1; - return (Finish); + ns_debug(ns_log_default, 1, "count = %d", count); + if ((count == 0) || NS_OPTION_P(OPTION_NORFC2308_TYPE1)) + return (Finish); + goto fetchns; } *cpp += n; @@ -760,7 +1078,7 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, if (cname++ >= MAXCNAMES) { ns_debug(ns_log_default, 3, "resp: leaving, MAXCNAMES exceeded"); - hp->rcode = SERVFAIL; + hp->rcode = ns_r_servfail; return (Finish); } goto try_again; @@ -770,11 +1088,46 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, "req: foundname=%d, count=%d, founddata=%d, cname=%d", foundname, count, founddata, cname); - if (type == T_AXFR) { - ns_xfr(qsp, np, zone, class, type, hp->opcode, ntohs(hp->id)); + if (ns_t_xfr_p(type)) { +#ifdef BIND_UPDATE + if ((zp->z_flags & Z_NEED_SOAUPDATE) != 0) + if (incr_serial(zp) < 0) + ns_error(ns_log_default, + "error updating serial number for %s from %d", + zp->z_origin, zp->z_serial); +#endif + /* + * Just return SOA if "up to date". + */ + if (type == ns_t_ixfr) { + hp->aa = 1; + if ((SEQ_GT(serial_ixfr, zp->z_serial) || + serial_ixfr == zp->z_serial)) + return (Finish); + } + + /* + * We don't handle UDP based IXFR queries (yet). + * Tell client to retry with TCP by returning SOA. + */ + if (qsp == NULL) + return (Finish); + else { + if (!ixfr_found) { + qsp->flags |= STREAM_AXFRIXFR; + hp->qdcount = htons(1); + } + ns_xfr(qsp, np, zone, class, type, + hp->opcode, ntohs(hp->id), + serial_ixfr, in_tsig); + } return (Return); } + if (count > 1 && type == T_A && !NS_OPTION_P(OPTION_NORECURSE) && + hp->rd) + sort_response(answers, *cpp, count, &from); + fetchns: /* * If we're already out of room in the response, we're done. @@ -782,6 +1135,9 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, if (hp->tc) return (Finish); + if (hp->ancount == 0) + hp->ad = 0; + /* * Look for name servers to refer to and fill in the authority * section or record the address for forwarding the query @@ -794,7 +1150,7 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, case NXDOMAIN: /* We are authoritative for this np. */ if (!foundname) - hp->rcode = NXDOMAIN; + hp->rcode = ns_r_nxdomain; ns_debug(ns_log_default, 3, "req: leaving (%s, rcode %d)", dname, hp->rcode); if (class != C_ANY) { @@ -838,21 +1194,29 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, case SERVFAIL: /* We're authoritative but the zone isn't loaded. */ if (!founddata && - !(NS_OPTION_P(OPTION_FORWARD_ONLY) && - server_options->fwdtab)) { - hp->rcode = SERVFAIL; + !(NS_ZOPTION_P(zp, OPTION_FORWARD_ONLY) && + NS_ZFWDTAB(zp))) { + hp->rcode = ns_r_servfail; free_nsp(nsp); return (Finish); } } + if (!founddata && hp->rd && recursion_blocked_by_acl) { + ns_notice(ns_log_security, + "unapproved recursive query from %s for %s", + sin_ntoa(from), *dname ? dname : "."); + } + /* * If we successfully found the answer in the cache, * or this is not a recursive query, or we are purposely - * never recursing, then add the nameserver references - * ("authority section") here and we're done. + * never recursing, or recursion is prohibited by ACL, then + * add the nameserver references("authority section") here + * and we're done. */ - if (founddata || !hp->rd || NS_OPTION_P(OPTION_NORECURSE)) { + if (founddata || !hp->rd || NS_OPTION_P(OPTION_NORECURSE) + || recursion_blocked_by_acl) { /* * If the qtype was NS, and the np of the authority is * the same as the np of the data, we don't need to add @@ -867,7 +1231,8 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, } *cpp += n; *buflenp -= n; - hp->nscount = htons((u_int16_t)count); + hp->nscount = htons(ntohs(hp->nscount) + + (u_int16_t)count); } free_nsp(nsp); @@ -886,29 +1251,31 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, omsg = (u_char *)memget((unsigned) *msglenp); if (omsg == NULL) { ns_info(ns_log_default, "ns_req: Out Of Memory"); - hp->rcode = SERVFAIL; + hp->rcode = ns_r_servfail; free_nsp(nsp); return (Finish); } id = hp->id; omsglen = *msglenp; memcpy(omsg, msg, omsglen); - n = res_mkquery(QUERY, dname, class, type, - NULL, 0, NULL, msg, - *msglenp + *buflenp); + n = res_nmkquery(&res, QUERY, dname, class, type, + NULL, 0, NULL, msg, + *msglenp + *buflenp); if (n < 0) { ns_info(ns_log_default, "res_mkquery(%s) failed", dname); - hp->rcode = SERVFAIL; + hp->rcode = ns_r_servfail; free_nsp(nsp); return (Finish); } *msglenp = n; } n = ns_forw(nsp, msg, *msglenp, from, qsp, dfd, &qp, - dname, class, type, np, 0); - if (n != FW_OK && cname) + dname, class, type, np, 0, in_tsig); + if (n != FW_OK && cname) { memput(omsg, omsglen); + omsg = NULL; + } switch (n) { case FW_OK: if (cname) { @@ -931,7 +1298,7 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, if (NAME(*np)[0] == '\0') { ns_notice(ns_log_default, "ns_req: no address for root server"); - hp->rcode = SERVFAIL; + hp->rcode = ns_r_servfail; free_nsp(nsp); return (Finish); } @@ -961,7 +1328,7 @@ req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, goto fetchns; /* Try again. */ case FW_SERVFAIL: do_servfail: - hp->rcode = SERVFAIL; + hp->rcode = ns_r_servfail; free_nsp(nsp); return (Finish); } @@ -984,11 +1351,7 @@ req_iquery(HEADER *hp, u_char **cpp, u_char *eom, int *buflenp, || ntohs(hp->arcount) != 0) { ns_debug(ns_log_default, 1, "FORMERR IQuery header counts wrong"); - hp->qdcount = htons(0); - hp->ancount = htons(0); - hp->nscount = htons(0); - hp->arcount = htons(0); - hp->rcode = FORMERR; + hp->rcode = ns_r_formerr; return (Finish); } @@ -998,14 +1361,14 @@ req_iquery(HEADER *hp, u_char **cpp, u_char *eom, int *buflenp, if ((n = dn_skipname(*cpp, eom)) < 0) { ns_debug(ns_log_default, 1, "FORMERR IQuery packet name problem"); - hp->rcode = FORMERR; + hp->rcode = ns_r_formerr; return (Finish); } *cpp += n; if (*cpp + 3 * INT16SZ + INT32SZ > eom) { ns_debug(ns_log_default, 1, "FORMERR IQuery message too short"); - hp->rcode = FORMERR; + hp->rcode = ns_r_formerr; return (Finish); } GETSHORT(type, *cpp); @@ -1016,7 +1379,7 @@ req_iquery(HEADER *hp, u_char **cpp, u_char *eom, int *buflenp, if (*cpp != eom) { ns_debug(ns_log_default, 1, "FORMERR IQuery message length off"); - hp->rcode = FORMERR; + hp->rcode = ns_r_formerr; return (Finish); } @@ -1025,10 +1388,18 @@ req_iquery(HEADER *hp, u_char **cpp, u_char *eom, int *buflenp, */ switch (type) { case T_A: - if (!NS_OPTION_P(OPTION_FAKE_IQUERY) || dlen != INT32SZ) + if (!NS_OPTION_P(OPTION_FAKE_IQUERY) || dlen != INT32SZ) { + if (dlen != INT32SZ) + ns_warning(ns_log_security, + "bad iquery from %s", + inet_ntoa(from.sin_addr)); return (Refuse); + } break; default: + ns_warning(ns_log_security, + "unsupported iquery type from %s", + inet_ntoa(from.sin_addr)); return (Refuse); } ns_debug(ns_log_default, 1, @@ -1036,8 +1407,12 @@ req_iquery(HEADER *hp, u_char **cpp, u_char *eom, int *buflenp, fname = (char *)msg + HFIXEDSZ; alen = (char *)*cpp - fname; - if ((size_t)alen > sizeof anbuf) + if ((size_t)alen > sizeof anbuf) { + ns_warning(ns_log_security, + "bad iquery from %s", + inet_ntoa(from.sin_addr)); return (Refuse); + } memcpy(anbuf, fname, alen); data = anbuf + alen - dlen; *cpp = (u_char *)fname; @@ -1124,7 +1499,7 @@ stale(struct databuf *dp) { zp->z_origin); } zp->z_flags &= ~Z_AUTH; - if (!(zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING))) { + if ((zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING)) == 0) { zp->z_time = tt.tv_sec; sched_zone_maint(zp); } @@ -1137,7 +1512,7 @@ stale(struct databuf *dp) { zp->z_origin); } zp->z_flags &= ~Z_AUTH; - if (!(zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING))) { + if ((zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING)) == 0) { zp->z_time = tt.tv_sec; sched_zone_maint(zp); } @@ -1146,6 +1521,7 @@ stale(struct databuf *dp) { return (0); case z_hint: + case z_cache: if (dp->d_flags & DB_F_HINT || dp->d_ttl >= (u_int32_t)tt.tv_sec) return (0); @@ -1169,7 +1545,8 @@ stale(struct databuf *dp) { */ int make_rr(const char *name, struct databuf *dp, u_char *buf, - int buflen, int doadd, u_char **comp_ptrs, u_char **edp) + int buflen, int doadd, u_char **comp_ptrs, u_char **edp, + int use_minimum) { u_char *cp; u_char *cp1, *sp; @@ -1177,20 +1554,13 @@ make_rr(const char *name, struct databuf *dp, u_char *buf, int32_t n; int16_t type = dp->d_type; u_int32_t ttl; -#ifdef BIND_UPDATE - u_int32_t serial; -#endif ns_debug(ns_log_default, 5, "make_rr(%s, %lx, %lx, %d, %d) %d zone %d ttl %lu", name, (u_long)dp, (u_long)buf, buflen, doadd, dp->d_size, dp->d_zone, (u_long)dp->d_ttl); - if (dp->d_rcode -#ifdef RETURNSOA - && dp->d_size == 0 -#endif - ) + if (dp->d_rcode && dp->d_size == 0) panic("make_rr: impossible d_rcode value", NULL); zp = &zones[dp->d_zone]; @@ -1202,7 +1572,7 @@ make_rr(const char *name, struct databuf *dp, u_char *buf, } else ttl = dp->d_ttl - (u_int32_t) tt.tv_sec; } else { - if (dp->d_ttl != USE_MINIMUM) + if (dp->d_ttl != USE_MINIMUM && !use_minimum) ttl = dp->d_ttl; else ttl = zp->z_minimum; /* really default */ @@ -1251,9 +1621,11 @@ make_rr(const char *name, struct databuf *dp, u_char *buf, return (-1); PUTSHORT((u_int16_t)n, sp); cp += n; - if (doadd) + if (doadd) { addname((char*)dp->d_data, name, - type, dp->d_class); + type, T_A, dp->d_class); + addname(name, name, type, T_KEY, dp->d_class); + } break; case T_SOA: @@ -1284,6 +1656,8 @@ make_rr(const char *name, struct databuf *dp, u_char *buf, n = 5 * INT32SZ; memcpy(cp, cp1, n); cp += n; + if (doadd) + addname(name, name, type, T_KEY, dp->d_class); } n = (u_int16_t)((cp - sp) - INT16SZ); PUTSHORT((u_int16_t)n, sp); @@ -1389,7 +1763,9 @@ make_rr(const char *name, struct databuf *dp, u_char *buf, cp1 += INT16SZ*2; } - n = dn_comp((char *)cp1, cp, buflen, comp_ptrs, edp); + n = dn_comp((char *)cp1, cp, buflen, + (type == ns_t_mx) ? comp_ptrs : NULL, + (type == ns_t_mx) ? edp : NULL); if (n < 0) return (-1); cp += n; @@ -1398,7 +1774,7 @@ make_rr(const char *name, struct databuf *dp, u_char *buf, n = (u_int16_t)((cp - sp) - INT16SZ); PUTSHORT((u_int16_t)n, sp); if (doadd) - addname((char*)cp1, name, type, dp->d_class); + addname((char*)cp1, name, type, T_A, dp->d_class); break; case T_PX: @@ -1461,7 +1837,32 @@ make_rr(const char *name, struct databuf *dp, u_char *buf, PUTSHORT((u_int16_t)n, sp); break; + case T_NXT: + cp1 = dp->d_data; + n = dn_comp((char *)cp1, cp, buflen, NULL, NULL); + if (n < 0) + return (-1); + + cp += n; + buflen -=n; + cp1 += strlen((char *)cp1) + 1; + + /* copy nxt bit map */ + n = dp->d_size - (u_int16_t)((cp1 - dp->d_data)); + if (n > buflen) + return (-1); /* out of room! */ + memcpy(cp, cp1, n); + cp += n; + buflen -= n; + + n = (u_int16_t)((cp - sp) - INT16SZ); + PUTSHORT((u_int16_t)n, sp); + + break; + default: + if ((type == T_A || type == T_AAAA) && doadd) + addname(name, name, type, T_KEY, dp->d_class); if (dp->d_size > buflen) return (-1); memcpy(cp, dp->d_data, dp->d_size); @@ -1473,13 +1874,13 @@ make_rr(const char *name, struct databuf *dp, u_char *buf, static void addname(const char *dname, const char *rname, - u_int16_t rtype, u_int16_t class) + u_int16_t rtype, u_int16_t type, u_int16_t class) { struct addinfo *ap; int n; for (ap = addinfo, n = addcount; --n >= 0; ap++) - if (strcasecmp(ap->a_dname, dname) == 0) + if (ns_samename(ap->a_dname, dname) == 1 && ap->a_type == type) return; /* add domain name to additional section */ @@ -1488,28 +1889,36 @@ addname(const char *dname, const char *rname, ap->a_dname = savestr(dname, 1); ap->a_rname = savestr(rname, 1); ap->a_rtype = rtype; + ap->a_type = type; ap->a_class = class; } } /* - * Lookup addresses for names in addinfo and put into the message's + * Lookup addresses/keys for names in addinfo and put into the message's * additional section. */ int doaddinfo(HEADER *hp, u_char *msg, int msglen) { - struct namebuf *np; - struct databuf *dp; - struct addinfo *ap; - u_char *cp; + register struct namebuf *np; + register struct databuf *dp; + register struct addinfo *ap; + register u_char *cp; struct hashbuf *htp; const char *fname; - int n, count; + register int n, count; + register int ns_logging; + int finishedA = 0; + int save_addcount = addcount; if (!addcount) return (0); - ns_debug(ns_log_default, 3, "doaddinfo() addcount = %d", addcount); + ns_logging = ns_wouldlog(ns_log_default, 3); + + if (ns_logging) + ns_debug(ns_log_default, 3, + "doaddinfo() addcount = %d", addcount); if (hp->tc) { ns_debug(ns_log_default, 4, @@ -1519,6 +1928,7 @@ doaddinfo(HEADER *hp, u_char *msg, int msglen) { count = 0; cp = msg; +loop: for (ap = addinfo; --addcount >= 0; ap++) { int foundany = 0, foundcname = 0, @@ -1526,37 +1936,50 @@ doaddinfo(HEADER *hp, u_char *msg, int msglen) { save_msglen = msglen; u_char *save_cp = cp; - ns_debug(ns_log_default, 3, - "do additional \"%s\" (from \"%s\")", - ap->a_dname, ap->a_rname); + if ((finishedA == 1 && ap->a_type == T_A) || + (finishedA == 0 && ap->a_type == T_KEY)) + continue; + if (ns_logging) + ns_debug(ns_log_default, 3, + "do additional \"%s\" (from \"%s\")", + ap->a_dname, ap->a_rname); htp = hashtab; /* because "nlookup" stomps on arg. */ np = nlookup(ap->a_dname, &htp, &fname, 0); if (np == NULL || fname != ap->a_dname) goto next_rr; - ns_debug(ns_log_default, 3, "found it"); + if (ns_logging) + ns_debug(ns_log_default, 3, "found it"); /* look for the data */ - delete_stale(np); + (void)delete_stale(np); for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (dp->d_rcode) continue; - if (match(dp, (int)ap->a_class, T_CNAME) || - match(dp, C_IN, T_CNAME)) { + if ((match(dp, (int)ap->a_class, T_CNAME) && + dp->d_type == T_CNAME) || + (match(dp, C_IN, T_CNAME) && + dp->d_type == T_CNAME)) { foundcname++; break; } - if (!match(dp, (int)ap->a_class, T_A) && + if (ap->a_type == T_A && + !match(dp, (int)ap->a_class, T_A) && !match(dp, C_IN, T_A) && !match(dp, (int)ap->a_class, T_AAAA) && !match(dp, C_IN, T_AAAA)) { continue; } + if (ap->a_type == T_KEY && + !match(dp, (int)ap->a_class, T_KEY) && + !match(dp, C_IN, T_KEY)) + continue; + foundany++; /* * Should be smart and eliminate duplicate * data here. XXX */ if ((n = make_rr(ap->a_dname, dp, cp, msglen, 0, - dnptrs, dnptrs_end)) < 0) { + dnptrs, dnptrs_end, 0)) < 0) { /* truncation in the additional-data section * is not all that serious. we do not set TC, * since the answer and authority sections are @@ -1583,10 +2006,11 @@ doaddinfo(HEADER *hp, u_char *msg, int msglen) { } next_rr: if (!NS_OPTION_P(OPTION_NOFETCHGLUE) && - !foundcname && !foundany) { + !foundcname && !foundany && + (ap->a_type == T_A || ap->a_type == T_AAAA)) { /* ask a real server for this info */ - (void) sysquery(ap->a_dname, (int)ap->a_class, T_A, - NULL, 0, QUERY); + (void) sysquery(ap->a_dname, (int)ap->a_class, + ap->a_type, NULL, 0, ns_port, QUERY); } if (foundcname) { if (!haveComplained(nhash(ap->a_dname), @@ -1600,6 +2024,11 @@ doaddinfo(HEADER *hp, u_char *msg, int msglen) { freestr(ap->a_dname); freestr(ap->a_rname); } + if (finishedA == 0) { + finishedA = 1; + addcount = save_addcount; + goto loop; /* now do the KEYs... */ + } hp->arcount = htons((u_int16_t)count); return (cp - msg); } @@ -1618,7 +2047,7 @@ doaddauth(HEADER *hp, u_char *cp, int buflen, dnbuf, buflen); return (0); } - n = make_rr(dnbuf, dp, cp, buflen, 1, dnptrs, dnptrs_end); + n = make_rr(dnbuf, dp, cp, buflen, 1, dnptrs, dnptrs_end, 1); if (n <= 0) { ns_debug(ns_log_default, 1, "doaddauth: can't add oversize '%s' (%d) (n=%d)", @@ -1628,6 +2057,8 @@ doaddauth(HEADER *hp, u_char *cp, int buflen, } return (0); } + if (dp->d_secure != DB_S_SECURE) + hp->ad = 0; hp->nscount = htons(ntohs(hp->nscount) + 1); return (n); } diff --git a/contrib/bind/bin/named/ns_resp.c b/contrib/bind/bin/named/ns_resp.c index 012f89e..d20b1ef 100644 --- a/contrib/bind/bin/named/ns_resp.c +++ b/contrib/bind/bin/named/ns_resp.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)ns_resp.c 4.65 (Berkeley) 3/3/91"; -static char rcsid[] = "$Id: ns_resp.c,v 8.56 1998/03/16 19:40:07 halley Exp $"; +static const char sccsid[] = "@(#)ns_resp.c 4.65 (Berkeley) 3/3/91"; +static const char rcsid[] = "$Id: ns_resp.c,v 8.133 1999/11/05 04:40:57 vixie Exp $"; #endif /* not lint */ /* @@ -82,7 +82,7 @@ static char rcsid[] = "$Id: ns_resp.c,v 8.56 1998/03/16 19:40:07 halley Exp $"; */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -104,6 +104,7 @@ static char rcsid[] = "$Id: ns_resp.c,v 8.56 1998/03/16 19:40:07 halley Exp $"; #include <sys/param.h> #include <sys/socket.h> #include <sys/file.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -122,6 +123,8 @@ static char rcsid[] = "$Id: ns_resp.c,v 8.56 1998/03/16 19:40:07 halley Exp $"; #include <isc/logging.h> #include <isc/memcluster.h> +#include <isc/dst.h> + #include "port_after.h" #include "named.h" @@ -164,23 +167,27 @@ struct flush_set { static void rrsetadd(struct flush_set *, const char *, struct databuf *), rrsetupdate(struct flush_set *, int flags, - struct sockaddr_in), + struct sockaddr_in, int), flushrrset(struct flush_set *, struct sockaddr_in), - free_flushset(struct flush_set *, int); -static int rrsetcmp(char *, struct db_list *), + free_flushset(struct flush_set *, int), + check_hints(struct flush_set *); +static int rrsetcmp(char *, struct db_list *, struct hashbuf *), check_root(void), check_ns(void), + wanted(const struct databuf *, int, int), + wantedsig(const struct databuf *, int, int), rrextract(u_char *, int, u_char *, struct databuf **, char *, int, struct sockaddr_in, char **); -static void sysnotify_slaves(const char *, const char *, - int, int, int *, int *); -static void sysnotify_ns(const char *, const char *, - int, int, int *, int *); +static void mark_bad(struct qinfo *qp, struct sockaddr_in from); +static void mark_lame(struct qinfo *qp, struct sockaddr_in from); +static void fast_retry(struct qinfo *qp, struct sockaddr_in from); static void add_related_additional(char *); static void free_related_additional(void); static int related_additional(char *); static void freestr_maybe(char **); +static enum ordering match_order(const struct namebuf *, int, int); +static int match_name(const struct namebuf *, const char *, size_t); #define MAX_RELATED 100 @@ -266,18 +273,19 @@ learntFrom(struct qinfo *qp, struct sockaddr_in *server) { } void -ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { +ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) +{ struct qinfo *qp; HEADER *hp; - struct qserv *qs; + struct qserv *qs = NULL; struct databuf *ns, *ns2; - u_char *cp; - u_char *eom = msg + msglen; + u_char *cp, *answers, *eom = msg + msglen; struct flush_set *flushset = NULL; int flushset_size = 0; struct sockaddr_in *nsa; struct databuf *nsp[NSMAX]; int i, c, n, qdcount, ancount, aucount, nscount, arcount, arfirst; + int soacount; u_int qtype, qclass; int restart; /* flag for processing cname response */ int validanswer, dbflags; @@ -286,7 +294,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { int buflen; int newmsglen; char name[MAXDNAME], qname[MAXDNAME], aname[MAXDNAME]; - char msgbuf[MAXDNAME]; + char msgbuf[MAXDNAME+100]; char *dname, tmpdomain[MAXDNAME]; const char *fname; const char *formerrmsg = "brain damage"; @@ -299,6 +307,14 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { struct databuf *dp; int forcecmsg = 0; char *tname = NULL; + int sendto_errno = 0; + int has_tsig, oldqlen; + u_char *oldqbuf; + u_char *smsg; + int smsglen, smsgsize, siglen; + u_char sig[TSIG_SIG_SIZE]; + time_t tsig_time; + DST_KEY *key; nameserIncr(from.sin_addr, nssRcvdR); nsp[0] = NULL; @@ -310,18 +326,39 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { return; } - ns_debug(ns_log_default, 2, "Response (%s %s %s) nsid=%d id=%d", - (qp->q_flags & Q_SYSTEM) ?"SYSTEM" :"USER", - (qp->q_flags & Q_PRIMING) ?"PRIMING" :"NORMAL", - (qp->q_flags & Q_ZSERIAL) ?"ZSERIAL" :"-", - ntohs(qp->q_nsid), ntohs(qp->q_id)); + if (ns_wouldlog(ns_log_default, 2)) { + ns_debug(ns_log_default, 2, "Response (%s %s %s) nsid=%d id=%d", + (qp->q_flags & Q_SYSTEM) ?"SYSTEM" :"USER", + (qp->q_flags & Q_PRIMING) ?"PRIMING" :"NORMAL", + (qp->q_flags & Q_ZSERIAL) ?"ZSERIAL" :"-", + ntohs(qp->q_nsid), ntohs(qp->q_id)); + } + + if (qp->q_nstsig == NULL) + has_tsig = 0; + else { + int ret; + + ret = ns_verify(msg, &msglen, qp->q_nstsig->key, + qp->q_nstsig->sig, qp->q_nstsig->siglen, + NULL, NULL, &tsig_time, 0); + if (ret == 0) + has_tsig = 1; + else { + if (hp->rcode == NOERROR) + hp->rcode = NOTAUTH; + ns_debug(ns_log_default, 1, + "resp: error bad tsig, record dropped"); + return; + } + } /* * Here we handle high level formatting problems by parsing the header. */ qdcount = ntohs(hp->qdcount); ancount = ntohs(hp->ancount); - aucount = ntohs(hp->nscount); /* !!! */ + aucount = ntohs(hp->nscount); arcount = ntohs(hp->arcount); free_addinfo(); /* sets addcount to zero */ cp = msg + HFIXEDSZ; @@ -343,7 +380,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { } GETSHORT(qtype, cp); GETSHORT(qclass, cp); - if (!ns_nameok(qname, qclass, NULL, response_trans, + if (!ns_nameok(qp, qname, qclass, NULL, response_trans, ns_ownercontext(qtype, response_trans), qname, from.sin_addr)) { formerrmsg = badNameFound; @@ -362,7 +399,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { formerrmsg = msgbuf; goto formerr; } - if (strcasecmp(qp->q_name, qname) != 0 || + if (ns_samename(qp->q_name, qname) != 1 || qp->q_class != qclass || qp->q_type != qtype) { formerrmsg = wrongQuestion; @@ -405,20 +442,11 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { nameserIncr(from.sin_addr, nssRcvdErr); break; } - /* mark server as bad */ - if (!qp->q_fwd) - for (i = 0; i < (int)qp->q_naddr; i++) - if (ina_equal(qp->q_addr[i].ns_addr.sin_addr, - from.sin_addr)) - qp->q_addr[i].nretry = MAXRETRY; - /* - * XXX: doesn't handle responses sent from the wrong - * interface on a multihomed server. - */ - if (qp->q_fwd || - ina_equal(qp->q_addr[qp->q_curaddr].ns_addr.sin_addr, - from.sin_addr)) - retry(qp); + if (ns_samename(qp->q_name, qp->q_domain) == 1 && + hp->rcode == SERVFAIL && hp->opcode == QUERY) + mark_lame(qp, from); + mark_bad(qp, from); + fast_retry(qp, from); return; } @@ -434,7 +462,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { * might have forwarded the query will be dropped. * XXX - should put this in STATS somewhere. */ - for (fwd = server_options->fwdtab; fwd; fwd = fwd->next) + for (fwd = NS_ZFWDTAB(qp->q_fzone); fwd; fwd = fwd->next) if (ina_equal(fwd->fwdaddr.sin_addr, from.sin_addr)) break; /* @@ -451,9 +479,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { if (fwd == NULL) { struct timeval *stp; - for (n = 0, qs = qp->q_addr; - (u_int)n < qp->q_naddr; - n++, qs++) + for (n = 0, qs = qp->q_addr; (u_int)n < qp->q_naddr; n++, qs++) if (ina_equal(qs->ns_addr.sin_addr, from.sin_addr)) break; if ((u_int)n >= qp->q_naddr) { @@ -472,7 +498,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { stp = &qs->stime; /* Handle response from different (untried) interface. */ - if ((qs->ns != NULL) && (stp->tv_sec == 0)) { + if (qs->ns != NULL && stp->tv_sec == 0) { ns = qs->ns; while (qs > qp->q_addr && (qs->stime.tv_sec == 0 || qs->ns != ns)) @@ -498,11 +524,13 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { (tt.tv_usec - stp->tv_usec) / 1000); } - ns_debug(ns_log_default, 3, - "stime %lu/%lu now %lu/%lu rtt %ld", - (u_long)stp->tv_sec, (u_long)stp->tv_usec, - (u_long)tt.tv_sec, (u_long)tt.tv_usec, - (long)rtrip); + if (ns_wouldlog(ns_log_default,3)) { + ns_debug(ns_log_default, 3, + "stime %lu/%lu now %lu/%lu rtt %ld", + (u_long)stp->tv_sec, (u_long)stp->tv_usec, + (u_long)tt.tv_sec, (u_long)tt.tv_usec, + (long)rtrip); + } /* prevent floating point overflow, limit to 1000 sec */ if (rtrip > 1000000) { @@ -534,9 +562,11 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { */ if (ns && qs->ns && (qp->q_nusedns < NSMAX)) { qp->q_usedns[qp->q_nusedns++] = qs->ns; - ns_debug(ns_log_default, 2, - "NS #%d addr %s used, rtt %d", - n, sin_ntoa(qs->ns_addr), ns->d_nstime); + if (ns_wouldlog(ns_log_default,2)) { + ns_debug(ns_log_default, 2, + "NS #%d addr %s used, rtt %d", + n, sin_ntoa(qs->ns_addr), ns->d_nstime); + } } /* @@ -573,9 +603,11 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { if (t > 65535) t = 65535; ns2->d_nstime = (u_int16_t)t; - ns_debug(ns_log_default, 2, "NS #%d %s rtt now %d", n, - sin_ntoa(qs->ns_addr), - ns2->d_nstime); + if (ns_wouldlog(ns_log_default,2)) { + ns_debug(ns_log_default, 2, "NS #%d %s rtt now %d", n, + sin_ntoa(qs->ns_addr), + ns2->d_nstime); + } } } @@ -586,11 +618,91 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { * a NOTIFY-QR is to remove it from the query queue. */ if (hp->opcode == NS_NOTIFY_OP) { + ns_info(ns_log_notify, + "Received NOTIFY answer from %s for \"%s %s %s\"", + inet_ntoa(from.sin_addr), + *(qp->q_name) ? qp->q_name : ".", + p_class(qp->q_class), p_type(qp->q_type)); qremove(qp); return; } #endif + if ((qp->q_flags & Q_ZSERIAL) != 0) { + if (hp->aa && ancount > 0 && hp->rcode == NOERROR && + qtype == T_SOA && (qclass == C_IN || qclass == C_HS)) + { + int n; + u_int type, class, dlen; + u_int32_t serial; + u_char *tp = cp; + u_char *rdatap; + + n = dn_expand(msg, eom, tp, name, sizeof name); + if (n < 0) { + formerrmsg = expandFailedAnswer; + goto formerr; + } + tp += n; /* name */ + if (tp + 3 * INT16SZ + INT32SZ > eom) { + formerrmsg = outofDataAnswer; + goto formerr; + } + GETSHORT(type, tp); /* type */ + GETSHORT(class, tp); /* class */ + tp += INT32SZ; /* ttl */ + GETSHORT(dlen, tp); /* dlen */ + rdatap = tp; /* start of rdata */ + if (!ns_nameok(qp, name, class, NULL, response_trans, + ns_ownercontext(type, response_trans), + name, from.sin_addr)) { + formerrmsg = badNameFound; + goto refused; + } + if (ns_samename(qname, name) != 1 || + qtype != type || qclass != class) { + sprintf(msgbuf, + "qserial answer mismatch (%s %s %s)", + name, p_class(class), p_type(type)); + formerrmsg = msgbuf; + goto formerr; + } + if (0 >= (n = dn_skipname(tp, eom))) { + formerrmsg = skipnameFailedAnswer; + goto formerr; + } + tp += n; /* mname */ + if (0 >= (n = dn_skipname(tp, eom))) { + formerrmsg = skipnameFailedAnswer; + goto formerr; + } + tp += n; /* rname */ + if (tp + 5 * INT32SZ > eom) { + formerrmsg = dlenUnderrunAnswer; + goto formerr; + } + GETLONG(serial, tp); + tp += 4 * INT32SZ; /* Skip rest of SOA. */ + if ((u_int)(tp - rdatap) != dlen) { + formerrmsg = dlenOverrunAnswer; + goto formerr; + } + for (n = 0, qs = qp->q_addr; (u_int)n < qp->q_naddr; + n++, qs++) + if (ina_equal(qs->ns_addr.sin_addr, + from.sin_addr)) + break; + if (n == qp->q_naddr) { + qserial_answer(qp); + qremove(qp); + return; + } + qs->serial = serial; + } + retry(qp); + return; + } + /* * Non-authoritative, no answer, no error, with referral. */ @@ -603,7 +715,8 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { int type, class; #ifdef DEBUG if (debug > 0) - fp_nquery(msg, msglen, log_get_stream(packet_channel)); + res_pquery(&res, msg, msglen, + log_get_stream(packet_channel)); #endif /* * Since there is no answer section (ancount == 0), @@ -622,7 +735,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { } GETSHORT(type, tp); GETSHORT(class, tp); - if (!ns_nameok(name, class, NULL, response_trans, + if (!ns_nameok(qp, name, class, NULL, response_trans, ns_ownercontext(type, response_trans), name, from.sin_addr)) { formerrmsg = badNameFound; @@ -638,14 +751,10 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { * classes tend to not have good strong delegation graphs). */ - if (type == T_NS && samedomain(qp->q_domain, name)) { + if (type == T_NS && ns_samedomain(qp->q_domain, name)) { nameserIncr(from.sin_addr, nssRcvdLDel); - /* mark server as bad */ - if (!qp->q_fwd) - for (i = 0; i < (int)qp->q_naddr; i++) - if (ina_equal(qp->q_addr[i].ns_addr.sin_addr, - from.sin_addr)) - qp->q_addr[i].nretry = MAXRETRY; + mark_lame(qp, from); + mark_bad(qp, from); if (class == C_IN && !haveComplained(ina_ulong(from.sin_addr), nhash(qp->q_domain))) { @@ -661,92 +770,21 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { freestr(learnt_from); } - /* XXX - doesn't handle responses sent from the wrong - * interface on a multihomed server - */ - if (qp->q_fwd || - ina_equal(qp->q_addr[qp->q_curaddr].ns_addr.sin_addr, - from.sin_addr)) - retry(qp); + fast_retry(qp, from); return; } } - if (qp->q_flags & Q_ZSERIAL) { - if (hp->aa && ancount > 0 && hp->rcode == NOERROR && - qtype == T_SOA && ((qclass == C_IN) || (qclass == C_HS))) - { - int n; - u_int type, class, dlen; - u_int32_t serial; - u_char *tp = cp; - u_char *rdatap; - - n = dn_expand(msg, eom, tp, name, sizeof name); - if (n < 0) { - formerrmsg = expandFailedAnswer; - goto formerr; - } - tp += n; /* name */ - if (tp + 3 * INT16SZ + INT32SZ > eom) { - formerrmsg = outofDataAnswer; - goto formerr; - } - GETSHORT(type, tp); /* type */ - GETSHORT(class, tp); /* class */ - tp += INT32SZ; /* ttl */ - GETSHORT(dlen, tp); /* dlen */ - rdatap = tp; /* start of rdata */ - if (!ns_nameok(name, class, NULL, response_trans, - ns_ownercontext(type, response_trans), - name, from.sin_addr)) { - formerrmsg = badNameFound; - goto refused; - } - if (strcasecmp(qname, name) || - qtype != type || - qclass != class) { - sprintf(msgbuf, - "qserial answer mismatch (%s %s %s)", - name, p_class(class), p_type(type)); - formerrmsg = msgbuf; - goto formerr; - } - if (0 >= (n = dn_skipname(tp, eom))) { - formerrmsg = skipnameFailedAnswer; - goto formerr; - } - tp += n; /* mname */ - if (0 >= (n = dn_skipname(tp, eom))) { - formerrmsg = skipnameFailedAnswer; - goto formerr; - } - tp += n; /* rname */ - if (tp + 5 * INT32SZ > eom) { - formerrmsg = dlenUnderrunAnswer; - goto formerr; - } - GETLONG(serial, tp); - tp += 4 * INT32SZ; /* Skip rest of SOA. */ - if ((u_int)(tp - rdatap) != dlen) { - formerrmsg = dlenOverrunAnswer; - goto formerr; - } - - qserial_answer(qp, serial, from); - qremove(qp); - } else { - retry(qp); - } - return; - } - /* * Add the info received in the response to the data base. */ arfirst = ancount + aucount; c = arfirst + arcount; + /* Don't return if it's a TSIG signed truncated message */ + if (has_tsig > 0 && hp->tc) + goto tcp_retry; + /* -ve $ing non-existence of record, must handle non-authoritative * NOERRORs with c == 0. */ @@ -769,11 +807,47 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { count -= ancount; /* things are pretty grim */ } +tcp_retry: /* retry using tcp provided this was not a tcp query */ if (!(qp->q_flags & Q_USEVC)) { qp->q_flags |= Q_USEVC; unsched(qp); schedretry(qp, 60); + + nsa = Q_NEXTADDR(qp, 0); + + key = tsig_key_from_addr(nsa->sin_addr); + if (key != NULL) { + smsgsize = qp->q_msglen + TSIG_BUF_SIZE; + smsg = memget(smsgsize); + smsglen = qp->q_msglen; + siglen = sizeof(sig); + memcpy(smsg, qp->q_msg, qp->q_msglen); + n = ns_sign(smsg, &smsglen, smsgsize, + NOERROR, key, NULL, 0, + sig, &siglen, 0); + if (n == 0) { + oldqbuf = qp->q_msg; + oldqlen = qp->q_msglen; + qp->q_msglen = smsglen; + qp->q_msg = smsg; + has_tsig = 1; + qp->q_nstsig = new_tsig(key, sig, + siglen); + } + else { + has_tsig = 0; + free_tsig(qp->q_nstsig); + qp->q_nstsig = NULL; + INSIST(0); + } + } + else { + has_tsig = 0; + free_tsig(qp->q_nstsig); + qp->q_nstsig = NULL; + } + if (tcp_send(qp) != NOERROR) /* * We're probably in trouble if tcp_send @@ -781,6 +855,12 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { * there isn't anything else to do. */ retry(qp); + + if (has_tsig == 1) { + memput(qp->q_msg, smsgsize); + qp->q_msg = oldqbuf; + qp->q_msglen = oldqlen; + } return; } else if (!qsp) { /* outstanding udp response */ @@ -789,15 +869,11 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { /* XXX truncated tcp response */ ns_error(ns_log_default, - "ns_resp: TCP truncated: \"%s\" %s %s", - qname, p_class(qclass), p_type(qtype)); + "ns_resp: TCP truncated: \"%s\" %s %s from %s", + qname, p_class(qclass), p_type(qtype), + sin_ntoa(from)); /* mark this server as bad */ - if (!qp->q_fwd) - for (i = 0; i < (int)qp->q_naddr; i++) - if (ina_equal(qp->q_addr[i].ns_addr.sin_addr, - from.sin_addr)) - qp->q_addr[i].nretry = MAXRETRY; - + mark_bad(qp, from); /* try another server, it may have a bigger write buffer */ retry(qp); return; @@ -808,6 +884,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { restart = 0; validanswer = 0; nscount = 0; + soacount = 0; cname = 0; lastwascname = 0; externalcname = 0; @@ -854,7 +931,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { type = dp->d_type; if (i < ancount) { /* Answer section. */ - if (externalcname || strcasecmp(name, aname) != 0) { + if (externalcname || ns_samename(name, aname) != 1) { if (!externalcname) ns_info(ns_log_resp_checks, "wrong ans. name (%s != %s)", @@ -870,7 +947,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { if (type == T_CNAME && qtype != T_CNAME && qtype != T_ANY) { strcpy(aname, (char *)dp->d_data); - if (!samedomain(aname, qp->q_domain)) + if (!ns_samedomain(aname, qp->q_domain)) externalcname = 1; cname++; lastwascname = 1; @@ -884,7 +961,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { tname = NULL; } - dp->d_cred = (hp->aa && !strcasecmp(name, qname)) + dp->d_cred = (hp->aa && ns_samename(name, qname) == 1) ? DB_C_AUTH : DB_C_ANSWER; } else { @@ -900,14 +977,14 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { switch (type) { case T_NS: case T_SOA: - if (!samedomain(aname, name)){ + if (!ns_samedomain(aname, name)) { ns_info(ns_log_resp_checks, "bad referral (%s !< %s)", aname[0] ? aname : ".", name[0] ? name : "."); db_freedata(dp); continue; - } else if (!samedomain(name, + } else if (!ns_samedomain(name, qp->q_domain)) { if (!externalcname) ns_info(ns_log_resp_checks, @@ -923,6 +1000,9 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { add_related_additional(tname); tname = NULL; } + if (type == T_SOA) { + soacount++; + } break; case T_NXT: /* XXX check */ @@ -939,13 +1019,17 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { db_freedata(dp); continue; } + dp->d_cred = (hp->aa && (cname == 0)) ? + DB_C_AUTH : (qp->q_flags & Q_PRIMING) + ? DB_C_ANSWER + : DB_C_ADDITIONAL; } else { /* Additional section. */ switch (type) { case T_A: case T_AAAA: if (externalcname || - !samedomain(name, qp->q_domain)) { + !ns_samedomain(name, qp->q_domain)) { ns_debug(ns_log_resp_checks, 3, "ignoring additional info '%s' type %s", name, p_type(type)); @@ -980,21 +1064,29 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { db_freedata(dp); continue; } + dp->d_cred = (qp->q_flags & Q_PRIMING) + ? DB_C_ANSWER + : DB_C_ADDITIONAL; } - dp->d_cred = (qp->q_flags & Q_PRIMING) - ? DB_C_ANSWER - : DB_C_ADDITIONAL; } rrsetadd(flushset, name, dp); } free_related_additional(); freestr_maybe(&tname); if (flushset != NULL) { - rrsetupdate(flushset, dbflags, from); + if ((qp->q_flags & Q_SYSTEM) && (qp->q_flags & Q_PRIMING)) { + check_hints(flushset); /* before rrsetupdate */ + rrsetupdate(flushset, dbflags, from, 1); + } else + rrsetupdate(flushset, dbflags, from, 0); free_flushset(flushset, flushset_size); } if (lastwascname && !externalcname) - ns_info(ns_log_cname, "%s (%s)", danglingCname, aname); + ns_debug(ns_log_cname, 3, "%s (%s) q(%s %s %s) %s qd(%s)", + danglingCname, aname, + (qname && *qname) ? qname : ".", + p_class(qclass), p_type(qtype), + sin_ntoa(from), qp->q_domain); if (cp > eom) { formerrmsg = outofDataAFinal; @@ -1004,18 +1096,8 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { if ((qp->q_flags & Q_SYSTEM) && ancount) { if ((qp->q_flags & Q_PRIMING) && !check_root()) { /* mark server as bad */ - if (!qp->q_fwd) - for (i = 0; i < (int)qp->q_naddr; i++) - if (ina_equal(qp->q_addr[i].ns_addr.sin_addr, - from.sin_addr)) - qp->q_addr[i].nretry = MAXRETRY; - /* XXX - doesn't handle responses sent from - * the wronginterface on a multihomed server - */ - if (qp->q_fwd || - qp->q_addr[qp->q_curaddr].ns_addr.sin_addr.s_addr - == from.sin_addr.s_addr) - retry(qp); + mark_bad(qp, from); + fast_retry(qp, from); return; } ns_debug(ns_log_default, 3, @@ -1024,9 +1106,8 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { if (qp->q_notifyzone != DB_Z_CACHE) { struct zoneinfo *zp = &zones[qp->q_notifyzone]; - /* Clear this first since sysnotify() might set it. */ qp->q_notifyzone = DB_Z_CACHE; - sysnotify(zp->z_origin, zp->z_class, ns_t_soa); + ns_notify(zp->z_origin, zp->z_class, ns_t_soa); } #endif qremove(qp); @@ -1052,6 +1133,9 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { restart = 1; } + if (!restart && !qp->q_cmsglen && ancount > 1 && qtype == T_A) + sort_response(tp, eom, ancount, &qp->q_from); + /* * An answer to a T_ANY query or a successful answer to a * regular query with no indirection, then just return answer. @@ -1068,11 +1152,19 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { * if ancount != 0 and rcode == NOERROR we cannot determine if the * CNAME chain has been processed to completion or not, so just * restart the query. DNS needs a NODATA return code! + * + * As some servers incorrectly return a NODATA indication when + * there is a CNAME chain instead of NXDOMAIN, we requery to get + * a definitive answer. */ - if (((hp->rcode == NXDOMAIN) && (cname == ancount)) || - ((hp->rcode == NOERROR) && (ancount == 0) && (nscount == 0))) + if ((hp->rcode == NXDOMAIN && cname == ancount) || + (hp->rcode == NOERROR && ancount == 0 && + (nscount == 0 || soacount != 0) + ) + ) { - cache_n_resp(msg, msglen, from); + cache_n_resp(msg, msglen, from, qp->q_name, + qp->q_class, qp->q_type); if (!qp->q_cmsglen) { ns_debug(ns_log_default, 3, @@ -1153,6 +1245,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { goto fetch_ns; foundname++; + answers = cp; count = cp - newmsg; /* * Look for NXDOMAIN record. @@ -1175,6 +1268,8 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { goto return_newmsg; } } +#else + count = 0; #endif hp->rcode = NXDOMAIN; /* @@ -1186,7 +1281,10 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { hp->aa = 1; ns_debug(ns_log_default, 3, "resp: NXDOMAIN aa = %d", hp->aa); - goto return_newmsg; + if ((count == 0) || NS_OPTION_P(OPTION_NORFC2308_TYPE1)) + goto return_newmsg; + founddata = 1; + goto fetch_ns; } } n = finddata(np, qclass, qtype, hp, &dname, &buflen, &count); @@ -1202,7 +1300,10 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { hp->nscount = htons((u_int16_t)count); } #endif - goto return_newmsg; + if ((count == 0) || NS_OPTION_P(OPTION_NORFC2308_TYPE1)) + goto return_newmsg; + founddata = 1; + goto fetch_ns; } cp += n; buflen -= n; @@ -1217,6 +1318,9 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { "resp: foundname=%d, count=%d, founddata=%d, cname=%d", foundname, count, founddata, cname); + if (count > 1 && qtype == T_A) + sort_response(answers, cp, count, &qp->q_from); + fetch_ns: if (hp->tc) goto return_newmsg; @@ -1256,7 +1360,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { } cp += n; buflen -= n; - hp->nscount = htons((u_int16_t)count); + hp->nscount = htons((u_int16_t)count + ntohs(hp->nscount)); goto return_newmsg; } @@ -1279,17 +1383,20 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { ns_freeqns(qp, "ns_resp"); qp->q_naddr = 0; qp->q_curaddr = 0; - qp->q_fwd = server_options->fwdtab; + nsfwdadd(qp, NS_ZFWDTAB(qp->q_fzone)); if (qp->q_domain != NULL) freestr(qp->q_domain); getname(np, tmpdomain, sizeof tmpdomain); qp->q_domain = savestr(tmpdomain, 1); - if ((n = nslookup(nsp, qp, dname, "ns_resp")) <= 0) { + if (NS_ZOPTION_P(qp->q_fzone, OPTION_FORWARD_ONLY)) + n = 0; + else if ((n = nslookup(nsp, qp, dname, "ns_resp")) <= 0) { if (n < 0) { - ns_debug(ns_log_default, 3, - "resp: nslookup reports danger"); + if (n == -1) + ns_debug(ns_log_default, 3, + "resp: nslookup reports danger"); if (cname) /* a remote CNAME that does not have data */ goto return_newmsg; goto servfail; @@ -1316,8 +1423,7 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { } for (n = 0; (u_int)n < qp->q_naddr; n++) qp->q_addr[n].stime.tv_sec = 0; - if (!qp->q_fwd) - qp->q_addr[0].stime = tt; + qp->q_addr[0].stime = tt; if (cname) { if (qp->q_cname++ == MAXCNAMES) { ns_debug(ns_log_default, 3, @@ -1339,8 +1445,8 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { goto servfail; } qp->q_msgsize = PACKETSZ; - n = res_mkquery(QUERY, dname, qclass, qtype, - NULL, 0, NULL, qp->q_msg, PACKETSZ); + n = res_nmkquery(&res, QUERY, dname, qclass, qtype, + NULL, 0, NULL, qp->q_msg, PACKETSZ); if (n < 0) { ns_info(ns_log_default, "resp: res_mkquery(%s) failed", dname); @@ -1355,23 +1461,55 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { } else hp = (HEADER *) qp->q_msg; hp->id = qp->q_nsid = htons(nsid_next()); - if (qp->q_fwd) + if (qp->q_addr[0].forwarder) hp->rd = 1; unsched(qp); schedretry(qp, retrytime(qp)); nsa = Q_NEXTADDR(qp, 0); - ns_debug(ns_log_default, 1, - "resp: forw -> %s ds=%d nsid=%d id=%d %dms", - sin_ntoa(*nsa), ds, - ntohs(qp->q_nsid), ntohs(qp->q_id), - (qp->q_addr[0].nsdata != NULL) - ? qp->q_addr[0].nsdata->d_nstime - : -1); + if (ns_wouldlog(ns_log_default,1)) { + ns_debug(ns_log_default, 1, + "resp: forw -> %s ds=%d nsid=%d id=%d %dms", + sin_ntoa(*nsa), ds, + ntohs(qp->q_nsid), ntohs(qp->q_id), + (qp->q_addr[0].nsdata != NULL) + ? qp->q_addr[0].nsdata->d_nstime + : -1); + } #ifdef DEBUG if (debug >= 10) - fp_nquery(qp->q_msg, qp->q_msglen, - log_get_stream(packet_channel)); + res_pquery(&res, qp->q_msg, qp->q_msglen, + log_get_stream(packet_channel)); #endif + key = tsig_key_from_addr(nsa->sin_addr); + if (key != NULL) { + smsgsize = qp->q_msglen + TSIG_BUF_SIZE; + smsg = memget(smsgsize); + smsglen = qp->q_msglen; + siglen = sizeof(sig); + memcpy(smsg, qp->q_msg, qp->q_msglen); + n = ns_sign(smsg, &smsglen, smsgsize, NOERROR, key, NULL, 0, + sig, &siglen, 0); + if (n == 0) { + oldqbuf = qp->q_msg; + oldqlen = qp->q_msglen; + qp->q_msglen = smsglen; + qp->q_msg = smsg; + has_tsig = 1; + qp->q_nstsig = new_tsig(key, sig, siglen); + } + else { + has_tsig = 0; + free_tsig(qp->q_nstsig); + qp->q_nstsig = NULL; + INSIST(0); + } + } + else { + has_tsig = 0; + free_tsig(qp->q_nstsig); + qp->q_nstsig = NULL; + } + if (qp->q_flags & Q_USEVC) { if (tcp_send(qp) != NOERROR) { if (!haveComplained(ina_ulong(nsa->sin_addr), @@ -1384,23 +1522,38 @@ ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { (struct sockaddr *)nsa, sizeof(struct sockaddr_in)) < 0) { + sendto_errno = errno; if (!haveComplained(ina_ulong(nsa->sin_addr), (u_long)sendtoStr)) ns_info(ns_log_default, "ns_resp: sendto(%s): %s", sin_ntoa(*nsa), strerror(errno)); nameserIncr(nsa->sin_addr, nssSendtoErr); } + if (has_tsig == 1) { + memput(qp->q_msg, smsgsize); + qp->q_msg = oldqbuf; + qp->q_msglen = oldqlen; + } hp->rd = 0; /* leave set to 0 for dup detection */ nameserIncr(nsa->sin_addr, nssSentFwdR); nameserIncr(qp->q_from.sin_addr, nssRcvdFwdR); ns_debug(ns_log_default, 3, "resp: Query sent."); free_nsp(nsp); + switch (sendto_errno) { + case ENETDOWN: + case ENETUNREACH: + case EHOSTDOWN: + case EHOSTUNREACH: + unsched(qp); + schedretry(qp, (time_t) 0); + } return; formerr: if (!haveComplained(ina_ulong(from.sin_addr), (u_long)formerrmsg)) ns_info(ns_log_resp_checks, "Malformed response from %s (%s)", sin_ntoa(from), formerrmsg); + fast_retry(qp, from); free_nsp(nsp); return; @@ -1487,7 +1640,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, { u_char *cp, *eom, *rdatap; u_int class, type, dlen; - int n, n1; + int n, n1, n2; u_int32_t ttl; u_char *cp1, data[MAXDATA*2]; HEADER *hp = (HEADER *)msg; @@ -1507,6 +1660,11 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ); GETSHORT(type, cp); GETSHORT(class, cp); + if (class > CLASS_MAX) { + ns_debug(ns_log_default, 3, "bad class in rrextract"); + hp->rcode = FORMERR; + return (-1); + } GETLONG(ttl, cp); if (ttl > MAXIMUM_TTL) { ns_debug(ns_log_default, 5, "%s: converted TTL > %u to 0", @@ -1516,7 +1674,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, GETSHORT(dlen, cp); BOUNDS_CHECK(cp, dlen); rdatap = cp; - if (!ns_nameok(dname, class, NULL, response_trans, + if (!ns_nameok(NULL, dname, class, NULL, response_trans, ns_ownercontext(type, response_trans), dname, from.sin_addr)) { hp->rcode = REFUSED; @@ -1558,6 +1716,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, case T_AAAA: case T_LOC: case T_KEY: + case ns_t_cert: cp1 = cp; n = dlen; cp += n; @@ -1574,7 +1733,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, hp->rcode = FORMERR; return (-1); } - if (!ns_nameok((char *)data, class, NULL, response_trans, + if (!ns_nameok(NULL, (char *)data, class, NULL, response_trans, type == T_PTR ?ns_ptrcontext(dname) :domain_ctx, dname, from.sin_addr)) { hp->rcode = FORMERR; @@ -1600,7 +1759,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, hp->rcode = FORMERR; return (-1); } - if (!ns_nameok((char *)data, class, NULL, response_trans, + if (!ns_nameok(NULL, (char *)data, class, NULL, response_trans, context, dname, from.sin_addr)) { hp->rcode = FORMERR; return (-1); @@ -1623,7 +1782,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, context = domain_ctx; else context = mailname_ctx; - if (!ns_nameok((char *)cp1, class, NULL, response_trans, + if (!ns_nameok(NULL, (char *)cp1, class, NULL, response_trans, context, dname, from.sin_addr)) { hp->rcode = FORMERR; return (-1); @@ -1679,7 +1838,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, hp->rcode = FORMERR; return (-1); } - if (!ns_nameok((char *)cp1, class, NULL, response_trans, + if (!ns_nameok(NULL, (char *)cp1, class, NULL, response_trans, hostname_ctx, dname, from.sin_addr)) { hp->rcode = FORMERR; return (-1); @@ -1718,7 +1877,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, hp->rcode = FORMERR; return (-1); } - if (!ns_nameok((char *)cp1, class, NULL, response_trans, + if (!ns_nameok(NULL, (char *)cp1, class, NULL, response_trans, hostname_ctx, dname, from.sin_addr)) { hp->rcode = FORMERR; return (-1); @@ -1749,7 +1908,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, hp->rcode = FORMERR; return (-1); } - if (!ns_nameok((char *)cp1, class, NULL, response_trans, + if (!ns_nameok(NULL, (char *)cp1, class, NULL, response_trans, domain_ctx, dname, from.sin_addr)) { hp->rcode = FORMERR; return (-1); @@ -1766,7 +1925,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, hp->rcode = FORMERR; return (-1); } - if (!ns_nameok((char *)cp1, class, NULL, response_trans, + if (!ns_nameok(NULL, (char *)cp1, class, NULL, response_trans, domain_ctx, dname, from.sin_addr)) { hp->rcode = FORMERR; return (-1); @@ -1779,13 +1938,16 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, case T_SIG: { u_long origTTL, exptime, signtime, timetilexp, now; + u_int8_t alg; /* Check signature time, expiration, and adjust TTL. */ /* This code is similar to that in db_load.c. */ - /* Skip coveredType, alg, labels */ + /* Skip coveredType, save alg, skip labels */ BOUNDS_CHECK(cp, INT16SZ + 1 + 1 + 3*INT32SZ); - cp1 = cp + INT16SZ + 1 + 1; + cp1 = cp + INT16SZ; + alg = *cp1++; + cp1++; GETLONG(origTTL, cp1); GETLONG(exptime, cp1); GETLONG(signtime, cp1); @@ -1836,7 +1998,7 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, /* then the signer's name */ n = dn_expand(msg, eom, cp, (char *)cp1, (sizeof data) - 18); - if (n < 0) { + if (n < 0 || n + NS_SIG_SIGNER > dlen) { hp->rcode = FORMERR; return (-1); } @@ -1845,15 +2007,31 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, /* finally, we copy over the variable-length signature. Its size is the total data length, minus what we copied. */ - if (18 + (u_int)n > dlen) { - hp->rcode = FORMERR; - return (-1); - } - n = dlen - (18 + n); - if (n > ((int)(sizeof data) - (int)(cp1 - (u_char *)data))) { + n = dlen - (NS_SIG_SIGNER + n); + + if (n > (sizeof data) - (cp1 - (u_char *)data)) { hp->rcode = FORMERR; return (-1); /* out of room! */ } + + switch (alg) { + case NS_ALG_MD5RSA: + if (n < NS_MD5RSA_MIN_SIZE || n > NS_MD5RSA_MAX_SIZE) + hp->rcode = FORMERR; + break; + + case NS_ALG_DSA: + if (n != NS_DSA_SIG_SIZE) + hp->rcode = FORMERR; + break; + + default: + break; + } + + if (hp->rcode == FORMERR) + return (-1); + memcpy(cp1, cp, n); cp += n; cp1 += n; @@ -1864,6 +2042,63 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, break; } + case T_NXT: + n = dn_expand(msg, eom, cp, (char *)data, sizeof data); + /* + * By testing if n >= dlen, we are requiring that the type + * bitmap be at least one octet. This is reasonable + * because we always have to look at the 0 bit to see if + * this is a "different format" NXT or not. + */ + if (n < 0 || n >= dlen) { + hp->rcode = FORMERR; + return (-1); + } + if (!ns_nameok(NULL, (char *)data, class, NULL, response_trans, + domain_ctx, dname, from.sin_addr)) { + hp->rcode = FORMERR; + return (-1); + } + cp += n; + n1 = strlen((char *)data) + 1; + cp1 = data + n1; + /* + * We don't need to BOUNDS_CHECK() cp here because we've + * previously checked that 'dlen' bytes are in bounds, and + * we know that n < dlen. + */ + n2 = dlen - n; + /* + * The first bit of the first octet determines the format + * of the NXT record. A format for types >= 128 has not + * yet been defined, so if bit zero is set, we just copy + * what's there because we don't understand it. + */ + if ((*cp & 0x80) == 0) { + /* + * Bit zero is not set; this is an ordinary NXT + * record. The bitmap must be at least 4 octets + * because the NXT bit should be set. It should be + * less than or equal to 16 octets because this NXT + * format is only defined for types < 128. + */ + if (n2 < 4 || n2 > 16) { + hp->rcode = FORMERR; + return (-1); + } + } + if (n2 > sizeof data - n1) { + hp->rcode = FORMERR; + return (-1); + } + memcpy(cp1, cp, n2); + cp += n2; + + /* compute size of data */ + n = cp1 - (u_char *)data; + cp1 = (u_char *)data; + break; + default: ns_debug(ns_log_default, 3, "unknown type %d", type); return ((cp - rrp) + dlen); @@ -1895,17 +2130,25 @@ rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, int send_msg(u_char *msg, int msglen, struct qinfo *qp) { + HEADER *hp = (HEADER *) msg; + u_char *oldmsg; + int oldlen; + int msgsize; + int ret; + if (qp->q_flags & Q_SYSTEM) return (1); if (!qp->q_stream && (msglen > PACKETSZ)) msglen = trunc_adjust(msg, msglen, PACKETSZ); - ns_debug(ns_log_default, 1, "send_msg -> %s (%s %d) id=%d", - sin_ntoa(qp->q_from), - qp->q_stream == NULL ? "UDP" : "TCP", - qp->q_stream == NULL ? qp->q_dfd : qp->q_stream->s_rfd, - ntohs(qp->q_id)); + if (ns_wouldlog(ns_log_default, 1)) { + ns_debug(ns_log_default, 1, "send_msg -> %s (%s %d) id=%d", + sin_ntoa(qp->q_from), + qp->q_stream == NULL ? "UDP" : "TCP", + qp->q_stream == NULL ? qp->q_dfd : qp->q_stream->s_rfd, + ntohs(qp->q_id)); + } #ifdef DEBUG - if (debug > 4) { + if (ns_wouldlog(ns_log_default, 4)) { struct qinfo *tqp; for (tqp = nsqhead; tqp != NULL; tqp = tqp->q_link) { @@ -1922,9 +2165,44 @@ send_msg(u_char *msg, int msglen, struct qinfo *qp) { } } if (debug >= 6) - fp_nquery(msg, msglen, log_get_stream(packet_channel)); + res_pquery(&res, msg, msglen, log_get_stream(packet_channel)); #endif /* DEBUG */ + + if (qp->q_tsig != NULL) { + u_char sig[TSIG_SIG_SIZE]; + int siglen = sizeof(sig); + + oldmsg = msg; + oldlen = msglen; + + msgsize = msglen + TSIG_BUF_SIZE; + msg = memget(msgsize); + memcpy(msg, oldmsg, oldlen); + + ret = ns_sign(msg, &msglen, msgsize, NOERROR, qp->q_tsig->key, + qp->q_tsig->sig, qp->q_tsig->siglen, + sig, &siglen, 0); + + if (ret != 0) { + INSIST(0); + } + } + if (qp->q_stream == NULL) { + /* + * Don't send FORMERR to these well known ports + * (loop avoidance). + */ + switch (ntohs(qp->q_from.sin_port)) { + case 7: /* echo */ + case 13: /* daytime */ + case 19: /* chargen */ + case 37: /* time */ + if (hp->rcode == FORMERR) + return (-1); + default: + break; + } if (sendto(qp->q_dfd, (char*)msg, msglen, 0, (struct sockaddr *)&qp->q_from, sizeof(qp->q_from)) < 0) { @@ -1942,232 +2220,78 @@ send_msg(u_char *msg, int msglen, struct qinfo *qp) { } } else writestream(qp->q_stream, (u_char*)msg, msglen); - return (0); -} -#ifdef notdef -/* i don't quite understand this but the only ref to it is notdef'd --vix */ -prime(class, type, oqp) - int class, type; - struct qinfo *oqp; -{ - char dname[MAXDNAME]; + if (qp->q_tsig != NULL) + memput(msg, oldlen + TSIG_BUF_SIZE); - if (oqp->q_msg == NULL) - return; - if (dn_expand((u_char *)oqp->q_msg, - (u_char *)oqp->q_msg + oqp->q_msglen, - (u_char *)oqp->q_msg + HFIXEDSZ, (u_char *)dname, - sizeof(dname)) < 0) - return; - ns_debug(ns_log_default, 2, "prime: %s", dname); - (void) sysquery(dname, class, type, NULL, 0, QUERY); + return (0); } -#endif -void -prime_cache() { - struct qinfo *qp; +static int +root_server_p(ns_class class) { + struct zoneinfo *zp = find_zone("", class); - /* - * XXX - should this always be skipped if OPTION_FORWARD_ONLY - * or should it be another option? What about when we are - * doing selective forwarding? - */ - if (!NS_OPTION_P(OPTION_FORWARD_ONLY)) { - ns_debug(ns_log_default, 1, "prime_cache: priming = %d", - priming); - if (!priming && fcachetab->h_tab[0] != NULL) { - priming++; - if (!(qp = sysquery("", C_IN, T_NS, NULL, 0, QUERY))) - priming = 0; - else - qp->q_flags |= (Q_SYSTEM | Q_PRIMING); - } - } - needs_prime_cache = 0; - return; + return (zp != NULL && + (zp->z_type == z_master || zp->z_type == z_slave)); } -#ifdef BIND_NOTIFY -/* - * sysnotify(dname, class, type) - * cause a NOTIFY request to be sysquery()'d to each secondary server - * of the zone that "dname" is within. - */ void -sysnotify(const char *dname, int class, int type) { - const char *zname, *fname; - int nns, na, zn, n; - struct zoneinfo *zp; - struct hashbuf *htp; - struct namebuf *np; - struct databuf *dp; - - ns_debug(ns_log_notify, 3, "sysnotify(%s, %s, %s)", - dname, p_class(class), p_type(type)); - htp = hashtab; - np = nlookup(dname, &htp, &fname, 0); - if (np == NULL) { - ns_warning(ns_log_notify, "sysnotify: can't find \"%s\"", - dname); - return; - } - zn = findMyZone(np, class); - if (zn == DB_Z_CACHE) { - ns_warning(ns_log_notify, "sysnotify: not auth for zone %s", - dname); - return; - } - zp = &zones[zn]; - if (zp->z_notify == znotify_no || - (zp->z_notify == znotify_use_default && - NS_OPTION_P(OPTION_NONOTIFY))) - return; - if (zp->z_type != z_master && zp->z_type != z_slave) { - ns_warning(ns_log_notify, "sysnotify: %s not master or slave", - dname); - return; - } - zname = zp->z_origin; - nns = na = 0; - if (zp->z_type == z_master) - sysnotify_slaves(dname, zname, class, zn, &nns, &na); - if (zp->z_notify_count != 0) { - struct in_addr *also_addr = zp->z_also_notify; - int i; - - for (i = 0; i < zp->z_notify_count; i++) { - sysquery(dname, class, T_SOA, also_addr, 1, - NS_NOTIFY_OP); - also_addr++; - } - nns += zp->z_notify_count; - na += zp->z_notify_count; - } - if (nns != 0 || na != 0) - ns_info(ns_log_notify, - "Sent NOTIFY for \"%s %s %s\" (%s); %d NS, %d A", - dname, p_class(class), p_type(type), zname, nns, na); -} - -static void -sysnotify_slaves(const char *dname, const char *zname, int class, int zn, - int *nns, int *na) -{ - const char *mname, *fname; - struct hashbuf *htp; - struct namebuf *np; - struct databuf *dp; - - /* - * Master. - */ - htp = hashtab; - np = nlookup(zname, &htp, &fname, 0); - if (!np) { - ns_warning(ns_log_notify, - "sysnotify: found name \"%s\" but not zone", - dname); - return; - } - mname = NULL; - for (dp = np->n_data; dp; dp = dp->d_next) { - if (dp->d_zone == DB_Z_CACHE || !match(dp, class, T_SOA)) - continue; - if (mname) { - ns_notice(ns_log_notify, - "multiple SOA's for zone \"%s\"?", - zname); - return; - } - mname = (char *) dp->d_data; - } - if (mname == NULL) { - ns_notice(ns_log_notify, "no SOA found for zone \"%s\"", - zname); - return; - } - for (dp = np->n_data; dp != NULL; dp = dp->d_next) { - if (dp->d_zone == DB_Z_CACHE || !match(dp, class, T_NS)) - continue; - if (strcasecmp((char*)dp->d_data, mname) == 0) - continue; - sysnotify_ns(dname, (char *)dp->d_data, class, zn, nns, na); - } -} +prime_cache(void) { + int root = root_server_p(ns_c_in); -static void -sysnotify_ns(const char *dname, const char *aname, - int class, int zn, int *nns, int *na) -{ - struct databuf *adp; - struct namebuf *anp; - const char *fname; - struct in_addr nss[NSMAX]; - struct hashbuf *htp; - int is_us, nsc; - - htp = hashtab; - anp = nlookup(aname, &htp, &fname, 0); - nsc = 0; - is_us = 0; - if (anp != NULL) - for (adp = anp->n_data; adp; adp = adp->d_next) { - struct in_addr ina; - - if (!match(adp, class, T_A)) - continue; - ina = ina_get(adp->d_data); - if (aIsUs(ina)) { - is_us = 1; - continue; - } - if (nsc < NSMAX) - nss[nsc++] = ina; - } /*next A*/ - if (nsc == 0) { - if (!is_us) { - struct qinfo *qp; + ns_debug(ns_log_default, 1, "prime_cache: priming = %d, root = %d", + priming, root); + if (!priming && !root) { + struct qinfo *qp = sysquery("", ns_c_in, ns_t_ns, + NULL, 0, ns_port, ns_o_query); - qp = sysquery(aname, class, T_A, 0, 0, QUERY); - if (qp != NULL) - qp->q_notifyzone = zn; + if (qp != NULL) { + qp->q_flags |= (Q_SYSTEM | Q_PRIMING); + priming++; } - return; } - (void) sysquery(dname, class, T_SOA, nss, nsc, NS_NOTIFY_OP); - (*nns)++; - *na += nsc; + needs_prime_cache = 0; } -#endif /*BIND_NOTIFY*/ struct qinfo * sysquery(const char *dname, int class, int type, - struct in_addr *nss, int nsc, int opcode) + struct in_addr *nss, int nsc, u_int16_t port, int opcode) { struct qinfo *qp, *oqp; HEADER *hp; char tmpdomain[MAXDNAME]; - struct namebuf *np; + struct namebuf *np = NULL; struct databuf *nsp[NSMAX]; - struct hashbuf *htp; + struct hashbuf *htp1; + struct hashbuf *htp2; + struct hashbuf *htp3; struct sockaddr_in *nsa; const char *fname; int n, count; + int sendto_errno = 0; + u_char *oldqbuf; + int oldqlen, has_tsig; + u_char *smsg; + int smsglen, smsgsize, siglen; + u_char sig[TSIG_SIG_SIZE]; + DST_KEY *key; nsp[0] = NULL; - ns_debug(ns_log_default, 3, "sysquery(%s, %d, %d, %#x, %d)", - dname, class, type, nss, nsc); + ns_debug(ns_log_default, 3, "sysquery(%s, %d, %d, %#x, %d, %d)", + dname, class, type, nss, nsc, ntohs(port)); qp = qnew(dname, class, type); - if (nss && nsc) + if (nss != NULL && nsc != 0) np = NULL; - else { - htp = hashtab; + else if (!NS_ZOPTION_P(qp->q_fzone, OPTION_FORWARD_ONLY)) { + htp1 = hashtab; + htp2 = hashtab; + htp3 = fcachetab; if (priming && dname[0] == '\0') { np = NULL; - } else if ((np = nlookup(dname, &htp, &fname, 1)) == NULL) { + } else if (((np = nlookup(dname, &htp1, &fname, 0)) == NULL) && + ((np = nlookup("", &htp2, &fname, 0)) == NULL) && + ((np = nlookup("", &htp3, &fname, 0)) == NULL)) { ns_info(ns_log_default, "sysquery: nlookup error on %s?", dname); @@ -2190,13 +2314,11 @@ sysquery(const char *dname, int class, int type, } } - /* build new qinfo struct */ + /* Build new qinfo struct. */ qp->q_cmsg = qp->q_msg = NULL; qp->q_dfd = ds; - if (nss && nsc) - qp->q_fwd = NULL; - else - qp->q_fwd = server_options->fwdtab; + if (nss == NULL || nsc == 0) + nsfwdadd(qp, NS_ZFWDTAB(qp->q_fzone)); qp->q_expire = tt.tv_sec + RETRY_TIMEOUT*2; qp->q_flags |= Q_SYSTEM; @@ -2208,9 +2330,9 @@ sysquery(const char *dname, int class, int type, goto err2; } qp->q_msgsize = PACKETSZ; - n = res_mkquery(opcode, dname, class, - type, NULL, 0, NULL, - qp->q_msg, PACKETSZ); + n = res_nmkquery(&res, opcode, dname, class, + type, NULL, 0, NULL, + qp->q_msg, PACKETSZ); if (n < 0) { ns_info(ns_log_default, "sysquery: res_mkquery(%s) failed", dname); @@ -2219,9 +2341,9 @@ sysquery(const char *dname, int class, int type, qp->q_msglen = n; hp = (HEADER *) qp->q_msg; hp->id = qp->q_nsid = htons(nsid_next()); - hp->rd = (qp->q_fwd ? 1 : 0); + hp->rd = (qp->q_addr[qp->q_curaddr].forwarder ? 1 : 0); - /* First check for an already pending query for this data */ + /* First check for an already pending query for this data. */ for (oqp = nsqhead; oqp != NULL; oqp = oqp->q_link) { if ((oqp != qp) && (oqp->q_msglen == qp->q_msglen) @@ -2242,30 +2364,30 @@ sysquery(const char *dname, int class, int type, } } - if (nss && nsc) { + if (nss != NULL && nsc != 0) { int i; struct qserv *qs; - for (i = 0, qs = qp->q_addr; - i < nsc; - i++, qs++) { + for (i = 0, qs = qp->q_addr; i < nsc; i++, qs++) { qs->ns_addr.sin_family = AF_INET; qs->ns_addr.sin_addr = nss[i]; - qs->ns_addr.sin_port = ns_port; + qs->ns_addr.sin_port = port; qs->ns = NULL; qs->nsdata = NULL; qs->stime = tt; + qs->forwarder = 0; qs->nretry = 0; } qp->q_naddr = nsc; - } else { + } else if (!NS_ZOPTION_P(qp->q_fzone, OPTION_FORWARD_ONLY)) { fetch_a: count = nslookup(nsp, qp, dname, "sysquery"); if (count <= 0) { if (count < 0) { - ns_info(ns_log_default, + if (n == -1) + ns_info(ns_log_default, "sysquery: nslookup reports danger (%s)", - dname); + dname); goto err2; } else if (np && NAME(*np)[0] == '\0') { /* @@ -2303,6 +2425,10 @@ sysquery(const char *dname, int class, int type, n, dname); goto err2; } + getname(np, tmpdomain, sizeof tmpdomain); + if (qp->q_domain != NULL) + freestr(qp->q_domain); + qp->q_domain = savestr(tmpdomain, 1); goto fetch_a; } goto err2; @@ -2310,8 +2436,7 @@ sysquery(const char *dname, int class, int type, } schedretry(qp, retrytime(qp)); - if (qp->q_fwd == NULL) - qp->q_addr[0].stime = tt; /* XXX - why not every? */ + qp->q_addr[0].stime = tt; /* XXX - why not every? */ nsa = Q_NEXTADDR(qp, 0); ns_debug(ns_log_default, 1, @@ -2321,20 +2446,67 @@ sysquery(const char *dname, int class, int type, (long)qp->q_time); #ifdef DEBUG if (debug >= 10) - fp_nquery(qp->q_msg, qp->q_msglen, - log_get_stream(packet_channel)); + res_pquery(&res, qp->q_msg, qp->q_msglen, + log_get_stream(packet_channel)); #endif + + key = tsig_key_from_addr(nsa->sin_addr); + if (key != NULL) { + smsgsize = qp->q_msglen + TSIG_BUF_SIZE; + smsg = memget(smsgsize); + smsglen = qp->q_msglen; + siglen = sizeof(sig); + memcpy(smsg, qp->q_msg, qp->q_msglen); + n = ns_sign(smsg, &smsglen, smsgsize, NOERROR, key, NULL, 0, + sig, &siglen, 0); + if (n == 0) { + oldqbuf = qp->q_msg; + oldqlen = qp->q_msglen; + qp->q_msglen = smsglen; + qp->q_msg = smsg; + has_tsig = 1; + qp->q_nstsig = new_tsig(key, sig, siglen); /* BEW? */ + + } + else { + INSIST(0); + has_tsig = 0; + free_tsig(qp->q_nstsig); + qp->q_nstsig = NULL; + } + } + else { + has_tsig = 0; + free_tsig(qp->q_nstsig); + qp->q_nstsig = NULL; + } + if (sendto(qp->q_dfd, (char*)qp->q_msg, qp->q_msglen, 0, (struct sockaddr *)nsa, sizeof(struct sockaddr_in)) < 0) { + sendto_errno = errno; if (!haveComplained(ina_ulong(nsa->sin_addr), (u_long)sendtoStr)) ns_info(ns_log_default, "sysquery: sendto(%s): %s", sin_ntoa(*nsa), strerror(errno)); nameserIncr(nsa->sin_addr, nssSendtoErr); } + if (has_tsig == 1) { + memput(qp->q_msg, smsgsize); + qp->q_msg = oldqbuf; + qp->q_msglen = oldqlen; + } + nameserIncr(nsa->sin_addr, nssSentSysQ); free_nsp(nsp); + switch (sendto_errno) { + case ENETDOWN: + case ENETUNREACH: + case EHOSTDOWN: + case EHOSTUNREACH: + unsched(qp); + schedretry(qp, (time_t) 0); + } return (qp); } @@ -2360,7 +2532,7 @@ check_root() { if (dp->d_type == T_NS) count++; ns_debug(ns_log_default, 1, "%d root servers", count); - if (count < MINROOTS) { + if (count < server_options->minroots) { ns_notice(ns_log_default, "check_root: %d root servers after query to root server < min", count); @@ -2429,12 +2601,12 @@ check_ns() { "check_ns: %s: not found %s %#lx", dname, fname, (u_long)tnp); sysquery(dname, dp->d_class, T_A, NULL, - 0, QUERY); + 0, ns_port, QUERY); continue; } /* look for name server addresses */ found_arr = 0; - delete_stale(tnp); + (void)delete_stale(tnp); for (tdp = tnp->n_data; tdp != NULL; tdp = tdp->d_next) { @@ -2463,7 +2635,7 @@ check_ns() { NAME(*np), NAME(*tnp)); else sysquery(dname, dp->d_class, T_A, NULL, - 0, QUERY); + 0, ns_port, QUERY); } } @@ -2530,7 +2702,7 @@ findns(struct namebuf **npp, int class, if (dp->d_zone != DB_Z_CACHE && ((zones[dp->d_zone].z_type == Z_PRIMARY) || (zones[dp->d_zone].z_type == Z_SECONDARY)) && - match(dp, class, T_SOA)) { + match(dp, class, T_SOA) && dp->d_type == T_SOA) { ns_debug(ns_log_default, 3, "findns: SOA found"); if (zones[dp->d_zone].z_flags & Z_AUTH) { @@ -2552,7 +2724,7 @@ findns(struct namebuf **npp, int class, /* If no SOA records, look for NS records. */ nspp = &nsp[0]; *nspp = NULL; - delete_stale(np); + (void)delete_stale(np); for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (!match(dp, class, T_NS)) continue; @@ -2630,46 +2802,48 @@ finddata(struct namebuf *np, int class, int type, struct databuf *dp; char *cp; int buflen, n, count = 0; + char *new_dnamep = NULL; + int defer = 0, found_count = 0, choice, i; + struct databuf **found = NULL; + struct databuf **tmpfound = NULL; + int foundcname; + int stalecount; + int ret = 0; + + stalecount = delete_stale(np); + + /* We don't want to return cached SIG records when asked for SIGs, + * since we may have an incomplete set. + */ + if (type == T_SIG && findMyZone(np, class) == DB_Z_CACHE) + return(0); - delete_stale(np); - -#ifdef ROUND_ROBIN - if (type != T_ANY && type != T_PTR) { - /* cycle order of RRs, for a load balancing effect... */ - - struct databuf **dpp; - - for (dpp = &np->n_data; (dp = *dpp) != NULL; - dpp = &dp->d_next) { - if (dp->d_next && wanted(dp, class, type)) { - struct databuf *lp; - - *dpp = lp = dp->d_next; - dp->d_next = NULL; - - for (dpp = &lp->d_next; - *dpp; - dpp = &lp->d_next) - lp = *dpp; - *dpp = dp; - break; - } - } + if (type != T_ANY && type != T_PTR && type != T_NXT) { + found = memget((stalecount + 1) * sizeof *found); + tmpfound = memget((stalecount + 1) * sizeof *tmpfound); + if (found == NULL || tmpfound == NULL) + ns_panic(ns_log_default, 1, "finddata: out of memory"); + defer = 1; } -#endif /*ROUND_ROBIN*/ buflen = *lenp; + #ifdef DEBUG if (buflen > PACKETSZ) ns_debug(ns_log_default, 1, "finddata(): buflen=%d", buflen); #endif cp = ((char *)hp) + *countp; + foundcname = 0; for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (!wanted(dp, class, type)) { if (type == T_CNAME && class == dp->d_class) { /* any data means no CNAME exists */ - *countp = 0; - return 0; + if (dp->d_type != T_NXT && + dp->d_type != T_KEY && + dp->d_type != T_SIG) { + ret = 0; + goto done; + } } continue; } @@ -2706,8 +2880,8 @@ finddata(struct namebuf *np, int class, int type, continue; hp->rcode = NOERROR_NODATA; if (dp->d_size == 0) { /* !RETURNSOA */ - *countp = 0; - return 1; /* XXX - we have to report success */ + ret = 1; + goto done; } } if (dp->d_rcode == NXDOMAIN) { @@ -2722,8 +2896,8 @@ finddata(struct namebuf *np, int class, int type, } hp->rcode = NXDOMAIN; if (dp->d_size == 0) { /* !RETURNSOA */ - *countp = 0; - return 1; /* XXX - we have to report success */ + ret = 1; + goto done; } } @@ -2733,49 +2907,285 @@ finddata(struct namebuf *np, int class, int type, (!((dp->d_type == T_SIG) || (dp->d_type == T_KEY))) ) continue; - if ((n = make_rr(*dnamep, dp, (u_char *)cp, buflen, 1, - dnptrs, dnptrs_end)) < 0) { - hp->tc = 1; - *countp = count; - return (*lenp - buflen); - } + if (!defer) { + if (foundcname != 0 && dp->d_type == T_CNAME) + continue; - cp += n; - buflen -= n; - count++; -#ifdef notdef - /* this isn't right for glue records, aa is set in ns_req */ - if (dp->d_zone != DB_Z_CACHE && - (zones[dp->d_zone].z_flags & Z_AUTH) != 0 && - class != C_ANY) - hp->aa = 1; /* XXX */ -#endif - if (dp->d_type == T_CNAME) { + if ((n = make_rr(*dnamep, dp, (u_char *)cp, buflen, 1, + dnptrs, dnptrs_end, 0)) < 0) { + hp->tc = 1; + ret = *lenp - buflen; + goto done; + } + if (dp->d_secure != DB_S_SECURE) + hp->ad = 0; + cp += n; + buflen -= n; + count++; + + if (dp->d_type == T_CNAME) { + foundcname = 1; +#define FOLLOWCNAME(type) \ + (type != T_KEY) && (type != T_SIG) && (type != T_NXT) && (type != T_ANY) /* don't alias if querying for key, sig, nxt, or any */ - if ((type != T_KEY) && - (type != T_SIG) && - (type != T_NXT) && - (type != T_ANY)) { /* or T_NS? */ - *dnamep = (caddr_t) dp->d_data; + + if (FOLLOWCNAME(type)) + new_dnamep = (char *)dp->d_data; } - break; + } else { + if (dp->d_type == T_CNAME) + foundcname = 1; + found[found_count++] = dp; } } + + if (found_count == 0 && count == 0) { + ret = 0; + goto done; + } + /* - * Cache invalidate the other RR's of same type - * if some have timed out + * If the query type was SIG or ANY we will have returned the SIG + * records already. */ + if (type != T_SIG && type != T_ANY) { + for (dp = np->n_data; dp != NULL; dp = dp->d_next) { + if (!wantedsig(dp, class, type)) + continue; + if (dp->d_cred == DB_C_ADDITIONAL) { +#ifdef NOADDITIONAL + continue; +#else + /* we want to expire additional data very + * quickly. current strategy is to cut 5% + * off each time it is accessed. this makes + * stale(dp) true earlier when this datum is + * used often. + */ + dp->d_ttl = tt.tv_sec + + + 0.95 * (int) (dp->d_ttl - tt.tv_sec); +#endif + } + if (!defer) { + if ((n = make_rr(*dnamep, dp, (u_char *)cp, + buflen, 1, dnptrs, dnptrs_end, + 0)) < 0) { + hp->tc = 1; + ret = *lenp - buflen; + goto done; + } + if (dp->d_secure != DB_S_SECURE) + hp->ad = 0; + cp += n; + buflen -= n; + count++; + } else + found[found_count++] = dp; + } + } + + if (defer && found_count > 0) { + int first_sig; + int non_sig_count; + int sig_count; /* number of SIG records in found */ + int idx, jdx; + enum ordering order; + + order = match_order(np, class, foundcname ? T_CNAME : type); + + /* shuffle the SIG records down to the bottom of the array + * as we need to make sure they get packed last, no matter + * what the ordering is. We're sure to maintain the + * original ordering within the two sets of records (so + * that fixed_order can work). + * First we pack the non-SIG records into the temp array. + */ + for (idx = jdx = 0 ; idx < found_count ; idx++) { + if (found[idx]->d_type != T_SIG) { + tmpfound[jdx++] = found[idx]; + } + } + non_sig_count = jdx; + sig_count = found_count - jdx; + first_sig = jdx ; + + /* now shift the SIG records down to the end of the array + * and copy in the non-SIG records + */ + for (i = idx = found_count - 1 ; idx >= 0 ; idx--) { + if (i < non_sig_count) { + found[i] = tmpfound[i]; + i--; + } else if (found[idx]->d_type == T_SIG) { + found[i--] = found[idx] ; + } + } + + foundcname = 0; + switch (order) { + case fixed_order: + for (i = 0; i < found_count; i++) { + dp = found[i]; + if (foundcname != 0 && dp->d_type == T_CNAME) + continue; + if (dp->d_type == T_CNAME) { + foundcname = 1; + if (FOLLOWCNAME(type)) { + new_dnamep = (char *)dp->d_data; + } + } + if ((n = make_rr(*dnamep, dp, (u_char *)cp, + buflen, 1, + dnptrs, dnptrs_end, 0)) < 0) { + hp->tc = 1; + ret = *lenp - buflen; + goto done; + } + if (dp->d_secure != DB_S_SECURE) + hp->ad = 0; + cp += n; + buflen -= n; + count++; + } + break; + + case random_order: { + /* first we shuffle the non-SIG records */ + int iters = non_sig_count; + for (i = 0; i < iters; i++) { + choice = ((u_int)rand()>>3) % non_sig_count; + non_sig_count--; + dp = found[choice]; + found[choice] = found[non_sig_count]; + if (foundcname != 0 && dp->d_type == T_CNAME) + continue; + if (dp->d_type == T_CNAME) { + foundcname = 1; + if (FOLLOWCNAME(type)) { + new_dnamep = (char *)dp->d_data; + } + } + if ((n = make_rr(*dnamep, dp, (u_char *)cp, + buflen, 1, + dnptrs, dnptrs_end, 0)) < 0) { + hp->tc = 1; + ret = *lenp - buflen; + goto done; + } + if (dp->d_secure != DB_S_SECURE) + hp->ad = 0; + cp += n; + buflen -= n; + count++; + } + + /* now shuffle the SIG records */ + iters = sig_count; + for (i = 0; i < iters; i++) { + choice = ((u_int)rand()>>3) % sig_count; + choice += first_sig; + sig_count--; + dp = found[choice]; + found[choice] = found[sig_count + first_sig]; + if ((n = make_rr(*dnamep, dp, (u_char *)cp, + buflen, 1, + dnptrs, dnptrs_end, 0)) < 0) { + hp->tc = 1; + ret = *lenp - buflen; + goto done; + } + if (dp->d_secure != DB_S_SECURE) + hp->ad = 0; + cp += n; + buflen -= n; + count++; + } + break; + } + + case cyclic_order: + /* first we do the non-SIG records */ + choice = ((u_int)rand()>>3) % non_sig_count; + for (i = 0; i < non_sig_count ; i++) { + dp = found[(i + choice) % non_sig_count]; + if (foundcname != 0 && dp->d_type == T_CNAME) + continue; + if (dp->d_type == T_CNAME) { + foundcname = 1; + if (FOLLOWCNAME(type)) { + new_dnamep = (char *)dp->d_data; + } + } + if ((n = make_rr(*dnamep, dp, (u_char *)cp, + buflen, 1, + dnptrs, dnptrs_end, 0)) < 0) { + hp->tc = 1; + ret = *lenp - buflen; + goto done; + } + if (dp->d_secure != DB_S_SECURE) + hp->ad = 0; + cp += n; + buflen -= n; + count++; + } + + /* now do the SIG record rotation. */ + if (sig_count > 0) { + choice = ((u_int)rand()>>3) % sig_count; + choice += first_sig; + i = choice; + do { + dp = found[i]; + if ((n = make_rr(*dnamep, dp, + (u_char *)cp, + buflen, 1, + dnptrs, + dnptrs_end, 0)) < 0) { + hp->tc = 1; + ret = *lenp - buflen; + goto done; + } + if (dp->d_secure != DB_S_SECURE) + hp->ad = 0; + cp += n; + buflen -= n; + count++; + i++; + if (i >= found_count) + i = first_sig; + } while (i != choice); + } + + break; + + default: + ns_warning(ns_log_default, "finddata: unknown ordering: %d", + order); + break; + } + } + + if (new_dnamep != NULL) + *dnamep = new_dnamep; + ns_debug(ns_log_default, 3, "finddata: added %d class %d type %d RRs", count, class, type); + ret = *lenp - buflen; + done: + if (found != NULL) + memput(found, (stalecount + 1) * sizeof *found); + if (tmpfound != NULL) + memput(tmpfound, (stalecount + 1) * sizeof *tmpfound); *countp = count; - return (*lenp - buflen); + return (ret); } /* * Do we want this data record based on the class and type? - * (We always return found unexpired SIG RR's that cover the wanted rrtype.) */ -int +static int wanted(const struct databuf *dp, int class, int type) { const u_char *cp; int coveredType; @@ -2818,7 +3228,7 @@ wanted(const struct databuf *dp, int class, int type) { cp += INT16SZ + INT32SZ; /* skip alg, labels, & orig TTL */ GETLONG(expiration,cp); - if (type == T_ANY || type == T_SIG || type == coveredType) { + if (type == T_ANY || type == T_SIG) { if (expiration > time(0)) return (1); /* Unexpired matching SIG */ } @@ -2833,11 +3243,9 @@ wanted(const struct databuf *dp, int class, int type) { break; } /* OK, now look at the type of query. */ - switch (type) { - case T_ANY: + if (type == ns_t_any) return (1); - - case T_MAILB: + else if (type == ns_t_mailb) switch (dp->d_type) { case T_MR: case T_MB: @@ -2845,14 +3253,57 @@ wanted(const struct databuf *dp, int class, int type) { case T_MINFO: return (1); } - break; - - case T_AXFR: - /* T_AXFR needs an authoritative SOA */ - if (dp->d_type == T_SOA && dp->d_zone != DB_Z_CACHE + else if (ns_t_xfr_p(type)) { + /* + * This is used to validate transfer requests, not + * generate transfer responses. Is there an SOA? + */ + if (dp->d_type == ns_t_soa && dp->d_zone != DB_Z_CACHE && (zones[dp->d_zone].z_flags & Z_AUTH)) return (1); - break; + } + return (0); +} + +static int +wantedsig(const struct databuf *dp, int class, int type) { + const u_char *cp; + int coveredType; + time_t expiration; +#ifdef DEBUG + char pclass[15], ptype[15]; +#endif + +#ifdef DEBUG + strcpy(pclass, p_class(class)); + strcpy(ptype, p_type(type)); + ns_debug(ns_log_default, 3, "wantedtsig(%#x, %s %s) [%s %s]", + dp, pclass, ptype, + p_class(dp->d_class), p_type(dp->d_type)); +#endif + + if (dp->d_class != class && class != C_ANY) + return (0); + if (dp->d_type != T_SIG || dp->d_rcode != 0) + return (0); + + cp = dp->d_data; + GETSHORT(coveredType, cp); + cp += INT16SZ + INT32SZ; /* skip alg, labels, & orig TTL */ + GETLONG(expiration,cp); + if (expiration < time(0)) + return (0); + + if (type == T_ANY || type == T_SIG || type == coveredType) + return (1); + if (type == ns_t_mailb) { + switch (coveredType) { + case T_MR: + case T_MB: + case T_MG: + case T_MINFO: + return (1); + } } return (0); } @@ -2879,7 +3330,7 @@ add_data(struct namebuf *np, struct databuf **dpp, if (dp->d_rcode) continue; if ((n = make_rr(dname, dp, cp, buflen, 1, - dnptrs, dnptrs_end)) < 0) + dnptrs, dnptrs_end, 0)) < 0) return (-bytes); /* Truncation */ cp += n; buflen -= n; @@ -2895,7 +3346,7 @@ rrsetadd(struct flush_set *flushset, const char *name, struct databuf *dp) { struct db_list *dbl; while (fs->fs_name && ( - strcasecmp(fs->fs_name,name) || + ns_samename(fs->fs_name,name) != 1 || (fs->fs_class != dp->d_class) || (fs->fs_type != dp->d_type) || (fs->fs_cred != dp->d_cred))) { @@ -2989,14 +3440,19 @@ ttlcheck(const char *name, struct db_list *dbl, int update) { return(1); } +/* + * lookup rrset in table and compare to dbl + * tri state result + * -1: lookup failed + * 0: rrsets same + * 1: rrsets differ + */ + static int -rrsetcmp(name, dbl) - char *name; - struct db_list *dbl; -{ +rrsetcmp(char * name, struct db_list * dbl, struct hashbuf * table) { int type = dbl->db_dp->d_type; int class = dbl->db_dp->d_class; - struct hashbuf *htp = hashtab; + struct hashbuf *htp = table; const char *fname; struct namebuf *np; struct db_list *dbp = dbl; @@ -3013,8 +3469,9 @@ rrsetcmp(name, dbl) /* check that all entries in dbl are in the cache */ while (dbp) { for (dp = np->n_data; dp != NULL; dp = dp->d_next) { - if (match(dp, class, type)) - exists++; + if (!match(dp, class, type)) + continue; + exists = 1; if (!db_cmp(dp, dbp->db_dp) #ifdef NOADDITIONAL && ((dp->d_cred == dbp->db_dp->d_cred) || @@ -3056,38 +3513,130 @@ rrsetcmp(name, dbl) return (0); } +/* + * verify incoming answer against what we already have in the hints + * issue warnings / errors if differences detected. + */ + static void -rrsetupdate(struct flush_set * flushset, int flags, struct sockaddr_in from) { +check_hints(struct flush_set * flushset) { + struct zoneinfo *zp; + struct flush_set *fs; + struct db_list *dbp; + + /* We don't use hints when in forward only mode */ + if (NS_OPTION_P(OPTION_FORWARD_ONLY)) + return; + + /* find "." NS rrset and hence class */ + for (fs = flushset; fs->fs_name != NULL; fs++) { + if ((fs->fs_name[0] != '\0') || (fs->fs_type != ns_t_ns)) + continue; + + /* see if we are a root server */ + zp = find_zone(fs->fs_name, fs->fs_class); + if (zp != NULL && + (zp->z_type == z_master || zp->z_type == z_slave)) + return; + switch (rrsetcmp(fs->fs_name, fs->fs_list, fcachetab)) { + case -1: + ns_error(ns_log_default, + "check_hints: no NS records for class %d in hints", + fs->fs_class); + break; + case 1: + ns_warning(ns_log_default, + "check_hints: root NS list in hints for class %d does not match root NS list", + fs->fs_class); + break; + case 0: + break; + default: + ns_error(ns_log_default, + "check_hints: unexpected response from rrsetcmp"); + break; + } + break; + } + + if (fs->fs_name == NULL) /* no root NS records */ + return; + + dbp = fs->fs_list; + while (dbp) { + /* for each NS find A rrset in answer and check */ + for (fs = flushset; fs->fs_name != NULL; fs++) { + if (ns_samename(fs->fs_name, (char *)dbp->db_dp->d_data) != 1 + || fs->fs_type != ns_t_a) + continue; + switch (rrsetcmp(fs->fs_name, fs->fs_list, fcachetab)) { + case -1: + ns_error(ns_log_default, + "check_hints: no A records for %s class %d in hints", + fs->fs_name[0] ? fs->fs_name : ".", + fs->fs_class); + break; + case 1: + ns_warning(ns_log_default, + "check_hints: A records for %s class %d do not match hint records", + fs->fs_name[0] ? fs->fs_name : ".", + fs->fs_class); + break; + case 0: + break; + default: + ns_error(ns_log_default, + "check_hints: unexpected response from rrsetcmp"); + break; + } + break; + } + + if (fs->fs_name == NULL) + ns_debug(ns_log_default, 2, + "check_hints: no A records for %s", + dbp->db_dp->d_data); + + dbp = dbp->db_next; + } +} + +static void +rrsetupdate(struct flush_set * flushset, int flags, struct sockaddr_in from, + int updatettl) { struct flush_set *fs = flushset; struct db_list *dbp, *odbp; int n; + void *state = NULL; while (fs->fs_name) { ns_debug(ns_log_default, 2, "rrsetupdate: %s", fs->fs_name[0] ? fs->fs_name : "."); - if ((n = rrsetcmp(fs->fs_name, fs->fs_list)) && + if ((n = rrsetcmp(fs->fs_name, fs->fs_list, hashtab)) && ttlcheck(fs->fs_name, fs->fs_list, 0)) { if (n > 0) flushrrset(fs, from); dbp = fs->fs_list; while (dbp) { - n = db_update(fs->fs_name, dbp->db_dp, - dbp->db_dp, NULL, flags, - hashtab, from); + n = db_set_update(fs->fs_name, dbp->db_dp, + &state, flags, + &hashtab, from, NULL, + 0, NULL); ns_debug(ns_log_default, 3, "rrsetupdate: %s %d", fs->fs_name[0] ? fs->fs_name : ".", n); - if (n != OK) - db_freedata(dbp->db_dp); odbp = dbp; dbp = dbp->db_next; memput(odbp, sizeof *odbp); } + ns_debug(ns_log_default, 3, + "rrsetupdate: %s %d", + fs->fs_name[0] ? fs->fs_name : ".", n); } else { - if (n == 0) - (void)ttlcheck(fs->fs_name,fs->fs_list, 1); + if ((n == 0) && updatettl) + (void)ttlcheck(fs->fs_name,fs->fs_list, 1); dbp = fs->fs_list; while (dbp) { db_freedata(dbp->db_dp); @@ -3099,6 +3648,8 @@ rrsetupdate(struct flush_set * flushset, int flags, struct sockaddr_in from) { fs->fs_list = NULL; fs++; } + n = db_set_update(NULL, NULL, &state, flags, &hashtab, from, + NULL, 0, NULL); } static void @@ -3161,22 +3712,26 @@ delete_all(struct namebuf *np, int class, int type) { * arguments: * np = pointer to namebuf to be cleaned. * returns: - * void. + * number of RRs associated with this name. * side effects: * delete_all() can be called, freeing memory and relinking chains. */ -void +int delete_stale(np) struct namebuf *np; { struct databuf *dp; - again: + int count; + again: + count = 0; for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (dp->d_zone == DB_Z_CACHE && stale(dp)) { delete_all(np, dp->d_class, dp->d_type); goto again; } + count++; } + return (count); } @@ -3256,6 +3811,44 @@ trunc_adjust(u_char *msg, int msglen, int outlen) { return (cp - msg); } +/* + * mark the server "from" bad in the qp structure so it won't be retried. + */ +static void +mark_bad(struct qinfo *qp, struct sockaddr_in from) { + int i; + + for (i = 0; i < (int)qp->q_naddr; i++) + if (ina_equal(qp->q_addr[i].ns_addr.sin_addr, from.sin_addr)) + qp->q_addr[i].nretry = MAXRETRY; +} + +static void +mark_lame(struct qinfo *qp, struct sockaddr_in from) { + int i; + + for (i = 0; i < (int)qp->q_naddr; i++) + if (ina_equal(qp->q_addr[i].ns_addr.sin_addr, from.sin_addr) && + qp->q_addr[i].ns != NULL) { + qp->q_addr[i].ns->d_flags |= DB_F_LAME; + db_lame_add(qp->q_domain, + (char*)qp->q_addr[i].ns->d_data, + tt.tv_sec + server_options->lame_ttl); + } +} + +/* + * Retry the message if and only if from matches where the query was + * last sent to. The code does not handle responses sent from the + * wrong interface an a multihomed server. + */ +static void +fast_retry(struct qinfo *qp, struct sockaddr_in from) { + if (ina_equal(qp->q_addr[qp->q_curaddr].ns_addr.sin_addr, + from.sin_addr)) + retry(qp); +} + static void add_related_additional(char *name) { int i; @@ -3263,7 +3856,7 @@ add_related_additional(char *name) { if (num_related >= MAX_RELATED - 1) return; for (i = 0; i < num_related; i++) - if (strcasecmp(name, related[i]) == 0) { + if (ns_samename(name, related[i]) == 1) { freestr(name); return; } @@ -3284,7 +3877,7 @@ related_additional(char *name) { int i; for (i = 0; i < num_related; i++) - if (strcasecmp(name, related[i]) == 0) + if (ns_samename(name, related[i]) == 1) return (1); return (0); } @@ -3296,3 +3889,87 @@ freestr_maybe(char **tname) { freestr(*tname); *tname = NULL; } + +/* + * Match a request namebuf against the configured rrset-order info. First + * match wins. There is an implicit '*.' at the front to the ordering names. + */ +static enum ordering +match_order(const struct namebuf *np, int class, int type) { + rrset_order_list orders = server_options->ordering; + rrset_order_element roe; + + if (orders == NULL) + return (DEFAULT_ORDERING); + + for (roe = orders->first ; roe != NULL ; roe = roe->next) { + if (roe->class != C_ANY && roe->class != class) + continue; + if (roe->type != T_ANY && roe->type != type) + continue; + + if (match_name(np, roe->name, strlen(roe->name)) == 0) { + return (roe->order); + } + } + + /* none matched so use default */ + return (DEFAULT_ORDERING); +} + +/* Do a simple compare of the NP data against the given NAME, recursively + * looking at the NP parent if necessary. NAMELEN is the length of the NAME + * that needs to be matched. Matching happen from right to left. Returns -1 + * on failure, on success the index of the first character of the matched + * portion of the string is returned. In the first level call a return + * value of 0 is of interest. + */ +static int +match_name(const struct namebuf *np, const char *name, size_t namelen) +{ + int matched ; + + if (name[0] == '*' && name[1] == '\0') + return 0; + + if (np->n_parent != NULL) { /* recurse to end of np list */ + matched = match_name(np->n_parent,name,namelen); + } else { + matched = namelen; + } + + if (matched > 0) { + int labellen = NAMELEN(*np); + char pch; + const char *start; + + if (labellen > matched) { + return -1; + } else if (labellen < matched) { + /* string is longer than this namebuf's data, so + make sure there's a period before the end of the + match so we don't just match a suffix. */ + start = name + (matched - labellen); + pch = start[-1]; + if (pch != '.') { + return -1; + } + } else { + start = name ; + } + + if (strncasecmp(start, NAME(*np), labellen) == 0) { + /* looking good. tell our caller what portion of + the tail of string has been matched */ + if (start == name) + return (0) ; + else + return (start - name - 1); /* matched '.' too */ + } else { + return (-1); + } + } + + return (matched); +} + diff --git a/contrib/bind/bin/named/ns_signal.c b/contrib/bind/bin/named/ns_signal.c new file mode 100644 index 0000000..4c7c48a --- /dev/null +++ b/contrib/bind/bin/named/ns_signal.c @@ -0,0 +1,264 @@ +#if !defined(lint) && !defined(SABER) +static const char sccsid[] = "@(#)ns_main.c 4.55 (Berkeley) 7/1/91"; +static const char rcsid[] = "$Id: ns_signal.c,v 8.11 1999/10/13 16:39:12 vixie Exp $"; +#endif /* not lint */ + +/* + * Copyright (c) 1986, 1989, 1990 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that 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. + */ + +/* Import. */ + +#include "port_before.h" + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#ifdef SVR4 /* XXX */ +# include <sys/sockio.h> +#else +# include <sys/mbuf.h> +#endif + +#include <netinet/in.h> +#include <net/route.h> +#include <net/if.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> + +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <grp.h> +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <netdb.h> +#include <pwd.h> +#include <resolv.h> +#include <string.h> +#include <syslog.h> +#include <time.h> +#include <unistd.h> + +#include <isc/eventlib.h> +#include <isc/logging.h> +#include <isc/memcluster.h> +#include <isc/list.h> + +#include "port_after.h" +#include "named.h" + +/* Forward. */ + +static SIG_FN onhup(int); +static SIG_FN onintr(int); +static SIG_FN setdumpflg(int); +static SIG_FN setIncrDbgFlg(int); +static SIG_FN setNoDbgFlg(int); +static SIG_FN setQrylogFlg(int); +static SIG_FN setstatsflg(int); +static SIG_FN discard_pipe(int); +static SIG_FN setreapflg(int); + +/* Data. */ + +static struct { + int sig; + SIG_FN (*hand)(int); +} sighandlers[] = { +#ifdef DEBUG + { SIGUSR1, setIncrDbgFlg }, + { SIGUSR2, setNoDbgFlg }, +#endif +#if defined(SIGWINCH) && defined(QRYLOG) + { SIGWINCH, setQrylogFlg }, +#endif +#if defined(SIGXFSZ) + { SIGXFSZ, onhup }, /* Wierd DEC Hesiodism, harmless. */ +#endif + { SIGINT, setdumpflg }, + { SIGILL, setstatsflg }, + { SIGHUP, onhup }, + { SIGCHLD, setreapflg }, + { SIGPIPE, discard_pipe }, + { SIGTERM, onintr } +}; + +static sigset_t mask; +static int blocked = 0; + +/* Private. */ + +static SIG_FN +onhup(int sig) { + ns_need_unsafe(main_need_reload); +} + +static SIG_FN +onintr(int sig) { + ns_need_unsafe(main_need_exit); +} + +static SIG_FN +setdumpflg(int sig) { + ns_need_unsafe(main_need_dump); +} + +#ifdef DEBUG +static SIG_FN +setIncrDbgFlg(int sig) { + desired_debug++; + ns_need_unsafe(main_need_debug); +} + +static SIG_FN +setNoDbgFlg(int sig) { + desired_debug = 0; + ns_need_unsafe(main_need_debug); +} +#endif /*DEBUG*/ + +#if defined(QRYLOG) && defined(SIGWINCH) +static SIG_FN +setQrylogFlg(int sig) { + ns_need_unsafe(main_need_qrylog); +} +#endif /*QRYLOG && SIGWINCH*/ + +static SIG_FN +setstatsflg(int sig) { + ns_need_unsafe(main_need_statsdump); +} + +static SIG_FN +discard_pipe(int sig) { +#ifdef SIGPIPE_ONE_SHOT + int saved_errno = errno; + struct sigaction sa; + + memset(&sa, 0, sizeof sa); + sa.sa_mask = mask; + sa.sa_handler = discard_pipe; + if (sigaction(SIGPIPE, &sa, NULL) < 0) + ns_error(ns_log_os, "sigaction failed in discard_pipe: %s", + strerror(errno)); + errno = saved_errno; +#endif +} + +static SIG_FN +setreapflg(int sig) { + ns_need_unsafe(main_need_reap); +} + +/* Public. */ + +void +init_signals(void) { + int sh; + + /* The mask of all our handlers will block all our other handlers. */ + (void)sigemptyset(&mask); + for (sh = 0; sh < sizeof sighandlers / sizeof sighandlers[0]; sh++) + sigaddset(&mask, sighandlers[sh].sig); + + /* Install our signal handlers with that shared mask. */ + for (sh = 0; sh < sizeof sighandlers / sizeof sighandlers[0]; sh++) { + struct sigaction sa; + + memset(&sa, 0, sizeof sa); + sa.sa_mask = mask; + sa.sa_handler = sighandlers[sh].hand; + if (sigaction(sighandlers[sh].sig, &sa, NULL) < 0) + ns_error(ns_log_os, + "sigaction failed in set_signal_handler(%d): %s", + sighandlers[sh].sig, strerror(errno)); + } +} + +void +block_signals(void) { + INSIST(!blocked); + if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) + ns_panic(ns_log_os, 1, "sigblock failed: %s", strerror(errno)); + blocked = 1; +} + +void +unblock_signals(void) { + INSIST(blocked); + if (sigprocmask(SIG_UNBLOCK, &mask, NULL) < 0) + ns_panic(ns_log_os, 1, "sigblock failed: %s", strerror(errno)); + blocked = 0; +} diff --git a/contrib/bind/bin/named/ns_sort.c b/contrib/bind/bin/named/ns_sort.c new file mode 100644 index 0000000..25c74eb --- /dev/null +++ b/contrib/bind/bin/named/ns_sort.c @@ -0,0 +1,410 @@ +#if !defined(lint) && !defined(SABER) +static const char sccsid[] = "@(#)ns_sort.c 4.10 (Berkeley) 3/3/91"; +static const char rcsid[] = "$Id: ns_sort.c,v 8.5 1999/10/13 16:39:12 vixie Exp $"; +#endif /* not lint */ + +/* + * Copyright (c) 1986, 1990 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that 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. + */ + +/* + * Sorting should really be handled by the resolver, but: + * 1) There are too many brain dead resolvers out there that can't be replaced. + * 2) It would be a pain to individually configure all those resolvers anyway. + * + * Here's the scoop: + * + * To enable address sorting in responses, you need to supply the sortlist + * statement in the config file. The sortlist statement takes an + * address match list and interprets it even more specially than the + * topology statement does. + * + * Each top level statement in the sortlist must itself be an explicit + * address match list with one or two elements. The first element + * (which may be an IP address, an IP prefix, an ACL name or nested + * address match list) of each top level list is checked against the + * source address of the query until a match is found. + * + * Once the source address of the query has been matched, if the top level + * statement contains only one element, the actual primitive element that + * matched the source address is used to select the address in the response + * to move to the beginning of the response. If the statement is a list + * of two elements, then the second element is treated like the address + * match list in a topology statement. Each top level element is assigned + * a distance and the address in the response with the minimum distance is + * moved to the beginning of the response. + * + * In the following example, any queries received from any of the addresses + * of the host itself will get responses preferring addresses on any of + * the locally connected networks. Next most preferred are addresses on + * the 192.168.1/24 network, and after that either the 192.168.2/24 or + * 192.168.3/24 network with no preference shown between these two networks. + * Queries received from a host on the 192.168.1/24 network will prefer + * other addresses on that network to the 192.168.2/24 and 192.168.3/24 + * networks. Queries received from a host on the 192.168.4/24 or the + * 192.168.5/24 network will only prefer other addresses on their + * directly connected networks. + * + * sortlist { + * { + * localhost; + * { + * localnets; + * 192.168.1/24; + * { 192,168.2/24; 192.168.3/24; }; + * }; + * }; + * { + * 192.168.1/24; + * { + * 192.168.1/24; + * { 192.168.2/24; 192.168.3/24; }; + * }; + * }; + * { + * 192.168.2/24; + * { + * 192.168.2/24; + * { 192.168.1/24; 192.168.3/24; }; + * }; + * }; + * { + * 192.168.3/24; + * { + * 192.168.3/24; + * { 192.168.1/24; 192.168.2/24; }; + * }; + * }; + * { + * { 192.168.4/24; 192.168.5/24; }; + * }; + * }; + * + * + * The following example will give reasonable behaviour for the local host + * and hosts on directly connected networks. It is similar to the behavior + * of the address sort in BIND 4.9.x. Responses sent to queries from the + * local host will favor any of the directly connected networks. Responses + * sent to queries from any other hosts on a directly connected network will + * prefer addresses on that same network. Responses to other queries will + * not be sorted. + * + * sortlist { + * { localhost; localnets; }; + * { localnets; }; + * }; + * + * XXX - it wouldb e nice to have an ACL called "source" that matched the + * source address of a query so that a host could be configured to + * automatically prefer itself, and an ACL called "sourcenet", that + * would return the primitive IP match element that matched the source + * address so that you could do: + * { localnets; { sourcenet; { other stuff ...}; }; + * and automatically get similar behaviour to what you get with: + * { localnets; }; + * + */ + +#include "port_before.h" + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/file.h> +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <syslog.h> +#include <resolv.h> + +#include <isc/eventlib.h> +#include <isc/logging.h> + +#include "port_after.h" + +#include "named.h" + +static int sort_rr(u_char *cp, u_char *eom, int ancount, ip_match_list iml); + +static int ip_match_address_elt(ip_match_list, struct in_addr, + ip_match_element *); + +void +sort_response(u_char *cp, u_char *eom, int ancount, struct sockaddr_in *from) { + struct in_addr address; + struct ip_match_element imelement; + ip_match_element imetl, imematch, imeprimitive; + struct ip_match_list imlist; + ip_match_list iml; + int indirect, matched; + + if (server_options->sortlist == NULL) + return; + + if (from->sin_family != AF_INET) + return; + + address = from->sin_addr; + + for (imetl = server_options->sortlist->first; imetl != NULL; + imetl = imetl->next) { + if (imetl->type == ip_match_indirect) + imematch = imetl->u.indirect.list->first; + else + /* + * allow a bare pattern as a top level statement + * and treat it like {pattern;}; + */ + imematch = imetl; + + switch (imematch->type) { + case ip_match_pattern: + indirect = 0; + break; + case ip_match_indirect: + indirect = 1; + break; + case ip_match_localhost: + imematch->u.indirect.list = local_addresses; + indirect = 1; + break; + case ip_match_localnets: + imematch->u.indirect.list = local_networks; + indirect = 1; + break; + default: + panic("unexpected ime type in ip_match_address()", + NULL); + } + if (indirect) { + imeprimitive = NULL; + matched = ip_match_address_elt(imematch->u.indirect.list, + address, &imeprimitive); + if (matched >= 0) { + if (imematch->flags & IP_MATCH_NEGATE) + /* Don't sort */ + return; + } else + continue; + } else { + if (ina_onnet(address, imematch->u.direct.address, + imematch->u.direct.mask)) { + if (imematch->flags & IP_MATCH_NEGATE) + /* Don't sort */ + return; + else + imeprimitive = imematch; + } else + continue; + } + if (imetl != imematch && imematch->next != NULL) { + /* + * Not a bare pattern at the top level, but a two + * element list + */ + switch (imematch->next->type) { + case ip_match_pattern: + case ip_match_localhost: + case ip_match_localnets: + imelement = *(imematch->next); + imelement.next = NULL; + iml = &imlist; + iml->first = iml->last = &imelement; + break; + case ip_match_indirect: + iml = imematch->next->u.indirect.list; + break; + default: + panic("unexpected ime type in ip_match_address()", + NULL); + } + } else if (imeprimitive) { + imelement = *imeprimitive; + imelement.next = NULL; + iml = &imlist; + iml->first = iml->last = &imelement; + } else { + /* Don't sort because we'd just use "any" */ + return; + } + sort_rr(cp, eom, ancount, iml); + break; + } + + return; +} + +static int +sort_rr(u_char *cp, u_char *eom, int ancount, ip_match_list iml) { + int type, class, dlen, n, c, distance, closest; + struct in_addr inaddr; + u_char *rr1 = NULL, *rrbest, *cpstart; + + rr1 = NULL; + cpstart = cp; + for (c = ancount; c > 0; --c) { + n = dn_skipname(cp, eom); + if (n < 0) + return (1); /* bogus, stop processing */ + cp += n; + if (cp + QFIXEDSZ > eom) + return (1); + GETSHORT(type, cp); + GETSHORT(class, cp); + cp += INT32SZ; + GETSHORT(dlen, cp); + if (dlen > eom - cp) + return (1); /* bogus, stop processing */ + switch (type) { + case T_A: + switch (class) { + case C_IN: + case C_HS: + memcpy((char *)&inaddr, cp, INADDRSZ); + /* Find the address with the minimum distance */ + if (rr1 == NULL) { + rr1 = cp; + rrbest = cp; + closest = distance_of_address(iml, inaddr); + } else { + distance = distance_of_address(iml, inaddr); + if (distance < closest) { + rrbest = cp; + closest = distance; + } + } + break; + } + break; + } + cp += dlen; + } + if (rr1 != rrbest && rr1 != NULL) { + memcpy((char *)&inaddr, rrbest, INADDRSZ); + memcpy(rrbest, rr1, INADDRSZ); + memcpy(rr1, (char *)&inaddr, INADDRSZ); + } + return (0); +} + +/* + * Just like ip_match_address(), but also returns a pointer to the primitive + * element that matched. + */ + +static int +ip_match_address_elt(ip_match_list iml, struct in_addr address, + ip_match_element *imep) { + ip_match_element ime; + int ret; + int indirect; + + INSIST(iml != NULL); + for (ime = iml->first; ime != NULL; ime = ime->next) { + switch (ime->type) { + case ip_match_pattern: + indirect = 0; + break; + case ip_match_indirect: + indirect = 1; + break; + case ip_match_localhost: + ime->u.indirect.list = local_addresses; + indirect = 1; + break; + case ip_match_localnets: + ime->u.indirect.list = local_networks; + indirect = 1; + break; + default: + panic("unexpected ime type in ip_match_address()", + NULL); + } + if (indirect) { + ret = ip_match_address_elt(ime->u.indirect.list, + address, imep); + if (ret >= 0) { + if (ime->flags & IP_MATCH_NEGATE) + ret = (ret) ? 0 : 1; + return (ret); + } + } else { + if (ina_onnet(address, ime->u.direct.address, + ime->u.direct.mask)) { + *imep = ime; + if (ime->flags & IP_MATCH_NEGATE) + return (0); + else + return (1); + } + } + } + return (-1); +} diff --git a/contrib/bind/bin/named/ns_stats.c b/contrib/bind/bin/named/ns_stats.c index 5be0257..44552ed 100644 --- a/contrib/bind/bin/named/ns_stats.c +++ b/contrib/bind/bin/named/ns_stats.c @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) -static char sccsid[] = "@(#)ns_stats.c 4.10 (Berkeley) 6/27/90"; -static char rcsid[] = "$Id: ns_stats.c,v 8.18 1998/02/13 19:50:24 halley Exp $"; +static const char sccsid[] = "@(#)ns_stats.c 4.10 (Berkeley) 6/27/90"; +static const char rcsid[] = "$Id: ns_stats.c,v 8.27 1999/10/13 16:39:12 vixie Exp $"; #endif /* not lint */ /* @@ -57,7 +57,7 @@ static char rcsid[] = "$Id: ns_stats.c,v 8.18 1998/02/13 19:50:24 halley Exp $"; */ /* - * Portions Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -77,12 +77,15 @@ static char rcsid[] = "$Id: ns_stats.c,v 8.18 1998/02/13 19:50:24 halley Exp $"; #include <sys/types.h> #include <sys/param.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 <resolv.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -103,39 +106,7 @@ static char rcsid[] = "$Id: ns_stats.c,v 8.18 1998/02/13 19:50:24 halley Exp $"; #include "named.h" -static u_long typestats[T_ANY+1]; -static const char *typenames[T_ANY+1] = { - /* 5 types per line */ - "Unknown", "A", "NS", "invalid(MD)", "invalid(MF)", - "CNAME", "SOA", "MB", "MG", "MR", - "NULL", "WKS", "PTR", "HINFO", "MINFO", - "MX", "TXT", "RP", "AFSDB", "X25", - "ISDN", "RT", "NSAP", "NSAP_PTR", "SIG", - "KEY", "PX", "invalid(GPOS)", "AAAA", "LOC", - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - /* 20 per line */ - 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, - /* 100 */ - "UINFO", "UID", "GID", "UNSPEC", 0, 0, 0, 0, 0, 0, - /* 110 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 120 */ - 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 200 */ - 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, - /* 240 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 250 */ - 0, 0, "AXFR", "MAILB", "MAILA", "ANY" -}; - +static u_long typestats[T_ANY+1]; static void nameserStats(FILE *); void @@ -161,25 +132,39 @@ ns_stats() { /* query type statistics */ fprintf(f, "%lu\tUnknown query types\n", (u_long)typestats[0]); - for(i=1; i < T_ANY+1; i++) - if (typestats[i]) { - if (typenames[i] != NULL) - fprintf(f, "%lu\t%s queries\n", - (u_long)typestats[i], typenames[i]); - else - fprintf(f, "%lu\ttype %d queries\n", - (u_long)typestats[i], i); - } + for (i = 1; i < T_ANY+1; i++) + fprintf(f, "%lu\t%s queries\n", typestats[i], p_type(i)); /* name server statistics */ nameserStats(f); + fprintf(f, "--- Statistics Dump --- (%ld) %s", + (long)timenow, checked_ctime(&timenow)); + (void) my_fclose(f); + + /* Now do the memory statistics file */ + if (!(f = fopen(server_options->memstats_filename, "a"))) { + ns_notice(ns_log_statistics, "cannot open memstat file, \"%s\"", + server_options->memstats_filename); + return; + } + + fprintf(f, "+++ Memory Statistics Dump +++ (%ld) %s", + (long)timenow, checked_ctime(&timenow)); + + fprintf(f, "%ld\ttime since boot (secs)\n", + (long)(timenow - boottime)); + fprintf(f, "%ld\ttime since reset (secs)\n", + (long)(timenow - resettime)); + fprintf(f, "++ Memory Statistics ++\n"); memstats(f); fprintf(f, "-- Memory Statistics --\n"); - fprintf(f, "--- Statistics Dump --- (%ld) %s", + + fprintf(f, "--- Memory Statistics Dump --- (%ld) %s", (long)timenow, checked_ctime(&timenow)); (void) my_fclose(f); + ns_notice(ns_log_statistics, "done dumping nameserver stats"); } @@ -370,11 +355,7 @@ ns_logstats(evContext ctx, void *uap, struct timespec due, for (i = 0; i < T_ANY+1; i++) { if (typestats[i]) { - if (typenames[i]) - sprintf(buffer2, " %s=%lu", - typenames[i], typestats[i]); - else - sprintf(buffer2, " %d=%lu", i, typestats[i]); + sprintf(buffer2, " %s=%lu", p_type(i), typestats[i]); if (strlen(buffer) + strlen(buffer2) > sizeof(buffer) - 1) { ns_info(ns_log_statistics, buffer); diff --git a/contrib/bind/bin/named/ns_udp.c b/contrib/bind/bin/named/ns_udp.c index 8b1af5e..95f0438 100644 --- a/contrib/bind/bin/named/ns_udp.c +++ b/contrib/bind/bin/named/ns_udp.c @@ -1,9 +1,9 @@ #if !defined(lint) && !defined(SABER) -static char rcsid[] = "$Id: ns_udp.c,v 8.5 1997/05/21 19:52:26 halley Exp $"; +static const char rcsid[] = "$Id: ns_udp.c,v 8.8 1999/10/13 16:39:13 vixie Exp $"; #endif /* not lint */ /* - * Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -26,6 +26,7 @@ static char rcsid[] = "$Id: ns_udp.c,v 8.5 1997/05/21 19:52:26 halley Exp $"; #include <sys/stat.h> #include <sys/socket.h> #include <sys/file.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> diff --git a/contrib/bind/bin/named/ns_update.c b/contrib/bind/bin/named/ns_update.c index 48db076..4f9817f 100644 --- a/contrib/bind/bin/named/ns_update.c +++ b/contrib/bind/bin/named/ns_update.c @@ -1,9 +1,9 @@ #if !defined(lint) && !defined(SABER) -static char rcsid[] = "$Id: ns_update.c,v 8.26 1998/05/05 19:45:10 halley Exp $"; +static const char rcsid[] = "$Id: ns_update.c,v 8.68 1999/11/05 04:40:58 vixie Exp $"; #endif /* not lint */ /* - * Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -20,6 +20,26 @@ static char rcsid[] = "$Id: ns_update.c,v 8.26 1998/05/05 19:45:10 halley Exp $" */ /* + * Portions Copyright (c) 1999 by Check Point Software Technologies, 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, and that + * the name of Check Point Software Technologies Incorporated 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 CHECK POINT SOFTWARE TECHNOLOGIES + * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED + * 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> */ @@ -31,6 +51,7 @@ static char rcsid[] = "$Id: ns_update.c,v 8.26 1998/05/05 19:45:10 halley Exp $" #include <sys/file.h> #include <sys/socket.h> #include <sys/stat.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -40,6 +61,7 @@ static char rcsid[] = "$Id: ns_update.c,v 8.26 1998/05/05 19:45:10 halley Exp $" #include <fcntl.h> #include <limits.h> #include <resolv.h> +#include <res_update.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -52,10 +74,14 @@ static char rcsid[] = "$Id: ns_update.c,v 8.26 1998/05/05 19:45:10 halley Exp $" #include <isc/logging.h> #include <isc/memcluster.h> +#include <isc/dst.h> + #include "port_after.h" #include "named.h" +static ns_updque curupd; + #define WRITEABLE_MASK (S_IWUSR | S_IWGRP | S_IWOTH) /* XXXRTH almost all funcs. in here should be static! @@ -106,14 +132,8 @@ static struct map m_section[] = { }; #define M_SECTION_CNT (sizeof(m_section) / sizeof(struct map)) +/* Forward. */ -/* from ns_req.c */ - -static ns_updrec *rrecp_start = NULL, *rrecp_last = NULL; - - -/* forward */ -static int findzone(const char *, int, int, int *, int); static int rdata_expand(const u_char *, const u_char *, const u_char *, u_int, size_t, u_char *, size_t); @@ -134,6 +154,21 @@ open_transaction_log(struct zoneinfo *zp) { return (fp); } +static FILE * +open_ixfr_log(struct zoneinfo *zp) { + FILE *fp; + + fp = fopen(zp->z_ixfr_base, "a+"); + if (fp == NULL) { + ns_error(ns_log_update, "can't open %s: %s", zp->z_ixfr_base, + strerror(errno)); + return (NULL); + } + if (ftell(fp) == 0L) { + fprintf(fp, "%s", LogSignature); + } + return (fp); +} static int close_transaction_log(struct zoneinfo *zp, FILE *fp) { @@ -155,13 +190,69 @@ close_transaction_log(struct zoneinfo *zp, FILE *fp) { return (0); } +static int +close_ixfr_log(struct zoneinfo *zp, FILE *fp) { + if (fflush(fp) == EOF) { + ns_error(ns_log_update, "fflush() of %s failed: %s", + zp->z_ixfr_base, strerror(errno)); + fclose(fp); + return (-1); + } + if (fsync(fileno(fp)) < 0) { + ns_error(ns_log_update, "fsync() of %s failed: %s", + zp->z_ixfr_base, strerror(errno)); + fclose(fp); + return (-1); + } + if (fclose(fp) == EOF) { + ns_error(ns_log_update, "fclose() of %s failed: %s", + zp->z_ixfr_base, strerror(errno)); + return (-1); + } + return (0); +} + +/* + * return true if 'db' had been added. + */ +static int +was_added(const ns_updque *updlist, struct databuf *dp) { + ns_updrec *rrecp; + + for (rrecp = HEAD(*updlist); rrecp != NULL; rrecp = NEXT(rrecp, r_link)) + if (rrecp->r_section == S_UPDATE && rrecp->r_dp == dp) + return (1); + return (0); +} + +/* + * return true if 'db' had been deleted. + */ +static int +was_deleted(const ns_updque *updlist, struct databuf *dp) { + ns_updrec *rrecp; + struct databuf *adp; + + + for (rrecp = HEAD(*updlist); rrecp != NULL; rrecp = NEXT(rrecp, r_link)) + if (rrecp->r_section == S_UPDATE && + rrecp->r_deldp != NULL) { + adp = rrecp->r_deldp; + do { + if (adp == dp) + return (1); + } while ((adp = adp->d_next) != NULL); + } + return (0); +} + /* - * printupdatelog(srcaddr, firstp, hp, zp, old_serial) + * printupdatelog(srcaddr, updlist, hp, zp, old_serial) * append an ascii form to the zone's transaction log file. */ static void printupdatelog(struct sockaddr_in srcaddr, - ns_updrec *firstp, + const ns_updque *updlist, HEADER *hp, struct zoneinfo *zp, u_int32_t old_serial) @@ -171,25 +262,35 @@ printupdatelog(struct sockaddr_in srcaddr, ns_updrec *rrecp; int opcode; char time[25]; - FILE *fp; + FILE *fp, *ifp; - if (!firstp) + if (EMPTY(*updlist)) return; fp = open_transaction_log(zp); if (fp == NULL) return; + ifp = open_ixfr_log(zp); + if (ifp == NULL) { + (void) close_transaction_log(zp, fp); + return; + } sprintf(time, "at %lu", (u_long)tt.tv_sec); fprintf(fp, "[DYNAMIC_UPDATE] id %u from %s %s (named pid %ld):\n", - hp->id, sin_ntoa(srcaddr), time, (long)getpid()); - for (rrecp = firstp; rrecp; rrecp = rrecp->r_next) { + ntohs(hp->id), sin_ntoa(srcaddr), time, (long)getpid()); + fprintf(ifp, "[DYNAMIC_UPDATE] id %u from %s %s (named pid %ld):\n", + ntohs(hp->id), sin_ntoa(srcaddr), time, (long)getpid()); + for (rrecp = HEAD(*updlist); rrecp != NULL; rrecp = NEXT(rrecp, r_link)) { INSIST(zp == &zones[rrecp->r_zone]); switch (rrecp->r_section) { case S_ZONE: fprintf(fp, "zone:\torigin %s class %s serial %u\n", zp->z_origin, p_class(zp->z_class), old_serial); + fprintf(ifp, "zone:\torigin %s class %s serial %u\n", + zp->z_origin, p_class(zp->z_class), + old_serial); break; case S_PREREQ: opcode = rrecp->r_opcode; @@ -207,6 +308,45 @@ printupdatelog(struct sockaddr_in srcaddr, break; case S_UPDATE: opcode = rrecp->r_opcode; + /* + * Translate all deletes into explict actions by + * looking at what was actually deleted from the + * zone for the ixfr log. + */ + dp = rrecp->r_deldp; + while (dp != NULL) { + if (dp->d_rcode == 0 && + !was_added(updlist, dp)) { + fprintf(ifp, + "update:\t{%s} %s. %u %s %s ", + "delete", + rrecp->r_dname, + dp->d_ttl, + p_class(dp->d_class), + p_type(dp->d_type)); + (void) rdata_dump(dp, ifp); + fprintf(ifp, "\n"); + } + dp = dp->d_next; + } + /* + * Only successful adds should be recorded. + * Don't add changes that are undone later. + * SOA additions performed later. + */ + if (opcode == ADD && (dp = rrecp->r_dp) != NULL && + dp->d_type != T_SOA && + (dp->d_mark & D_MARK_ADDED) != 0 && + !was_deleted(updlist, dp)) { + fprintf(ifp, "update:\t{%s} %s. ", + opcodes[opcode], rrecp->r_dname); + fprintf(ifp, "%u ", rrecp->r_ttl); + fprintf(ifp, "%s ", p_class(zp->z_class)); + fprintf(ifp, "%s ", p_type(rrecp->r_type)); + (void) rdata_dump(dp, ifp); + fprintf(ifp, "\n"); + } + /* Update log. */ fprintf(fp, "update:\t{%s} %s. ", opcodes[opcode], rrecp->r_dname); if (opcode == ADD) @@ -228,8 +368,37 @@ printupdatelog(struct sockaddr_in srcaddr, /*NOTREACHED*/ } } + /* + * SOA additions must be last in this update as they + * (or [INCR_SERIAL]) terminate an IXFR chunk. Only the last SOA + * addition will be emitted for any dynamic update regardless + * of the number of SOA changes in the update. + */ + for (rrecp = HEAD(*updlist); rrecp != NULL; rrecp = NEXT(rrecp, r_link)) { + INSIST(zp == &zones[rrecp->r_zone]); + switch (rrecp->r_section) { + case S_UPDATE: + opcode = rrecp->r_opcode; + if (opcode == ADD && (dp = rrecp->r_dp) != NULL && + dp->d_type == T_SOA && + (dp->d_mark & D_MARK_ADDED) != 0 && + !was_deleted(updlist, dp)) { + fprintf(ifp, "update:\t{%s} %s. ", + opcodes[opcode], rrecp->r_dname); + fprintf(ifp, "%u ", rrecp->r_ttl); + fprintf(ifp, "%s ", p_class(zp->z_class)); + fprintf(ifp, "%s ", p_type(rrecp->r_type)); + (void) rdata_dump(dp, ifp); + fprintf(ifp, "\n[END_DELTA]\n"); + } + break; + default: + break; + } + } fprintf(fp, "\n"); (void) close_transaction_log(zp, fp); + (void) close_ixfr_log(zp, ifp); } static void @@ -379,8 +548,15 @@ process_prereq(ns_updrec *ur, int *rcodep, u_int16_t zclass) { } htp = hashtab; np = nlookup(dname, &htp, &fname, 0); - if (fname != dname) - np = NULL; /* Matching by wildcard not allowed here. */ + /* + * Matching by wildcard not allowed here. + * We need to post check for a wildcard match. + */ + if (fname != dname || + (np != NULL && ns_wildcard(NAME(*np)) && + (dname[0] != '*' || (dname[1] != '.' && dname[1] != '\0')))) + np = NULL; + if (class == C_ANY) { if (rdp->d_size) { ns_debug(ns_log_update, 1, @@ -411,7 +587,8 @@ process_prereq(ns_updrec *ur, int *rcodep, u_int16_t zclass) { for (dp = np->n_data; dp && !found; dp = dp->d_next) - if (match(dp, class, type)) + if (match(dp, class, type) && + dp->d_type == type) found = 1; if (!found) { ns_debug(ns_log_update, 1, @@ -485,12 +662,12 @@ process_prereq(ns_updrec *ur, int *rcodep, u_int16_t zclass) { return (0); } for (dp = np->n_data; dp; dp = dp->d_next) { - if (match(dp, class, type)) { + if (match(dp, class, type) && dp->d_type == type) { int found = 0; for (tmp = ur; - tmp && !found; - tmp = tmp->r_next) { + tmp != NULL && !found; + tmp = NEXT(tmp, r_link)) { if (tmp->r_section != S_PREREQ) break; if (!db_cmp(dp, tmp->r_dp)) { @@ -505,9 +682,9 @@ process_prereq(ns_updrec *ur, int *rcodep, u_int16_t zclass) { } } } - for (tmp = ur; tmp; tmp = tmp->r_next) + for (tmp = ur; tmp != NULL; tmp = NEXT(tmp, r_link)) if (tmp->r_section == S_PREREQ && - !strcasecmp(dname, tmp->r_dname) && + ns_samename(dname, tmp->r_dname) == 1 && tmp->r_class == class && tmp->r_type == type && (ur->r_dp->d_mark & D_MARK_FOUND) == 0) { @@ -527,6 +704,153 @@ process_prereq(ns_updrec *ur, int *rcodep, u_int16_t zclass) { return (1); } +static int +prescan_nameok(ns_updrec *ur, int *rcodep, u_int16_t zclass, + struct zoneinfo *zp) { + const char *dname = ur->r_dname; + const char *owner = ur->r_dname; + u_int16_t class = ur->r_class; + u_int16_t type = ur->r_type; + char *cp = (char *)ur->r_dp->d_data; + enum context context; + + int ret = 1; + + /* We don't care about deletes */ + if (ur->r_class != zclass) + return (1); + + context = ns_ownercontext(type, primary_trans); + if (!ns_nameok(NULL, owner, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + + switch (type) { + case ns_t_soa: + context = hostname_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + cp += strlen(cp) + 1; + context = mailname_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_rp: + context = mailname_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + cp += strlen(cp) + 1; + context = domain_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_minfo: + context = mailname_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + cp += strlen(cp) + 1; + context = mailname_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_ns: + context = hostname_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_cname: + case ns_t_mb: + case ns_t_mg: + case ns_t_mr: + context = domain_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_ptr: + context = ns_ptrcontext(owner); + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_naptr: + /* + * Order (2) + * Preference (2) + * Flags (1) + */ + cp += 5; + /* Service (txt) */ + cp += strlen(cp) + 1; + /* Pattern (txt) */ + cp += strlen(cp) + 1; + context = domain_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_srv: + cp += 4; + /* FALLTHROUGH */ + case ns_t_mx: + case ns_t_afsdb: + case ns_t_rt: + case ns_t_kx: + cp += 2; + context = hostname_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_px: + cp += 2; + context = domain_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + cp += strlen(cp) + 1; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_sig: + /* + * Type covered (2) + * Alg (1) * + * Labels (1) + * ttl (4) + * expires (4) + * signed (4) + * footprint (2) + */ + cp += 18; + context = domain_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_nxt: + context = domain_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + default: + break; + } + return (1); + refused: + *rcodep = REFUSED; + return (0); +} + /* * int * prescan_update(ur, rcodep) @@ -549,9 +873,7 @@ prescan_update(ns_updrec *ur, int *rcodep, u_int16_t zclass) { struct namebuf *np; if (class == zclass) { - if (type == T_ANY || - type == T_AXFR || type == T_IXFR || - type == T_MAILA || type == T_MAILB) { + if (!ns_t_rr_p(type)) { ns_debug(ns_log_update, 1, "prescan_update: invalid type (%s)", p_type(type)); @@ -560,19 +882,18 @@ prescan_update(ns_updrec *ur, int *rcodep, u_int16_t zclass) { } } else if (class == C_ANY) { if (ttl != 0 || rdp->d_size || - type == T_AXFR || type == T_IXFR || - type == T_MAILA || type == T_MAILB) { + (!ns_t_rr_p(type) && type != T_ANY)) + { ns_debug(ns_log_update, 1, "prescan_update: formerr(#2)"); *rcodep = FORMERR; return (0); } } else if (class == C_NONE) { - if (ttl != 0 || type == T_ANY || - type == T_AXFR || type == T_IXFR || - type == T_MAILA || type == T_MAILB) { + if (ttl != 0 || !ns_t_rr_p(type)) { ns_debug(ns_log_update, 1, - "prescan_update: formerr(#3)"); + "prescan_update: formerr(#3) %d %s", + ttl, p_type(type)); *rcodep = FORMERR; return (0); } @@ -589,7 +910,7 @@ prescan_update(ns_updrec *ur, int *rcodep, u_int16_t zclass) { /* * int - * process_updates(firstp, rcodep, from) + * process_updates(updlist, rcodep, from) * Process prerequisites and apply updates from the list to the database. * returns: * number of successful updates, 0 if none were successful. @@ -598,7 +919,9 @@ prescan_update(ns_updrec *ur, int *rcodep, u_int16_t zclass) { * can schedule maintainance for zone dumps and soa.serial# increments. */ static int -process_updates(ns_updrec *firstp, int *rcodep, struct sockaddr_in from) { +process_updates(const ns_updque *updlist, int *rcodep, + struct sockaddr_in from) +{ int i, j, n, dbflags, matches, zonenum; int numupdated = 0, soaupdated = 0, schedmaint = 0; u_int16_t zclass; @@ -609,11 +932,12 @@ process_updates(ns_updrec *firstp, int *rcodep, struct sockaddr_in from) { int zonelist[MAXDNAME]; *rcodep = SERVFAIL; - if (!firstp) + if (EMPTY(*updlist)) return (0); - if (firstp->r_section == S_ZONE) { - zclass = firstp->r_class; - zonenum = firstp->r_zone; + ur = HEAD(*updlist); + if (ur->r_section == S_ZONE) { + zclass = ur->r_class; + zonenum = ur->r_zone; zp = &zones[zonenum]; } else { ns_debug(ns_log_update, 1, @@ -622,7 +946,7 @@ process_updates(ns_updrec *firstp, int *rcodep, struct sockaddr_in from) { } /* Process prereq records and prescan update records. */ - for (ur = firstp; ur != NULL; ur = ur->r_next) { + for (ur = HEAD(*updlist); ur != NULL; ur = NEXT(ur, r_link)) { const char * dname = ur->r_dname; u_int16_t class = ur->r_class; u_int16_t type = ur->r_type; @@ -642,7 +966,9 @@ class=%s, type=%s, ttl=%d, dp=0x%0x", for (j = 0; j < matches && !ur->r_zone; j++) if (zonelist[j] == zonenum) ur->r_zone = zonelist[j]; - if (!ur->r_zone) { + if (!ur->r_zone || + (section != S_ADDT && type == T_SOA && + ns_samename(dname, zp->z_origin) != 1)) { ns_debug(ns_log_update, 1, "process_updates: record does not belong to the zone %s", zones[zonenum].z_origin); @@ -661,6 +987,8 @@ class=%s, type=%s, ttl=%d, dp=0x%0x", case S_UPDATE: if (!prescan_update(ur, rcodep, zclass)) return (0); /* *rcodep has been set. */ + if (!prescan_nameok(ur, rcodep, zclass, zp)) + return (0); /* *rcodep has been set. */ ns_debug(ns_log_update, 3, "update prescan succeeded"); break; case S_ADDT: @@ -673,7 +1001,7 @@ class=%s, type=%s, ttl=%d, dp=0x%0x", } /* Now process the records in update section. */ - for (ur = firstp; ur != NULL; ur = ur->r_next) { + for (ur = HEAD(*updlist); ur != NULL; ur = NEXT(ur, r_link)) { const char * dname = ur->r_dname; u_int16_t class = ur->r_class; @@ -689,10 +1017,11 @@ class=%s, type=%s, ttl=%d, dp=0x%0x", * is done in db_update(). */ ur->r_opcode = ADD; - dbflags |= DB_NODATA; + dbflags |= DB_NODATA | DB_REPLACE; n = db_update(dname, dp, dp, &savedp, dbflags, hashtab, from); - if (n != OK) { + if (!((n == OK) || + ((zp->z_xferpid == XFER_ISIXFR) && (n == DATAEXISTS)))) { ns_debug(ns_log_update, 3, "process_updates: failed to add databuf (%d)", n); @@ -723,10 +1052,11 @@ class=%s, type=%s, ttl=%d, dp=0x%0x", dbflags |= DB_DELETE; n = db_update(dname, dp, NULL, &savedp, dbflags, hashtab, from); - if (n != OK) + if (!((n == OK) || + ((zp->z_xferpid == XFER_ISIXFR) && (n == NODATA)))) { ns_debug(ns_log_update, 3, "process_updates: delete failed"); - else { + } else { ns_debug(ns_log_update, 3, "process_updates: delete succeeded"); numupdated++; @@ -771,7 +1101,7 @@ class=%s, type=%s, ttl=%d, dp=0x%0x", schedmaint = 1; #ifdef BIND_NOTIFY if (!loading) - sysnotify(zp->z_origin, zp->z_class, T_SOA); + ns_notify(zp->z_origin, zp->z_class, ns_t_soa); #endif } else { if (schedule_soa_update(zp, numupdated)) @@ -784,7 +1114,8 @@ class=%s, type=%s, ttl=%d, dp=0x%0x", static enum req_action req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, - struct qstream *qsp, int dfd, struct sockaddr_in from) + struct qstream *qsp, int dfd, struct sockaddr_in from, + struct tsig_record *in_tsig) { char dnbuf[MAXDNAME], *dname; u_int zocount, prcount, upcount, adcount, class, type, dlen; @@ -801,6 +1132,9 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, int zonelist[MAXDNAME]; int should_use_tcp; u_int32_t old_serial; + int unapproved_ip = 0; + int tsig_len; + DST_KEY *in_key = (in_tsig != NULL) ? in_tsig->key : NULL; nsp[0] = NULL; @@ -854,7 +1188,7 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, * Begin Access Control Point */ - if (!ip_address_allowed(zp->z_update_acl, from.sin_addr)) { + if (!ip_addr_or_key_allowed(zp->z_update_acl, from.sin_addr, in_key)) { ns_notice(ns_log_security, "unapproved update from %s for %s", sin_ntoa(from), *dname ? dname : "."); return (Refuse); @@ -864,8 +1198,6 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, * End Access Control Point */ - /* XXXVIX should check update key when we have one. */ - /* we should be authoritative */ if (!(zp->z_flags & Z_AUTH)) { ns_debug(ns_log_update, 1, @@ -877,11 +1209,12 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, if (zp->z_type == Z_SECONDARY) { /* - * XXX the code below is broken. Until fixed, we just - * refuse. + * XXX The code below is broken. + * Until fixed, we just refuse. */ +#if 1 return (Refuse); - +#else /* We are a slave for this zone, forward it to the master. */ for (cnt = 0; cnt < zp->z_addrcnt; cnt++) *nspp++ = savedata(zp->z_class, T_A, USE_MINIMUM, @@ -892,8 +1225,15 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, * If the request came in over TCP, forward it over TCP */ should_use_tcp = (qsp != NULL); + if (in_tsig != NULL) { + tsig_len = ns_skiprr(eom, eom + TSIG_BUF_SIZE, + ns_s_ar, 1); + eom += tsig_len; + } n = ns_forw(nsp, msg, eom-msg, from, qsp, dfd, &qp, - dname, class, type, NULL, should_use_tcp); + dname, class, type, NULL, should_use_tcp, NULL); + if (in_tsig != NULL) + eom -= tsig_len; free_nsp(nsp); switch (n) { case FW_OK: @@ -905,6 +1245,7 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, hp->rcode = SERVFAIL; return (Finish); } +#endif } /* * We are the primary master server for this zone, @@ -920,11 +1261,10 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, ns_debug(ns_log_update, 3, "req_update: update request for zone %s, class %s", zp->z_origin, p_class(class)); - rrecp_start = res_mkupdrec(S_ZONE, dname, class, type, 0); - rrecp_start->r_zone = zonenum; - rrecp_start->r_prev = NULL; - rrecp_start->r_next = NULL; - rrecp_last = rrecp_start; + rrecp = res_mkupdrec(S_ZONE, dname, class, type, 0); + rrecp->r_zone = zonenum; + + APPEND(curupd, rrecp, r_link); /* * Parse the prerequisite and update sections for format errors. @@ -946,6 +1286,12 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, } GETSHORT(type, cp); GETSHORT(class, cp); + if (class > CLASS_MAX) { + ns_debug(ns_log_update, 1, + "req_update: bad class"); + hp->rcode = FORMERR; + return (Finish); + } GETLONG(ttl, cp); GETSHORT(dlen, cp); n = 0; @@ -972,14 +1318,12 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, dp = savedata(class, type, ttl, rdata, n); dp->d_zone = zonenum; dp->d_cred = DB_C_ZONE; + dp->d_secure = DB_S_INSECURE; /* should be UNCHECKED */ dp->d_clev = nlabels(zp->z_origin); /* XXX - also record in dp->d_ns, which host this came from */ rrecp->r_dp = dp; /* Append the current record to the end of list of records. */ - rrecp_last->r_next = rrecp; - rrecp->r_prev = rrecp_last; - rrecp->r_next = NULL; - rrecp_last = rrecp; + APPEND(curupd, rrecp, r_link); if (cp > eom) { ns_info(ns_log_update, "Malformed response from %s (overrun)", @@ -990,44 +1334,47 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, } /* Now process all parsed records in the prereq and update sections. */ - numupdated = process_updates(rrecp_start, &rcode, from); + numupdated = process_updates(&curupd, &rcode, from); hp->rcode = rcode; if (numupdated <= 0) { - ns_error(ns_log_update, - "error processing update packet id %d from %s", - hp->id, sin_ntoa(from)); + if (rcode != NOERROR) + ns_error(ns_log_update, + "error processing update packet (%s) id %d from %s", + p_rcode(rcode), ntohs(hp->id), sin_ntoa(from)); return (Finish); } + /* + * Stop any outbound zone transfers. + * (Eventlib is synchronous for this.) + */ + ns_stopxfrs(zp); + /* Make a log of the update. */ - (void) printupdatelog(from, rrecp_start, hp, zp, old_serial); + (void) printupdatelog(from, &curupd, hp, zp, old_serial); return (Finish); } -static void -free_rrecp(ns_updrec **startpp, ns_updrec **lastpp, int rcode, - struct sockaddr_in from) -{ +void +free_rrecp(ns_updque *updlist, int rcode, struct sockaddr_in from) { ns_updrec *rrecp, *first_rrecp, *next_rrecp; struct databuf *dp, *tmpdp; char *dname, *msg; - REQUIRE(startpp != NULL && lastpp != NULL); - if (rcode == NOERROR) { - first_rrecp = *startpp; + first_rrecp = HEAD(*updlist); msg = "free_rrecp: update transaction succeeded, cleaning up"; } else { - first_rrecp = *lastpp; + first_rrecp = TAIL(*updlist); msg = "free_rrecp: update transaction aborted, rolling back"; } ns_debug(ns_log_update, 1, msg); for (rrecp = first_rrecp; rrecp != NULL; rrecp = next_rrecp) { if (rcode == NOERROR) - next_rrecp = rrecp->r_next; + next_rrecp = NEXT(rrecp, r_link); else - next_rrecp = rrecp->r_prev; + next_rrecp = PREV(rrecp, r_link); if (rrecp->r_section != S_UPDATE) { if (rrecp->r_dp) db_freedata(rrecp->r_dp); @@ -1096,7 +1443,7 @@ free_rrecp(ns_updrec **startpp, ns_updrec **lastpp, int rcode, /* Add the databuf back. */ tmpdp->d_mark &= ~D_MARK_DELETED; if (db_update(dname, tmpdp, tmpdp, NULL, - 0, hashtab, from) != OK) { + DB_REPLACE, hashtab, from) != OK) { ns_error(ns_log_update, "free_rrecp: failed to add back databuf: dname=%s, type=%s", dname, p_type(tmpdp->d_type)); @@ -1109,18 +1456,19 @@ free_rrecp(ns_updrec **startpp, ns_updrec **lastpp, int rcode, } res_freeupdrec(rrecp); } - *startpp = NULL; - *lastpp = NULL; + INIT_LIST(*updlist); } enum req_action req_update(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, - struct qstream *qsp, int dfd, struct sockaddr_in from) + struct qstream *qsp, int dfd, struct sockaddr_in from, + struct tsig_record *in_tsig) { enum req_action ret; - ret = req_update_private(hp, cp, eom, msg, qsp, dfd, from); - free_rrecp(&rrecp_start, &rrecp_last, hp->rcode, from); + INIT_LIST(curupd); + ret = req_update_private(hp, cp, eom, msg, qsp, dfd, from, in_tsig); + free_rrecp(&curupd, ret == Refuse ? ns_r_refused : hp->rcode, from); if (ret == Finish) { hp->qdcount = hp->ancount = hp->nscount = hp->arcount = 0; memset(msg + HFIXEDSZ, 0, (eom - msg) - HFIXEDSZ); @@ -1139,11 +1487,13 @@ rdata_expand(const u_char *msg, const u_char *eom, const u_char *cp, { const u_char *cpinit = cp; const u_char *cp1init = cp1; - int n, i; + int n, i, n1; switch (type) { case T_A: - if (dlen != INT32SZ) + case T_AAAA: + if ((type == T_A && dlen != INT32SZ) || + (type == T_AAAA && dlen != NS_IN6ADDRSZ)) return (0); /*FALLTHROUGH*/ case T_WKS: @@ -1153,6 +1503,8 @@ rdata_expand(const u_char *msg, const u_char *eom, const u_char *cp, case T_ISDN: case T_NSAP: case T_LOC: + case T_KEY: + case ns_t_cert: if (size < dlen) return (0); memcpy(cp1, cp, dlen); @@ -1249,6 +1601,56 @@ rdata_expand(const u_char *msg, const u_char *eom, const u_char *cp, if (cp != cpinit + dlen) return (0); return (cp1 - cp1init); + case T_SIG: + if (dlen < SIG_HDR_SIZE || size < dlen) + return (0); + memcpy(cp1, cp, SIG_HDR_SIZE); + size -= SIG_HDR_SIZE; + cp += SIG_HDR_SIZE; + cp1 += SIG_HDR_SIZE; + n = dn_expand(msg, eom, cp, (char *)cp1, size); + if (n < 0 || n + SIG_HDR_SIZE > dlen) + return (0); + cp += n; + n1 = dlen - n - SIG_HDR_SIZE; + n = strlen((char *)cp1) + 1; + cp1 += n; + if (size < n1) + return (0); + memcpy(cp1, cp, n1); + cp1 += n1; + return (cp1 - cp1init); + case T_NXT: + n = dn_expand(msg, eom, cp, (char *)cp1, size); + if (n < 0 || (u_int)n >= dlen) + return (0); + size -= n; + cp += n; + n1 = dlen - n; + n = strlen((char *)cp1) + 1; + cp1 += n; + /* + * The first bit of the first octet determines the format + * of the NXT record. A format for types >= 128 has not + * yet been defined, so if bit zero is set, we just copy + * what's there because we don't understand it. + */ + if ((*cp & 0x80) == 0) { + /* + * Bit zero is not set; this is an ordinary NXT + * record. The bitmap must be at least 4 octets + * because the NXT bit should be set. It should be + * less than or equal to 16 octets because this NXT + * format is only defined for types < 128. + */ + if (n1 < 4 || n1 > 16) + return (0); + } + if (n1 > size) + return (0); + memcpy(cp1, cp, n1); + cp1 += n1; + return (cp1 - cp1init); default: ns_debug(ns_log_update, 3, "unknown type %d", type); return (0); @@ -1267,6 +1669,10 @@ rdata_dump(struct databuf *dp, FILE *fp) { u_char *cp, *end; int i, j; const char *proto; + u_char *savecp; + char temp_base64[NS_MD5RSA_MAX_BASE64]; + u_int16_t keyflags; + u_char *sigdata, *certdata; cp = (u_char *)dp->d_data; switch (dp->d_type) { @@ -1339,6 +1745,15 @@ rdata_dump(struct databuf *dp, FILE *fp) { fprintf(fp, "%u", n); fprintf(fp, " %s.", cp); break; + case T_SRV: + GETSHORT(n, cp); /* priority */ + fprintf(fp, "%u ", n); + GETSHORT(n, cp); /* weight */ + fprintf(fp, "%u ", n); + GETSHORT(n, cp); /* port */ + fprintf(fp, "%u ", n); + fprintf(fp, " %s.", cp); + break; case T_PX: GETSHORT(n, cp); fprintf(fp, "%u", n); @@ -1353,12 +1768,16 @@ rdata_dump(struct databuf *dp, FILE *fp) { while (cp < end) { if ((n = *cp++) != '\0') { for (j = n; j > 0 && cp < end; j--) - if (*cp == '\n') { - (void) putc('\\', fp); - (void) putc(*cp++, fp); + if ((*cp < ' ') || (*cp > '~')) { + fprintf(fp, "\\%03.3d", *cp++); + } else if (*cp == '\\' || *cp =='"') { + putc('\\', fp); + putc(*cp++, fp); } else (void) putc(*cp++, fp); } + if (cp != end) + fputs("\" \"", fp); } /* XXXVIX need to keep the segmentation (see 4.9.5). */ (void) fputs("\"", fp); @@ -1393,6 +1812,91 @@ rdata_dump(struct databuf *dp, FILE *fp) { cp += strlen((char *)cp) + 1; fprintf(fp, " %s.", cp); break; + case T_KEY: + savecp = cp; /* save the beginning */ + /*>>> Flags (unsigned_16) */ + NS_GET16(keyflags,cp); + fprintf(fp, "0x%04x ", keyflags); + /*>>> Protocol (8-bit decimal) */ + fprintf(fp, "%3u ", *cp++); + /*>>> Algorithm id (8-bit decimal) */ + fprintf(fp, "%3u ", *cp++); + + /*>>> Public-Key Data (multidigit BASE64) */ + /* containing ExponentLen, Exponent, and Modulus */ + i = b64_ntop(cp, dp->d_size - (cp - savecp), + temp_base64, sizeof temp_base64); + if (i < 0) + fprintf(fp, "; BAD BASE64"); + else + fprintf(fp, "%s", temp_base64); + break; + case T_SIG: + sigdata = cp; + /* RRtype (char *) */ + NS_GET16(n,cp); + fprintf(fp, "%s ", p_type(n)); + /* Algorithm id (8-bit decimal) */ + fprintf(fp, "%d ", *cp++); + /* Labels (8-bit decimal) (not saved in file) */ + /* XXXX FIXME -- check value and print err if bad */ + cp++; + /* OTTL (u_long) */ + NS_GET32(n, cp); + fprintf(fp, "%u ", n); + /* Texp (u_long) */ + NS_GET32(n, cp); + fprintf(fp, "%s ", p_secstodate (n)); + /* Tsig (u_long) */ + NS_GET32(n, cp); + fprintf(fp, "%s ", p_secstodate (n)); + /* Kfootprint (unsigned_16) */ + NS_GET16(n, cp); + fprintf(fp, "%u ", n); + /* Signer's Name (char *) */ + fprintf(fp, "%s ", cp); + cp += strlen((char *)cp) + 1; + /* Signature (base64 of any length) */ + i = b64_ntop(cp, dp->d_size - (cp - sigdata), + temp_base64, sizeof temp_base64); + if (i < 0) + fprintf(fp, "; BAD BASE64"); + else + fprintf(fp, "%s", temp_base64); + break; + + case T_NXT: + fprintf(fp, "%s.", cp); + n = strlen ((char *)cp) + 1; + cp += n; + i = 8 * (dp->d_size - n); /* How many bits? */ + for (n = 0; n < (u_int32_t)i; n++) { + if (NS_NXT_BIT_ISSET(n, cp)) + fprintf(fp," %s",__p_type(n)); + } + break; + case ns_t_cert: + certdata = cp; + NS_GET16(n,cp); + fprintf(fp, "%d ", n); /* cert type */ + + NS_GET16(n,cp); + fprintf(fp, "%d %d ", n, *cp++); /* tag & alg */ + + /* Certificate (base64 of any length) */ + i = b64_ntop(cp, dp->d_size - (cp - certdata), + temp_base64, sizeof(temp_base64)); + if (i < 0) + fprintf(fp, "; BAD BASE64"); + else + fprintf(fp, "%s", temp_base64); + break; + case ns_t_aaaa: { + char t[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"]; + + (void) fputs(inet_ntop(AF_INET6, dp->d_data, t, sizeof t), fp); + break; + } default: fprintf(fp, "\t;?d_type=%d?", dp->d_type); } @@ -1404,7 +1908,7 @@ rdata_dump(struct databuf *dp, FILE *fp) { * authoritative zone numbers will be stored in "zonelist", ordered * deepest match first. */ -static int +int findzone(const char *dname, int class, int depth, int *zonelist, int maxzones){ char *tmpdname; char tmpdnamebuf[MAXDNAME]; @@ -1428,7 +1932,7 @@ zonelist=0x%x, maxzones=%d)", tmpdname = tmpdnamebuf; /* * The code to handle trailing dots and escapes is adapted - * from samedomain(). + * from ns_samedomain(). */ tmpdnamelen = strlen(tmpdname); /* @@ -1538,7 +2042,7 @@ zonelist=0x%x, maxzones=%d)", * returns -1 on error, 0 on success, 1 if dump reload needed */ int -merge_logs(struct zoneinfo *zp) { +merge_logs(struct zoneinfo *zp, char *logname) { char origin[MAXDNAME], data[MAXDATA], dnbuf[MAXDNAME], sclass[3]; char buf[BUFSIZ], buf2[100]; FILE *fp; @@ -1558,6 +2062,7 @@ merge_logs(struct zoneinfo *zp) { u_char *serialp; struct sockaddr_in empty_from; int datasize; + unsigned long l; empty_from.sin_family = AF_INET; empty_from.sin_addr.s_addr = htonl(INADDR_ANY); @@ -1568,64 +2073,67 @@ merge_logs(struct zoneinfo *zp) { * getword() is used here just to be consistent with db_load() */ + ns_debug(ns_log_update, 3, "merge_logs(%s)", logname); + /* If there is no log file, just return. */ - if (stat(zp->z_updatelog, &st) < 0) { + if (stat(logname, &st) < 0) { if (errno != ENOENT) ns_error(ns_log_update, "unexpected stat(%s) failure: %s", - zp->z_updatelog, strerror(errno)); + logname, strerror(errno)); return (-1); } - fp = fopen(zp->z_updatelog, "r"); + fp = fopen(logname, "r"); if (fp == NULL) { ns_error(ns_log_update, "fopen(%s) failed: %s", - zp->z_updatelog, strerror(errno)); + logname, strerror(errno)); return (-1); } /* * See if we really have a log file -- it might be a zone dump - * that was in the process of being renamed, or it might + * that was in the process of being movefiled, or it might * be garbage! */ if (fgets(buf, sizeof(buf), fp)==NULL) { ns_error(ns_log_update, "fgets() from %s failed: %s", - zp->z_updatelog, strerror(errno)); + logname, strerror(errno)); fclose(fp); return (-1); } if (strcmp(buf, DumpSignature) == 0) { - /* It's a dump; finish rename that was interrupted. */ + /* It's a dump; finish movefile that was interrupted. */ ns_info(ns_log_update, - "completing interrupted dump rename for %s", + "completing interrupted dump movefile for %s", zp->z_source); - if (rename(zp->z_updatelog, zp->z_source) < 0) { - ns_error(ns_log_update, "rename(%s,%s) failed: %s", - zp->z_updatelog, zp->z_source, + fclose(fp); + if (movefile(logname, zp->z_source) < 0) { + ns_error(ns_log_update, "movefile(%s,%s) failed: %s :1", + logname, zp->z_source, strerror(errno)); + fclose(fp); return (-1); } - fclose(fp); /* Finally, tell caller to reload zone. */ return (1); } if (strcmp(buf, LogSignature) != 0) { /* Not a dump and not a log; complain and then bail out. */ ns_error(ns_log_update, "invalid log file %s", - zp->z_updatelog); + logname); fclose(fp); return (-1); } ns_debug(ns_log_update, 3, "merging logs for %s from %s", - zp->z_origin, zp->z_updatelog); + zp->z_origin, logname); lineno = 1; - rrecp_start = NULL; - rrecp_last = NULL; + INIT_LIST(curupd); for (;;) { + err = 0; if (!getword(buf, sizeof buf, fp, 0)) { - if (lineno == (nonempty_lineno + 1)) { + if (lineno == (nonempty_lineno + 1) && !(feof(fp))) { /* * End of a nonempty line inside an update * packet or not inside an update packet. @@ -1644,7 +2152,8 @@ merge_logs(struct zoneinfo *zp) { nonempty_lineno = lineno; } - if (!strcasecmp(buf, "[DYNAMIC_UPDATE]")) { + if (!strcasecmp(buf, "[DYNAMIC_UPDATE]") || + !strcasecmp(buf, "[IXFR_UPDATE]")) { err = 0; rcode = NOERROR; cp = fgets(buf, sizeof buf, fp); @@ -1665,13 +2174,13 @@ merge_logs(struct zoneinfo *zp) { &old_serial, &new_serial)) { ns_error(ns_log_update, "incr_serial problem with %s", - zp->z_updatelog); + logname); } else { serial = get_serial(zp); if (serial != old_serial) { ns_error(ns_log_update, "serial number mismatch (log=%u, zone=%u) in %s", old_serial, - serial, zp->z_updatelog); + serial, logname); } else { set_serial(zp, new_serial); /* @@ -1682,26 +2191,30 @@ merge_logs(struct zoneinfo *zp) { sched_zone_maint(zp); ns_info(ns_log_update, "set serial to %u (log file %s)", - new_serial, zp->z_updatelog); + new_serial, logname); } } prev_pktdone = 1; cont = 1; + } else if (!strcasecmp(buf, "[END_DELTA]")) { + prev_pktdone = 1; + cont = 1; } if (prev_pktdone) { - if (rrecp_start) { - n = process_updates(rrecp_start, &rcode, + if (!EMPTY(curupd)) { + n = process_updates(&curupd, &rcode, empty_from); if (n > 0) ns_info(ns_log_update, "successfully merged update id %d from log file %s", - id, zp->z_updatelog); - else + id, logname); + else { ns_error(ns_log_update, "error merging update id %d from log file %s", - id, zp->z_updatelog); - free_rrecp(&rrecp_start, &rrecp_last, rcode, - empty_from); + id, logname); + return(-1); + } + free_rrecp(&curupd, rcode, empty_from); } prev_pktdone = 0; if (feof(fp)) @@ -1738,7 +2251,7 @@ merge_logs(struct zoneinfo *zp) { *buf = '\0'; n = sscanf(cp, "origin %s class %s serial %ul", origin, sclass, &serial); - if (n != 3 || strcasecmp(origin, zp->z_origin)) + if (n != 3 || ns_samename(origin, zp->z_origin) != 1) err++; if (cp) lineno++; @@ -1746,7 +2259,7 @@ merge_logs(struct zoneinfo *zp) { ns_error(ns_log_update, "serial number mismatch in update id %d (log=%u, zone=%u) in %s", id, serial, zp->z_serial, - zp->z_updatelog); + logname); inside_next = 0; err++; } @@ -1809,11 +2322,11 @@ merge_logs(struct zoneinfo *zp) { data[0] = '\0'; (void) getword(buf, sizeof buf, fp, 1); if (isdigit(buf[0])) { /* ttl */ - ttl = strtoul(buf, 0, 10); - if (errno == ERANGE && ttl == ULONG_MAX) { + if (ns_parse_ttl(buf, &l) < 0) { err++; break; } + ttl = l; (void) getword(buf, sizeof buf, fp, 1); } @@ -1888,45 +2401,56 @@ merge_logs(struct zoneinfo *zp) { case T_MINFO: case T_RP: (void) strcpy(data, buf); - cp = data + strlen(data) + 1; + cp = data + strlen(data) -1; + *(cp++) = 0; /* ditch dot */ if (!getword((char *)cp, sizeof data - (cp - data), fp, 1)) { err++; break; } - cp += strlen((char *)cp) + 1; + cp += strlen((char *)cp) -1; + *(cp++) = 0; /* ditch dot */ if (type != T_SOA) { n = cp - data; break; } + else + n = cp - data; if (class != zp->z_class || - strcasecmp(dname, zp->z_origin)) { + ns_samename(dname, zp->z_origin) != 1) { err++; break; } - c = getnonblank(fp, zp->z_updatelog); + c = getnonblank(fp, logname); if (c == '(') { multiline = 1; } else { multiline = 0; ungetc(c, fp); } - for (i = 0; i < 5; i++) { - n = getnum(fp, zp->z_updatelog, - GETNUM_SERIAL); - if (getnum_error) { + n = getnum(fp, logname, GETNUM_SERIAL); + if (getnum_error) { + err++; + break; + } + PUTLONG(n, cp); + for (i = 0; i < 4; i++) { + if (getttl(fp, logname, lineno, + &n, &multiline) <= 0) + { err++; break; } PUTLONG(n, cp); } if (multiline && - getnonblank(fp, zp->z_updatelog) - != ')') { + (getnonblank(fp, logname) + != ')')) { err++; break; } + n = cp - data; endline(fp); break; case T_WKS: @@ -1938,11 +2462,11 @@ merge_logs(struct zoneinfo *zp) { cp = data; PUTLONG(n, cp); *cp = (char)getprotocol(fp, - zp->z_updatelog + logname ); n = INT32SZ + sizeof(char); n = getservices((int)n, data, - fp, zp->z_updatelog); + fp, logname); break; case T_NS: case T_CNAME: @@ -2012,22 +2536,24 @@ merge_logs(struct zoneinfo *zp) { cp = data; datasize = sizeof data; cp1 = buf; - while (i > 255) { - if (datasize < 256) { + while (i > MAXCHARSTRING) { + if (datasize <= MAXCHARSTRING){ ns_error(ns_log_update, "record too big"); + fclose(fp); return (-1); } - datasize -= 255; - *cp++ = 255; - memcpy(cp, cp1, 255); - cp += 255; - cp1 += 255; - i -= 255; + datasize -= MAXCHARSTRING; + *cp++ = (char)MAXCHARSTRING; + memcpy(cp, cp1, MAXCHARSTRING); + cp += MAXCHARSTRING; + cp1 += MAXCHARSTRING; + i -= MAXCHARSTRING; } if (datasize < i + 1) { ns_error(ns_log_update, "record too big"); + fclose(fp); return (-1); } *cp++ = i; @@ -2064,6 +2590,29 @@ merge_logs(struct zoneinfo *zp) { } endline(fp); break; + case ns_t_sig: + case ns_t_key: + case ns_t_nxt: + case ns_t_cert: + { + char * errmsg = NULL; + int s; + + s = parse_sec_rdata(buf, sizeof(buf), + 1, + (u_char *)data, + sizeof(data), + fp, zp, dnbuf, + ttl, type, + domain_ctx, + primary_trans, + &errmsg); + if (s < 0) { + err++; + break; + } + break; + } default: err++; } @@ -2086,11 +2635,22 @@ merge_logs(struct zoneinfo *zp) { } } else { /* section == S_UPDATE */ if (opcode == DELETE) { + ttl = 0; if (n == 0) { class = C_ANY; if (type == -1) type = T_ANY; - } else { + /* WTF? C_NONE or C_ANY _must_ be the case if + * we really are to delete this. If + * C_NONE is used, according to process_updates(), + * the class is gotten from the zone's class. + * This still isn't perfect, but it will at least + * work. + * + * Question: What is so special about the class + * of the update while we are deleting?? + */ + } else /* if (zp->z_xferpid != XFER_ISIXFR) */ { class = C_NONE; } } @@ -2108,8 +2668,7 @@ merge_logs(struct zoneinfo *zp) { ns_debug(ns_log_update, 1, "merge of update id %d failed due to error at line %d", id, lineno); - free_rrecp(&rrecp_start, &rrecp_last, rcode, - empty_from); + free_rrecp(&curupd, FORMERR, empty_from); continue; } rrecp = res_mkupdrec(section, dname, class, type, ttl); @@ -2118,21 +2677,12 @@ merge_logs(struct zoneinfo *zp) { dp->d_zone = zonenum; dp->d_cred = DB_C_ZONE; dp->d_clev = nlabels(zp->z_origin); + dp->d_secure = DB_S_INSECURE; /* should be UNCHECKED */ rrecp->r_dp = dp; } else { rrecp->r_zone = zonenum; } - if (rrecp_start == NULL) { - rrecp_start = rrecp; - rrecp_last = rrecp; - rrecp->r_prev = NULL; - rrecp->r_next = NULL; - } else { - rrecp_last->r_next = rrecp; - rrecp->r_prev = rrecp_last; - rrecp->r_next = NULL; - rrecp_last = rrecp; - } + APPEND(curupd, rrecp, r_link); } /* for (;;) */ fclose(fp); @@ -2144,9 +2694,7 @@ merge_logs(struct zoneinfo *zp) { * Create a disk database to back up zones */ int -zonedump(zp) - struct zoneinfo *zp; -{ +zonedump(struct zoneinfo *zp, int mode) { FILE *fp; const char *fname; struct hashbuf *htp; @@ -2213,11 +2761,13 @@ zonedump(zp) if (fflush(fp) == EOF) { ns_error(ns_log_update, "fflush() of %s failed: %s", tmp_name, strerror(errno)); + fclose(fp); return (-1); } if (fsync(fileno(fp)) < 0) { ns_error(ns_log_update, "fsync() of %s failed: %s", tmp_name, strerror(errno)); + fclose(fp); return (-1); } if (fclose(fp) == EOF) { @@ -2242,16 +2792,47 @@ zonedump(zp) tmp_name, st.st_mode, strerror(errno)); } - if (rename(tmp_name, zp->z_updatelog) < 0) { - ns_error(ns_log_update, "rename(%s,%s) failed: %s", - tmp_name, zp->z_updatelog, strerror(errno)); - return (-1); - } - if (rename(zp->z_updatelog, zp->z_source) < 0) { - ns_error(ns_log_update, "rename(%s,%s) failed: %s", - zp->z_updatelog, zp->z_source, - strerror(errno)); - return (-1); + + if (mode == ISIXFR) { + if (movefile(tmp_name, zp->z_ixfr_tmp) < 0) { + ns_error(ns_log_update, "movefile(%s,%s) failed: %s :2", + tmp_name, zp->z_ixfr_tmp, strerror(errno)); + return (-1); + } + if (chmod(zp->z_source, 0644) < 0) + ns_error(ns_log_update, + "chmod(%s,%o) failed, pressing on: %s", + zp->z_source, st.st_mode, + strerror(errno)); + if (movefile(zp->z_ixfr_tmp, zp->z_source) < 0) { + ns_error(ns_log_update, "movefile(%s,%s) failed: %s :3", + zp->z_ixfr_tmp, zp->z_source, + strerror(errno)); + return (-1); + } + st.st_mode &= ~WRITEABLE_MASK; + if (chmod(zp->z_source, st.st_mode) < 0) + ns_error(ns_log_update, + "chmod(%s,%o) failed, pressing on: %s", + zp->z_source, st.st_mode, + strerror(errno)); + } else if (mode == ISNOTIXFR) { + if (movefile(tmp_name, zp->z_updatelog) < 0) { + ns_error(ns_log_update, "movefile(%s,%s) failed: %s :4", + tmp_name, zp->z_updatelog, strerror(errno)); + return (-1); + } + if (movefile(zp->z_updatelog, zp->z_source) < 0) { + ns_error(ns_log_update, "movefile(%s,%s) failed: %s:5", + zp->z_updatelog, zp->z_source, + strerror(errno)); + return (-1); + } + } else { + if (movefile(tmp_name, zp->z_source) < 0) { + ns_error(ns_log_update, "movefile(%s,%s) failed: % s :6", tmp_name, zp->z_source, strerror(errno)); + return (-1); + } } } else ns_debug(ns_log_update, 1, "zonedump: no zone to dump"); @@ -2332,10 +2913,10 @@ set_serial(struct zoneinfo *zp, u_int32_t serial) { zp->z_updatecnt = 0; #ifdef BIND_NOTIFY if (!loading) - sysnotify(zp->z_origin, zp->z_class, T_SOA); + ns_notify(zp->z_origin, zp->z_class, ns_t_soa); #endif /* - * Note: caller is responsible for scheduling a dump + * Note: caller is responsible for scheduling a dump. */ } @@ -2346,8 +2927,10 @@ set_serial(struct zoneinfo *zp, u_int32_t serial) { int incr_serial(struct zoneinfo *zp) { u_int32_t serial, old_serial; - FILE *fp; + FILE *fp, *ifp; time_t t; + struct databuf *dp, *olddp; + unsigned char *cp; old_serial = get_serial(zp); serial = old_serial + 1; @@ -2364,6 +2947,32 @@ incr_serial(struct zoneinfo *zp) { old_serial, serial, checked_ctime(&t)); if (close_transaction_log(zp, fp)<0) return (-1); + ifp = open_ixfr_log(zp); + if (ifp == NULL) + return (-1); + dp = findzonesoa(zp); + if (dp) { + olddp = memget(DATASIZE(dp->d_size)); + if (olddp != NULL) { + memcpy(olddp, dp, DATASIZE(dp->d_size)); + cp = findsoaserial(olddp->d_data); + PUTLONG(old_serial, cp); + fprintf(ifp, "update: {delete} %s. %u %s %s ", + zp->z_origin, dp->d_ttl, + p_class(dp->d_class), p_type(dp->d_type)); + (void) rdata_dump(olddp, ifp); + fprintf(ifp, "\n"); + memput(olddp, DATASIZE(dp->d_size)); + } + fprintf(ifp, "update: {add} %s. %u %s %s ", + zp->z_origin, dp->d_ttl, + p_class(dp->d_class), p_type(dp->d_type)); + (void) rdata_dump(dp, ifp); + fprintf(ifp, "\n"); + } + fprintf(ifp, "[END_DELTA]\n"); + if (close_ixfr_log(zp, ifp)<0) + return (-1); /* * This shouldn't happen, but we check to be sure. @@ -2390,6 +2999,6 @@ dynamic_about_to_exit(void) { if ((zp->z_flags & Z_DYNAMIC) && ((zp->z_flags & Z_NEED_SOAUPDATE) || (zp->z_flags & Z_NEED_DUMP))) - (void)zonedump(zp); + (void)zonedump(zp, ISNOTIXFR); } } diff --git a/contrib/bind/bin/named/ns_xfr.c b/contrib/bind/bin/named/ns_xfr.c index 52d3464..e25a536 100644 --- a/contrib/bind/bin/named/ns_xfr.c +++ b/contrib/bind/bin/named/ns_xfr.c @@ -1,9 +1,9 @@ #if !defined(lint) && !defined(SABER) -static char rcsid[] = "$Id: ns_xfr.c,v 8.25 1998/03/25 18:47:34 halley Exp $"; +static const char rcsid[] = "$Id: ns_xfr.c,v 8.55 1999/10/13 16:39:13 vixie Exp $"; #endif /* not lint */ /* - * Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -24,6 +24,7 @@ static char rcsid[] = "$Id: ns_xfr.c,v 8.25 1998/03/25 18:47:34 halley Exp $"; #include <sys/param.h> #include <sys/file.h> #include <sys/socket.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -32,26 +33,26 @@ static char rcsid[] = "$Id: ns_xfr.c,v 8.25 1998/03/25 18:47:34 halley Exp $"; #include <errno.h> #include <fcntl.h> #include <resolv.h> +#include <res_update.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <syslog.h> #include <time.h> +#include <unistd.h> #include <isc/eventlib.h> #include <isc/logging.h> #include <isc/memcluster.h> +#include <isc/dst.h> + #include "port_after.h" #include "named.h" static struct qs_x_lev *sx_freelev(struct qs_x_lev *lev); -static void sx_newmsg(struct qstream *qsp), - sx_sendlev(struct qstream *qsp), - sx_sendsoa(struct qstream *qsp); - static int sx_flush(struct qstream *qsp), sx_addrr(struct qstream *qsp, const char *dname, @@ -59,20 +60,18 @@ static int sx_flush(struct qstream *qsp), sx_nsrrs(struct qstream *qsp), sx_allrrs(struct qstream *qsp), sx_pushlev(struct qstream *qsp, struct namebuf *np); +static struct databuf *db_next(struct databuf *dp); /* * void - * ns_xfr(qsp, znp, zone, class, type, opcode, id) + * ns_xfr(qsp, znp, zone, class, type, opcode, id, serial_ixfr, in_tsig) * Initiate a concurrent (event driven) outgoing zone transfer. */ void ns_xfr(struct qstream *qsp, struct namebuf *znp, int zone, int class, int type, - int opcode, int id) + int opcode, int id, u_int32_t serial_ixfr, struct tsig_record *in_tsig) { - FILE *rfp; - int fdstat; - pid_t pid; server_info si; #ifdef SO_SNDBUF static const int sndbuf = XFER_BUFSIZE * 2; @@ -80,9 +79,26 @@ ns_xfr(struct qstream *qsp, struct namebuf *znp, #ifdef SO_SNDLOWAT static const int sndlowat = XFER_BUFSIZE; #endif + ns_updrec *changes; - ns_info(ns_log_xfer_out, "zone transfer of \"%s\" (%s) to %s", - zones[zone].z_origin, p_class(class), sin_ntoa(qsp->s_from)); + switch (type) { + case ns_t_axfr: /*FALLTHROUGH*/ + case ns_t_ixfr: +#ifdef BIND_ZXFR + case ns_t_zxfr: +#endif + ns_info(ns_log_xfer_out, + "zone transfer (%s) of \"%s\" (%s) to %s", + p_type(type), zones[zone].z_origin, p_class(class), + sin_ntoa(qsp->s_from)); + break; + default: + ns_warning(ns_log_xfer_out, + "unsupported XFR (type %s) of \"%s\" (%s) to %s", + p_type(type), zones[zone].z_origin, p_class(class), + sin_ntoa(qsp->s_from)); + goto abort; + } #ifdef SO_SNDBUF /* @@ -104,9 +120,10 @@ ns_xfr(struct qstream *qsp, struct namebuf *znp, if (sq_openw(qsp, 64*1024) == -1) goto abort; memset(&qsp->xfr, 0, sizeof qsp->xfr); - qsp->xfr.top = znp; + qsp->xfr.top.axfr = znp; qsp->xfr.zone = zone; qsp->xfr.class = class; + qsp->xfr.type = type; qsp->xfr.id = id; qsp->xfr.opcode = opcode; qsp->xfr.msg = memget(XFER_BUFSIZE); @@ -118,19 +135,76 @@ ns_xfr(struct qstream *qsp, struct namebuf *znp, zones[zone].z_numxfrs++; qsp->flags |= STREAM_AXFR; +#ifdef BIND_ZXFR + if (type == ns_t_zxfr) { + enum { rd = 0, wr = 1 }; + int z[2]; + pid_t p; + + if (pipe(z) < 0) { + ns_error(ns_log_xfer_out, "pipe: %s", strerror(errno)); + goto abort; + } + p = vfork(); + if (p < 0) { + ns_error(ns_log_xfer_out, "vfork: %s", strerror(errno)); + goto abort; + } + if (p == 0) { + /* Child. */ + dup2(z[rd], STDIN_FILENO); + dup2(qsp->s_rfd, STDOUT_FILENO); + execlp("gzip", "gzip", NULL); + ns_error(ns_log_xfer_out, "execlp: %s", strerror(errno)); + _exit(1); + } + ns_info(ns_log_xfer_out, "zxfr gzip pid %lu", p); + /* Parent. */ + dup2(z[wr], qsp->s_rfd); + close(z[wr]); + close(z[rd]); + + /* When a ZXFR completes, there can be no more requests. */ + qsp->flags |= STREAM_DONE_CLOSE; + } +#endif + si = find_server(qsp->s_from.sin_addr); if (si != NULL && si->transfer_format != axfr_use_default) qsp->xfr.transfer_format = si->transfer_format; else qsp->xfr.transfer_format = server_options->transfer_format; + if (in_tsig == NULL) + qsp->xfr.tsig_state = NULL; + else { + qsp->xfr.tsig_state = memget(sizeof(ns_tcp_tsig_state)); + ns_sign_tcp_init(in_tsig->key, in_tsig->sig, in_tsig->siglen, + qsp->xfr.tsig_state); + qsp->xfr.tsig_skip = 0; + } - if (sx_pushlev(qsp, znp) < 0) { - abort: - (void) shutdown(qsp->s_rfd, 2); - sq_remove(qsp); - return; + if (type == ns_t_ixfr) { + changes = ixfr_get_change_list(&zones[zone], serial_ixfr, + zones[zone].z_serial); + if (changes != NULL) + { + qsp->xfr.serial = serial_ixfr; + qsp->xfr.top.ixfr = changes; + } + else + type = ns_t_axfr; } - (void) sq_writeh(qsp, sx_sendsoa); + if (sx_pushlev(qsp, znp) < 0) { + abort: + (void) shutdown(qsp->s_rfd, 2); + sq_remove(qsp); + return; + } + if (type != ns_t_ixfr) + (void) sq_writeh(qsp, sx_sendsoa); + else + (void) sq_writeh(qsp, sx_send_ixfr); + } /* @@ -176,7 +250,7 @@ ns_freexfr(struct qstream *qsp) { * init the header of a message, reset the compression pointers, and * reset the write pointer to the first byte following the header. */ -static void +void sx_newmsg(struct qstream *qsp) { HEADER *hp = (HEADER *)qsp->xfr.msg; @@ -190,6 +264,11 @@ sx_newmsg(struct qstream *qsp) { qsp->xfr.ptrs[1] = NULL; qsp->xfr.cp = qsp->xfr.msg + HFIXEDSZ; + + qsp->xfr.eom = qsp->xfr.msg + XFER_BUFSIZE; + + if (qsp->xfr.tsig_state != NULL) + qsp->xfr.eom -= TSIG_BUF_SIZE; } /* @@ -205,12 +284,30 @@ sx_flush(struct qstream *qsp) { #ifdef DEBUG if (debug >= 10) - fp_nquery(qsp->xfr.msg, qsp->xfr.cp - qsp->xfr.msg, - log_get_stream(packet_channel)); + res_pquery(&res, qsp->xfr.msg, qsp->xfr.cp - qsp->xfr.msg, + log_get_stream(packet_channel)); #endif + if (qsp->xfr.tsig_state != NULL && qsp->xfr.tsig_skip == 0) { + int msglen = qsp->xfr.cp - qsp->xfr.msg; + + ns_sign_tcp(qsp->xfr.msg, &msglen, qsp->xfr.eom - qsp->xfr.msg, + NOERROR, qsp->xfr.tsig_state, + qsp->xfr.state == s_x_done); + + if (qsp->xfr.state == s_x_done) { + memput(qsp->xfr.tsig_state, sizeof(ns_tcp_tsig_state)); + qsp->xfr.tsig_state = NULL; + } + qsp->xfr.cp = qsp->xfr.msg + msglen; + + } ret = sq_write(qsp, qsp->xfr.msg, qsp->xfr.cp - qsp->xfr.msg); - if (ret >= 0) + if (ret >= 0) { qsp->xfr.cp = NULL; + qsp->xfr.tsig_skip = 0; + } + else + qsp->xfr.tsig_skip = 1; return (ret); } @@ -229,7 +326,7 @@ static int sx_addrr(struct qstream *qsp, const char *dname, struct databuf *dp) { HEADER *hp = (HEADER *)qsp->xfr.msg; u_char **edp = qsp->xfr.ptrs + sizeof qsp->xfr.ptrs / sizeof(u_char*); - int n; + int n, type; if (qsp->xfr.cp != NULL) { if (qsp->xfr.transfer_format == axfr_one_answer && @@ -238,15 +335,34 @@ sx_addrr(struct qstream *qsp, const char *dname, struct databuf *dp) { } if (qsp->xfr.cp == NULL) sx_newmsg(qsp); + + /* + * Add question to first answer. + */ + if (qsp->xfr.state == s_x_firstsoa && dp->d_type == T_SOA ) { + if ((qsp->xfr.type == ns_t_ixfr) || (qsp->flags & STREAM_AXFRIXFR)) { + n = dn_comp(dname, qsp->xfr.cp, qsp->xfr.eom - qsp->xfr.cp, + qsp->xfr.ptrs, edp); + if (n > 0 && (qsp->xfr.cp + n + INT16SZ * 2) <= qsp->xfr.eom) { + qsp->xfr.cp += n; + type = (qsp->xfr.type == ns_t_zxfr) ? + ns_t_axfr : qsp->xfr.type; + PUTSHORT((u_int16_t) type, qsp->xfr.cp); + PUTSHORT((u_int16_t) qsp->xfr.class, qsp->xfr.cp); + hp->qdcount = htons(ntohs(hp->qdcount) + 1); + } + } + } + n = make_rr(dname, dp, qsp->xfr.cp, qsp->xfr.eom - qsp->xfr.cp, - 0, qsp->xfr.ptrs, edp); + 0, qsp->xfr.ptrs, edp, 0); if (n < 0) { if (sx_flush(qsp) < 0) return (-1); if (qsp->xfr.cp == NULL) sx_newmsg(qsp); n = make_rr(dname, dp, qsp->xfr.cp, qsp->xfr.eom - qsp->xfr.cp, - 0, qsp->xfr.ptrs, edp); + 0, qsp->xfr.ptrs, edp, 0); INSIST(n >= 0); } hp->ancount = htons(ntohs(hp->ancount) + 1); @@ -264,18 +380,37 @@ sx_addrr(struct qstream *qsp, const char *dname, struct databuf *dp) { * side effects: * if progress was made, header and pointers will be advanced. */ -static int +int sx_soarr(struct qstream *qsp) { struct databuf *dp; + int added_soa = 0; - foreach_rr(dp, qsp->xfr.top, T_SOA, qsp->xfr.class, qsp->xfr.zone) { + foreach_rr(dp, qsp->xfr.top.axfr, T_SOA, qsp->xfr.class, + qsp->xfr.zone) { if (sx_addrr(qsp, zones[qsp->xfr.zone].z_origin, dp) < 0) { /* RR wouldn't fit. Bail out. */ return (-1); } - return (0); + added_soa = 1; + break; } - ns_panic(ns_log_xfer_out, 1, "no SOA at zone top"); + if (added_soa == 0) + ns_panic(ns_log_xfer_out, 1, "no SOA at zone top"); + if (qsp->xfr.state == s_x_firstsoa) { + foreach_rr(dp, qsp->xfr.top.axfr, T_SIG, qsp->xfr.class, + qsp->xfr.zone) + { + if (SIG_COVERS(dp) != T_SOA) + continue; + if (sx_addrr(qsp, zones[qsp->xfr.zone].z_origin, dp) < + 0) + { + /* RR wouldn't fit. Bail out. */ + return (-1); + } + } + } + return (0); } /* @@ -283,6 +418,9 @@ sx_soarr(struct qstream *qsp) { * sx_nsrrs(qsp) * add the NS RR's at the current level's current np, * to the assembly message + * This function also adds the SIG(NS), KEY, SIG(KEY), NXT, SIG(NXT) + * the reason for this these records are part of the delegation. + * * return: * >1 = number of NS RRs added, note that there may be more * 0 = success, there are no more NS RRs at this level @@ -303,11 +441,11 @@ sx_nsrrs(struct qstream *qsp) { int rrcount, class; class = qsp->xfr.class; - top = qsp->xfr.top; + top = qsp->xfr.top.axfr; rrcount = 0; for ((void)NULL; (dp = qsp->xfr.lev->dp) != NULL; - qsp->xfr.lev->dp = dp->d_next) { + qsp->xfr.lev->dp = db_next(dp)) { /* XYZZY foreach_rr? */ if (dp->d_class != class && class != C_ANY) continue; @@ -323,14 +461,21 @@ sx_nsrrs(struct qstream *qsp) { */ if (dp->d_zone == DB_Z_CACHE) continue; - if (dp->d_type != T_NS) + + if (dp->d_type != T_NS && dp->d_type != T_KEY && + dp->d_type != T_NXT && dp->d_type != T_SIG) + continue; + if (dp->d_type == T_SIG && ((SIG_COVERS(dp) != T_NS) && + (SIG_COVERS(dp) != T_KEY) && (SIG_COVERS(dp) != T_NXT))) continue; if (!(qsp->xfr.lev->flags & SXL_GLUING)) { if (sx_addrr(qsp, qsp->xfr.lev->dname, dp) < 0) { /* RR wouldn't fit. Bail out. */ return (-1); } - rrcount++; + if (dp->d_type != T_NS) /* no glue processing */ + continue; + rrcount++; /* only count NS records */ } /* @@ -373,6 +518,16 @@ sx_nsrrs(struct qstream *qsp) { */ return (-1); } + /* for IPv6 glue AAAA record transfer */ + /* patched by yasuhiro@nic.ad.jp, 1999/5/23 */ + foreach_rr(gdp, gnp, T_AAAA, class, DB_Z_CACHE) + if (sx_addrr(qsp, fname, gdp) < 0) { + /* + * Rats. We already sent the NS RR, too. + * Note that SXL_GLUING is being left on. + */ + return (-1); + } qsp->xfr.lev->flags &= ~SXL_GLUING; } return (rrcount); @@ -383,6 +538,8 @@ sx_nsrrs(struct qstream *qsp) { * sx_allrrs(qsp) * add the non-(SOA,NS) RR's at the current level's current np, * to the assembly message + * do not add the DNSSEC types KEY and NXT as the delegation check + * wrote these types out. * return: * >0 = number of RR's added, note that there may be more * 0 = success, there are no more RRs at this level @@ -396,20 +553,18 @@ sx_nsrrs(struct qstream *qsp) { */ static int sx_allrrs(struct qstream *qsp) { - struct databuf *dp, *tdp, *gdp; - struct namebuf *gnp, *tnp, *top; - struct hashbuf *htp; - const char *fname; + struct databuf *dp; + struct namebuf *top; int rrcount, class; u_int zone; class = qsp->xfr.class; - top = qsp->xfr.top; + top = qsp->xfr.top.axfr; zone = qsp->xfr.zone; rrcount = 0; for ((void)NULL; (dp = qsp->xfr.lev->dp) != NULL; - qsp->xfr.lev->dp = dp->d_next) { + qsp->xfr.lev->dp = db_next(dp)) { /* XYZZY foreach_rr? */ if (dp->d_class != class && class != C_ANY) continue; @@ -417,18 +572,13 @@ sx_allrrs(struct qstream *qsp) { continue; if (dp->d_zone != zone || stale(dp)) continue; - if (dp->d_type == T_SOA || dp->d_type == T_NS) + if (dp->d_type == T_SOA || dp->d_type == T_NS || + dp->d_type == T_NXT || dp->d_type == T_KEY) + continue; + if (dp->d_type == T_SIG && + (SIG_COVERS(dp) == T_SOA || SIG_COVERS(dp) == T_NS || + SIG_COVERS(dp) == T_KEY || SIG_COVERS(dp) == T_NXT)) continue; - /* XXXRTH I presume this is still relevant and that - this is the right place... */ -#if 0 /* Not yet implemented. Only a SHOULD in the I-D. -gnu@toad.com */ - /* skip the SIG AXFR record because we did it first too. */ - if (dp->d_type == T_SIG) { - int sig_rrtype = GETSHORT (dp->d_data); - if (sig_rrtype == T_AXFR) - continue; - } -#endif /* 0 */ INSIST(!(qsp->xfr.lev->flags & SXL_GLUING)); if (sx_addrr(qsp, qsp->xfr.lev->dname, dp) < 0) { @@ -452,7 +602,7 @@ sx_allrrs(struct qstream *qsp) { * qsp->xfr.state at the end of the topmost level. changes the * qsp->xfr.lev->state several times per domain name. */ -static void +void sx_sendlev(struct qstream *qsp) { struct qs_x_lev *lev; int rrcount; @@ -462,6 +612,12 @@ sx_sendlev(struct qstream *qsp) { switch (lev->state) { case sxl_ns: { while (lev->dp) { + /* Was the child zone reloaded under us? */ + if ((lev->dp->d_flags & DB_F_ACTIVE) == 0) { + (void) shutdown(qsp->s_rfd, 2); + sq_remove(qsp); + return; + } rrcount = sx_nsrrs(qsp); /* If we can't pack this one in, come back later. */ if (rrcount < 0) @@ -470,7 +626,7 @@ sx_sendlev(struct qstream *qsp) { * NS RRs other than those at the * zone top are zone cuts. */ - if (rrcount > 0 && qsp->xfr.top != lev->np) + if (rrcount > 0 && qsp->xfr.top.axfr != lev->np) lev->flags |= SXL_ZONECUT; } /* No more DP's for the NS RR pass on this NP. */ @@ -481,10 +637,18 @@ sx_sendlev(struct qstream *qsp) { /* No NS RR's, so it's safe to send other types. */ lev->state = sxl_all; lev->dp = lev->np->n_data; + if (lev->dp) + DRCNTINC(lev->dp); goto again; } case sxl_all: { while (lev->dp) { + /* Was a record updated under us? */ + if ((lev->dp->d_flags & DB_F_ACTIVE) == 0) { + (void) shutdown(qsp->s_rfd, 2); + sq_remove(qsp); + return; + } /* If we can't pack this one in, come back later. */ if (sx_allrrs(qsp) < 0) return; @@ -535,11 +699,15 @@ sx_sendlev(struct qstream *qsp) { * side effects: * changes qsp->xfr.state. adds RR to output buffer. */ -static void +void sx_sendsoa(struct qstream *qsp) { + HEADER * hp = (HEADER *) qsp->xfr.msg; + if (sx_soarr(qsp) == -1) return; /* No state change, come back here later. */ + hp->aa = 1; + switch (qsp->xfr.state) { case s_x_firstsoa: { /* Next thing to do is send the zone. */ @@ -549,8 +717,8 @@ sx_sendsoa(struct qstream *qsp) { } case s_x_lastsoa: { /* Next thing to do is go back and wait for another query. */ - (void)sx_flush(qsp); qsp->xfr.state = s_x_done; + (void)sx_flush(qsp); sq_writeh(qsp, sq_flushw); break; } @@ -581,6 +749,8 @@ sx_pushlev(struct qstream *qsp, struct namebuf *np) { new->state = sxl_ns; new->np = np; new->dp = np->n_data; + if (new->dp) + DRCNTINC(new->dp); getname(np, new->dname, sizeof new->dname); /* * We find the subdomains by looking in the hash table for this @@ -637,6 +807,26 @@ static struct qs_x_lev * sx_freelev(struct qs_x_lev *lev) { struct qs_x_lev *next = lev->next; + if (lev->dp) { + DRCNTDEC(lev->dp); + if (lev->dp->d_rcnt == 0) + db_freedata(lev->dp); + } memput(lev, sizeof *lev); return (next); } + +static struct databuf * +db_next(struct databuf *dp) { + struct databuf *next = dp->d_next; + + DRCNTDEC(dp); + if (dp->d_rcnt == 0) + db_freedata(dp); + + if (next) + DRCNTINC(next); + + return (next); +} + diff --git a/contrib/bind/bin/named/pathtemplate.h b/contrib/bind/bin/named/pathtemplate.h index d339ef8..65056b6 100644 --- a/contrib/bind/bin/named/pathtemplate.h +++ b/contrib/bind/bin/named/pathtemplate.h @@ -1,9 +1,9 @@ /* - * $Id: pathtemplate.h,v 8.1 1998/03/19 19:53:21 halley Exp $ + * $Id: pathtemplate.h,v 8.4 1999/01/08 19:28:30 vixie Exp $ */ /* - * Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 @@ -41,6 +41,10 @@ #define _PATH_PIDFILE "%DESTRUN%/named.pid" #endif +#ifndef _PATH_NDCSOCK +#define _PATH_NDCSOCK "%DESTRUN%/ndc" +#endif + #ifndef _PATH_STATS #define _PATH_STATS "named.stats" #endif diff --git a/contrib/bind/bin/named/test/named.conf b/contrib/bind/bin/named/test/named.conf index b852604..0e43eac 100644 --- a/contrib/bind/bin/named/test/named.conf +++ b/contrib/bind/bin/named/test/named.conf @@ -5,6 +5,8 @@ options { // directory "/var/named"; check-names master warn; /* default. */ datasize 20M; + deallocate-on-exit yes; + listen-on { 10.0.0.53; }; }; zone "localhost" IN { @@ -27,3 +29,17 @@ zone "." IN { type hint; file "root.hint"; }; + +logging { + channel xfer-log { + file "/var/tmp/bind-xfer.log" versions unlimited size 10m; + print-category yes; + print-severity yes; + print-time yes; + severity info; + }; + category xfer-in { xfer-log; }; + category xfer-out { xfer-log; }; + category notify { xfer-log; }; + category load { xfer-log; }; +}; diff --git a/contrib/bind/bin/named/version.c b/contrib/bind/bin/named/version.c index 9468be2..31820f5 100644 --- a/contrib/bind/bin/named/version.c +++ b/contrib/bind/bin/named/version.c @@ -1,11 +1,11 @@ /* * @(#)Version.c 4.9 (Berkeley) 7/21/90 - * $Id: version.c,v 8.2 1997/04/24 23:59:02 vixie Exp $ + * $Id: version.c,v 8.3 1999/01/02 06:05:14 vixie Exp $ */ #ifndef lint char sccsid[] = "@(#)named %VERSION% %WHEN% %WHOANDWHERE%"; -char rcsid[] = "$Id: version.c,v 8.2 1997/04/24 23:59:02 vixie Exp $"; +char rcsid[] = "$Id: version.c,v 8.3 1999/01/02 06:05:14 vixie Exp $"; #endif /* not lint */ char Version[] = "named %VERSION% %WHEN%\n\t%WHOANDWHERE%"; diff --git a/contrib/bind/bin/ndc/Makefile b/contrib/bind/bin/ndc/Makefile index 13340c2..d2b9feb 100644 --- a/contrib/bind/bin/ndc/Makefile +++ b/contrib/bind/bin/ndc/Makefile @@ -1,4 +1,4 @@ -## Copyright (c) 1996 by Internet Software Consortium +## 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 @@ -13,7 +13,7 @@ ## ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ## SOFTWARE. -# $Id: Makefile,v 1.6 1997/06/19 03:22:10 halley Exp $ +# $Id: Makefile,v 1.15 1999/08/08 17:51:02 vixie Exp $ DESTDIR= CC= cc @@ -31,56 +31,64 @@ A=a O=o LEX = lex -I SYSLIBS = -ll -lutil -PIDDIR = /var/run DESTBIN = /usr/local/bin DESTSBIN = /usr/local/sbin DESTEXEC = /usr/local/libexec DESTMAN = /usr/share/man DESTHELP= /usr/share/misc -AR= ar cruv +AR= ar cru INSTALL= install STRIP=-s +INSTALL_EXEC= +INSTALL_LIB=-o bin -g bin PS=ps LDFLAGS= CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL} ${DEFS} PROG= ndc -SRCS= -OBJS= +SRCS= ${PROG}.c +OBJS= ${PROG}.${O} +HDRS= pathnames.h -all: ${PROG} +all: ${PROG}${EXE} -${PROG}: ${PROG}.sh ../named/pathnames ../named/pathnames.h Makefile - sed -e "s|%PIDFILE%|"`../named/pathnames _path_pidfile`"|" \ - -e "s|%NAMED%|"`../named/pathnames _path_named`"|" \ - -e "s|%PS%|${PS}|" \ - < ndc.sh > ndc - chmod +x ndc +${PROG}${EXE}: ${HDRS} ${OBJS} ${LIBBIND} Makefile + ${CC} ${CDEBUG} ${LDFLAGS} ${BOUNDS} -o ${PROG}${EXE} ${OBJS} ${LIBBIND} ${SYSLIBS} + +.c.${O}: + ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c + +pathnames.h: ${TOP}/.settings Makefile ../named/pathtemplate.h + rm -f pathnames.h + sed -e "s|%DESTSBIN%|${DESTSBIN}|" \ + -e "s|%DESTEXEC%|${DESTEXEC}|" \ + -e "s|%DESTETC%|${DESTETC}|" \ + -e "s|%DESTRUN%|${DESTRUN}|" \ + < ../named/pathtemplate.h > pathnames.h distclean: clean clean: FRC - rm -f ${PROG} ${OBJS} core .depend + rm -f ${PROG}${EXE} ${OBJS} core .depend rm -f *.BAK *.CKP *~ *.orig + rm -f pathnames.h -depend: +depend: ${SRCS} pathnames.h + mkdep ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS} ${DESTDIR}${DESTSBIN}: mkdir -p ${DESTDIR}${DESTSBIN} -install: ${DESTDIR}${DESTSBIN} ${PROG} - ${INSTALL} -c -m 755 ${PROG} ${DESTDIR}${DESTSBIN}/${PROG} +install: ${DESTDIR}${DESTSBIN} ${PROG}${EXE} + ${INSTALL} ${INSTALL_EXEC} ${STRIP} -c -m 755 ${PROG}${EXE} ${DESTDIR}${DESTSBIN}/${PROG}${EXE} links: FRC - @set -e; ln -s SRC/*.sh . + @set -e; ln -s SRC/*.[ch] . tags: FRC ctags ${SRCS} *.h -commands.c: commands.l - ${LEX} -t $< > $@ || rm $@ - FRC: # DO NOT DELETE THIS LINE -- mkdep uses it. diff --git a/contrib/bind/bin/ndc/ndc.c b/contrib/bind/bin/ndc/ndc.c new file mode 100644 index 0000000..764d05b --- /dev/null +++ b/contrib/bind/bin/ndc/ndc.c @@ -0,0 +1,698 @@ +#if !defined(lint) && !defined(SABER) +static const char rcsid[] = "$Id: ndc.c,v 1.13 1999/10/13 16:39:16 vixie Exp $"; +#endif /* not lint */ + +/* + * Portions 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. + */ + +#include "port_before.h" + +#include <sys/types.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 <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> + +#include <isc/eventlib.h> +#include <isc/ctl.h> + +#include "port_after.h" +#include "pathnames.h" + +typedef union { + struct sockaddr_in in; + struct sockaddr_un un; +} sockaddr_t; + +typedef void (*closure)(void *, const char *, int); + +static const char * program = "amnesia"; +static enum { e_channel, e_signals } mode = e_channel; +static char * channel = _PATH_NDCSOCK; +static const char helpfmt[] = "\t%-16s\t%s\n"; +static const char * pidfile = _PATH_PIDFILE; +static sockaddr_t client, server; +static int quiet = 0, tracing = 0, silent = 0, client_set = 0; +static int debug = 0, errors = 0, doneflag, exitflag; +static int logger_show = 1; +static evContext ev; +static char cmd[1000]; +static const char * named_path = _PATH_NAMED; + +static int slashcmd(void); +static void slashhelp(void); +static int builtincmd(void); +static void command(void); +static int running(int, pid_t *); +static void command_channel(void); +static void channel_loop(char *, int, closure, void *); +static void getpid_closure(void *, const char *, int); +static void banner(struct ctl_cctx *, void *, const char *, u_int); +static void done(struct ctl_cctx *, void *, const char *, u_int); +static void logger(enum ctl_severity, const char *fmt, ...); +static void command_signals(void); +static void stop_named(pid_t); +static void start_named(const char *, int); +static int fgetpid(const char *, pid_t *); +static int get_sockaddr(char *, sockaddr_t *); +static size_t impute_addrlen(const struct sockaddr *); +static void vtrace(const char *, va_list); +static void trace(const char *, ...); +static void result(const char *, ...); +static void fatal(const char *, ...); +static void verror(const char *, va_list); +static void error(const char *, ...); + +static void +usage(const char *fmt, ...) { + va_list args; + + va_start(args, fmt); + fprintf(stderr, "%s: usage error: ", program); + vfprintf(stderr, fmt, args); + fputc('\n', stderr); + va_end(args); + fatal("usage: %s \ +[-l localsock] [-c channel] [-p pidfile] [-n namedpath] \ +[-dqst] [command [args]]\n\ +", + program); +} + +/* Public. */ + +int +main(int argc, char *argv[], char *envp[]) { + char *p; + int ch; + + if ((program = strrchr(argv[0], '/')) != NULL) + program++; + else + program = argv[0]; + while ((ch = getopt(argc, argv, "c:p:l:n:dqst")) != -1) { + switch (ch) { + case 'c': + channel = optarg; + mode = e_channel; + break; + case 'p': + pidfile = optarg; + mode = e_signals; + break; + case 'l': + if (!get_sockaddr(optarg, &client)) + usage("bad local socket (%s)", optarg); + client_set++; + break; + case 'n': + named_path = optarg; + break; + case 'd': + tracing++; + debug++; + break; + case 'q': + quiet++; + break; + case 's': + silent++; + break; + case 't': + tracing++; + break; + default: + usage("unrecognized command option (%c)", ch); + /* NOTREACHED */ + } + } + if (mode != e_channel && client_set) + usage("the -l flag is only valid for control channels"); + if (mode == e_channel) { + if (!get_sockaddr(channel, &server)) + usage("bad channel name (%s)", channel); + if (evCreate(&ev) < 0) + fatal("evCreate - %s", strerror(errno)); + } + *(p = cmd) = '\0'; + for (argc -= optind, argv += optind; + argc > 0; + argc--, argv++) { + size_t t = strlen(*argv); + + if ((p - cmd) + t + 2 > sizeof cmd) + usage("command too long"); + strcpy(p, *argv); + p += t; + if (argv[1] != NULL) + *p++ = ' '; + *p = '\0'; + } + if (cmd[0] != '\0') { + command(); + } else { + if (!quiet) + result("Type help -or- /h if you need help."); + for (exitflag = 0; !exitflag; (void)NULL) { + if (!quiet) { + printf("%s> ", program); + fflush(stdout); + } + if (!fgets(cmd, sizeof cmd, stdin)) { + if (!quiet) + result("EOF"); + exitflag++; + continue; + } + if (cmd[strlen(cmd) - 1] == '\n') + cmd[strlen(cmd) - 1] = '\0'; + if (cmd[0] == '\0') + continue; + if (slashcmd()) + continue; + command(); + } + } + if (mode == e_channel) + evDestroy(ev); + exit(errors != 0); +} + +/* Private. */ + +static int +slashcmd(void) { + if (strncasecmp(cmd, "/help", strlen(cmd)) == 0) + slashhelp(); + else if (strncasecmp(cmd, "/exit", strlen(cmd)) == 0) + exitflag++; + else if (strncasecmp(cmd, "/trace", strlen(cmd)) == 0) + result("tracing now %s", + (tracing = !tracing) ? "on" : "off"); + else if (strncasecmp(cmd, "/debug", strlen(cmd)) == 0) + result("debugging now %s", + (debug = !debug) ? "on" : "off"); + else if (strncasecmp(cmd, "/quiet", strlen(cmd)) == 0) + result("%s is now %s", program, + (quiet = !quiet) ? "quiet" : "noisy"); + else if (strncasecmp(cmd, "/silent", strlen(cmd)) == 0) + result("%s is now %s", program, + (silent = !silent) + ? "silent" : "gregarious"); + else + return (0); + return (1); +} + +static void +slashhelp(void) { + printf(helpfmt, "/h(elp)", "this text"); + printf(helpfmt, "/e(xit)", "leave this program"); + printf(helpfmt, "/t(race)", + "toggle tracing (protocol and system events)"); + printf(helpfmt, "/d(ebug)", + "toggle debugging (internal program events)"); + printf(helpfmt, "/q(uiet)", + "toggle quietude (prompts and results)"); + printf(helpfmt, "/s(ilent)", + "toggle silence (suppresses nonfatal errors)"); +} + +static int +builtincmd(void) { + static const char spaces[] = " \t"; + char *rest, *syscmd; + pid_t pid; + int save_quiet = quiet; + int len; + + quiet = 1; + + len = strcspn(cmd, spaces); + rest = cmd + len; + if (*rest != '\0') { + rest++; + rest += strspn(rest, spaces); + } + syscmd = malloc(strlen(named_path) + sizeof " " + strlen(rest)); + if (syscmd == NULL) + fatal("malloc() failed - %s", strerror(errno)); + strcpy(syscmd, named_path); + if (*rest != '\0') { + strcat(syscmd, " "); + strcat(syscmd, rest); + } + if (strncasecmp(cmd, "start", len) == 0) { + if (running(debug, &pid)) + error("name server already running? (pid %ld)", + (long)pid); + else + start_named(syscmd, save_quiet); + quiet = save_quiet; + free(syscmd); + return (1); + } else if (strncasecmp(cmd, "restart", len) == 0) { + if (!running(debug, &pid)) + error("name server was not running (warning only)"); + else + stop_named(pid); + start_named(syscmd, save_quiet); + quiet = save_quiet; + free(syscmd); + return (1); + } + quiet = save_quiet; + free(syscmd); + return (0); +} + +static void +builtinhelp(void) { + printf(helpfmt, "start", "start the server"); + printf(helpfmt, "restart", "stop server if any, start a new one"); +} + +static void +command(void) { + if (builtincmd()) + return; + switch (mode) { + case e_channel: + command_channel(); + break; + case e_signals: + command_signals(); + break; + default: + abort(); + } +} + +static int +running(int show, pid_t *pidp) { + pid_t pid; + + switch (mode) { + case e_channel: + pid = 0; + channel_loop("getpid", show, getpid_closure, &pid); + if (pid != 0) { + if (tracing) + result("pid %ld is running", (long)pid); + *pidp = pid; + return (1); + } + break; + case e_signals: + if (fgetpid(pidfile, pidp)) { + if (tracing) + result("pid %ld is running", (long)pid); + return (1); + } + break; + default: + abort(); + } + if (show) + error("pid not valid or server not running"); + return (0); +} + +static void +getpid_closure(void *uap, const char *text, int flags) { + pid_t *pidp = uap; + const char *cp; + + flags = flags; + if ((cp = strchr(text, '<')) != NULL) { + long l = 0; + char ch; + + while ((ch = *++cp) != '\0' && ch != '>' && isdigit(ch)) + l *= 10, l += (ch - '0'); + if (ch == '>') { + *pidp = (pid_t)l; + return; + } + } + error("response does not contain pid (%s)", text); +} + +static void +command_channel(void) { + int helping = (strcasecmp(cmd, "help") == 0); + int save_quiet = quiet; + + if (helping) + quiet = 0; + channel_loop(cmd, !quiet, NULL, NULL); + quiet = save_quiet; +} + +struct args { + const char *cmd; + closure cl; + void *ua; +}; + +static void +channel_loop(char *cmdtext, int show, closure cl, void *ua) { + struct ctl_cctx *ctl; + struct sockaddr *client_addr; + struct args a; + evEvent e; + int save_logger_show = logger_show; + + if (!client_set) + client_addr = NULL; + else + client_addr = (struct sockaddr *)&client; + a.cmd = cmdtext; + a.cl = cl; + a.ua = ua; + logger_show = show; + ctl = ctl_client(ev, client_addr, impute_addrlen(client_addr), + (struct sockaddr *)&server, + impute_addrlen((struct sockaddr *)&server), + banner, &a, 15, logger); + if (ctl == NULL) { + if (show) + error("cannot connect to command channel (%s)", + channel); + } else { + doneflag = 0; + while (evGetNext(ev, &e, EV_WAIT) == 0) + if (evDispatch(ev, e) < 0 || doneflag) + break; + ctl_endclient(ctl); + } + logger_show = save_logger_show; +} + +static void +banner(struct ctl_cctx *ctl, void *uap, const char *msg, u_int flags) { + struct args *a = uap; + + if (msg == NULL) { + trace("EOF"); + doneflag = 1; + return; + } + trace("%s", msg); + if ((flags & CTL_MORE) != 0) + return; + if (ctl_command(ctl, a->cmd, strlen(a->cmd), done, a) < 0) { + error("ctl_command failed - %s", strerror(errno)); + doneflag = 1; + } +} + +static void +done(struct ctl_cctx *ctl, void *uap, const char *msg, u_int flags) { + struct args *a = uap; + + if (msg == NULL) { + trace("EOF"); + doneflag = 1; + return; + } + if (!tracing && !quiet && strlen(msg) > 4) + result("%s", msg + 4); + trace("%s", msg); + if (a->cl) + (a->cl)(a->ua, msg, flags); + if ((flags & CTL_MORE) == 0) + doneflag = 1; +} + +static void +logger(enum ctl_severity ctlsev, const char *format, ...) { + va_list args; + + va_start(args, format); + switch (ctlsev) { + case ctl_debug: + /* FALLTHROUGH */ + case ctl_warning: + if (debug) + vtrace(format, args); + break; + case ctl_error: + if (logger_show) + verror(format, args); + break; + default: + abort(); + } + va_end(args); +} + +static struct cmdsig { + const char * cmd; + int sig; + const char * help; +} cmdsigs[] = { + { "dumpdb", SIGINT, "dump cache database to a file" }, + { "reload", SIGHUP, "reload configuration file" }, + { "stats", SIGILL, "dump statistics to a file" }, + { "trace", SIGUSR1, "increment trace level" }, + { "notrace", SIGUSR2, "turn off tracing" }, +#ifdef SIGWINCH + { "querylog", SIGWINCH, "toggle query logging" }, + { "qrylog", SIGWINCH, "alias for querylog" }, +#endif + { NULL, 0 } +}; + +static void +command_signals(void) { + struct cmdsig *cmdsig; + pid_t pid; + int sig; + + if (strcasecmp(cmd, "help") == 0) { + printf(helpfmt, "help", "this output"); + printf(helpfmt, "status", "check for running server"); + printf(helpfmt, "stop", "stop the server"); + builtinhelp(); + for (cmdsig = cmdsigs; cmdsig->cmd != NULL; cmdsig++) + printf(helpfmt, cmdsig->cmd, cmdsig->help); + } else if (strcasecmp(cmd, "status") == 0) { + if (!fgetpid(pidfile, &pid)) + error("pid not valid or server not running"); + else + result("pid %ld is running", (long)pid); + } else if (strcasecmp(cmd, "stop") == 0) { + if (!fgetpid(pidfile, &pid)) + error("name server not running"); + else + stop_named(pid); + } else { + for (cmdsig = cmdsigs; cmdsig->cmd != NULL; cmdsig++) + if (strcasecmp(cmd, cmdsig->cmd) == 0) + break; + if (cmdsig->cmd == NULL) + error("unrecognized command (%s)", cmd); + else if (!fgetpid(pidfile, &pid)) + error("can't get pid (%s)", pidfile); + else if (kill(pid, cmdsig->sig) < 0) + error("kill() failed - %s", strerror(errno)); + else + trace("pid %ld sig %d OK", (long)pid, cmdsig->sig); + } +} + +static void +stop_named(pid_t pid) { + int n; + + trace("stopping named (pid %ld)", (long)pid); + switch (mode) { + case e_signals: + if (kill(pid, SIGTERM) < 0) { + error("kill(%ld, SIGTERM) failed - %s", + (long)pid, strerror(errno)); + return; + } + trace("SIGTERM ok, waiting for death"); + break; + case e_channel: + channel_loop("stop", tracing, NULL, NULL); + break; + default: + abort(); + } + for (n = 0; n < 10; n++) { + if (kill(pid, 0) != 0) { + trace("named (pid %ld) is dead", (long)pid); + return; + } + sleep(1); + } + error("named (pid %ld) didn't die", (long)pid); +} + +static void +start_named(const char *syscmd, int local_quiet) { + pid_t pid; + + if (system(syscmd) != 0) + error("could not start new name server (%s)", syscmd); + else { + sleep(3); + if (!running(0, &pid)) + error("name server has not started (yet?)"); + else if (!local_quiet) + result("new pid is %ld", (long)pid); + } +} + +static int +fgetpid(const char *f, pid_t *pid) { + FILE *fp; + int try; + long t; + + for (try = 0; try < 5; try++) { + trace("pidfile is \"%s\" (try #%d)", pidfile, try + 1); + if ((fp = fopen(pidfile, "r")) == NULL) + trace("pid file (%s) unavailable - %s", + pidfile, strerror(errno)); + else if (fscanf(fp, "%ld\n", &t) != 1) + trace("pid file (%s) format is bad", pidfile); + else if (*pid = (pid_t)t, fclose(fp), kill(*pid, 0) < 0) + trace("pid file (%s) contains unusable pid (%d) - %s", + pidfile, *pid, strerror(errno)); + else { + trace("pid is %ld", (long)*pid); + return (1); + } + sleep(1); + } + trace("pid not found"); + return (0); +} + +static int +get_sockaddr(char *name, sockaddr_t *addr) { + char *slash; + + if (name[0] == '/') { + memset(&addr->un, '\0', sizeof addr->un); + addr->un.sun_family = AF_UNIX; + strncpy(addr->un.sun_path, name, sizeof addr->un.sun_path - 1); + addr->un.sun_path[sizeof addr->un.sun_path - 1] = '\0'; + } else if ((slash = strrchr(name, '/')) != NULL) { + *slash = '\0'; + memset(&addr->in, '\0', sizeof addr->in); + if (!inet_pton(AF_INET, name, &addr->in.sin_addr)) + usage("bad ip address (%s)", name); + if ((addr->in.sin_port = htons(atoi(slash+1))) == 0) + usage("bad ip port (%s)", slash+1); + addr->in.sin_family = AF_INET; + *slash = ':'; + } else { + return (0); + } + return (1); +} + +static size_t +impute_addrlen(const struct sockaddr *sa) { + if (sa == 0) + return (0); + switch (sa->sa_family) { + case AF_INET: + return (sizeof(struct sockaddr_in)); + case AF_UNIX: + return (sizeof(struct sockaddr_un)); + default: + abort(); + } +} + +static void +vtrace(const char *fmt, va_list ap) { + if (tracing) { + fprintf(stdout, "%s: [", program); + vfprintf(stdout, fmt, ap); + fputs("]\n", stdout); + } +} + +static void +trace(const char *fmt, ...) { + va_list args; + + va_start(args, fmt); + vtrace(fmt, args); + va_end(args); +} + +static void +result(const char *fmt, ...) { + va_list args; + + va_start(args, fmt); + vfprintf(stdout, fmt, args); + fputc('\n', stdout); + va_end(args); +} + +static void +fatal(const char *fmt, ...) { + va_list args; + + va_start(args, fmt); + fprintf(stderr, "%s: fatal error: ", program); + vfprintf(stderr, fmt, args); + fputc('\n', stderr); + va_end(args); + exit(1); +} + +static void +verror(const char *fmt, va_list ap) { + fprintf(stderr, "%s: error: ", program); + vfprintf(stderr, fmt, ap); + fputc('\n', stderr); + errors++; +} + +static void +error(const char *fmt, ...) { + va_list args; + + va_start(args, fmt); + if (silent) + vtrace(fmt, args); + else + verror(fmt, args); + va_end(args); +} diff --git a/contrib/bind/bin/nslookup/Makefile b/contrib/bind/bin/nslookup/Makefile index 15cc94f..0f6db20 100644 --- a/contrib/bind/bin/nslookup/Makefile +++ b/contrib/bind/bin/nslookup/Makefile @@ -1,4 +1,4 @@ -## Copyright (c) 1996 by Internet Software Consortium +## 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 @@ -13,7 +13,7 @@ ## ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ## SOFTWARE. -# $Id: Makefile,v 8.18 1997/12/03 22:55:16 halley Exp $ +# $Id: Makefile,v 8.24 1999/10/13 01:14:46 vixie Exp $ DESTDIR= CC= cc @@ -29,18 +29,20 @@ PORTINCL = ${TOP}/port/${SYSTYPE}/include LIBBIND = ${TOP}/lib/libbind.a A=a O=o +EXE= LEX = lex -I SYSLIBS = -ll -lutil -PIDDIR = /var/run DESTBIN = /usr/local/bin DESTSBIN = /usr/local/sbin DESTEXEC = /usr/local/libexec DESTMAN = /usr/share/man DESTHELP= /usr/share/misc STRIP=-s +INSTALL_EXEC= +INSTALL_LIB=-o bin -g bin LDFLAGS= -DEFS= -D_PATH_HELPFILE=\"${DESTDIR}${DESTHELP}/nslookup.help\" +DEFS= -D_PATH_HELPFILE=\"${DESTHELP}/nslookup.help\" CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL} ${DEFS} PROG= nslookup @@ -49,17 +51,20 @@ SRCS= ${CSRCS} commands.l OBJS= main.${O} getinfo.${O} debug.${O} send.${O} skip.${O} list.${O} \ subr.${O} commands.${O} -all: ${PROG} +all: ${PROG}${EXE} -${PROG}: ${OBJS} ${LIBBIND} Makefile - ${CC} ${CDEBUG} ${LDFLAGS} -o ${PROG} ${OBJS} \ +${PROG}${EXE}: ${OBJS} ${LIBBIND} Makefile + ${CC} ${CDEBUG} ${LDFLAGS} ${BOUNDS} -o ${PROG}${EXE} ${OBJS} \ ${LIBBIND} ${SYSLIBS} +.c.${O}: + ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c + distclean: clean rm -f commands.c clean: FRC - rm -f ${PROG} ${OBJS} core .depend + rm -f ${PROG}${EXE} ${OBJS} core .depend rm -f *.BAK *.CKP *~ *.orig rm -f lex.yy.c lex.yy.o @@ -72,9 +77,9 @@ ${DESTDIR}${DESTHELP}: ${DESTDIR}${DESTBIN}: mkdir -p ${DESTDIR}${DESTBIN} -install: ${DESTDIR}${DESTBIN} ${DESTDIR}${DESTHELP} ${PROG} - ${INSTALL} ${STRIP} -c -m 755 ${PROG} ${DESTDIR}${DESTBIN}/${PROG} - ${INSTALL} -c -o bin -g bin -m 444 nslookup.help ${DESTDIR}${DESTHELP}/ +install: ${DESTDIR}${DESTBIN} ${DESTDIR}${DESTHELP} ${PROG}${EXE} + ${INSTALL} ${STRIP} -c ${INSTALL_EXEC} -m 755 ${PROG}${EXE} ${DESTDIR}${DESTBIN}/${PROG}${EXE} + ${INSTALL} -c ${INSTALL_LIB} -m 444 nslookup.help ${DESTDIR}${DESTHELP}/ links: FRC @set -e; ln -s SRC/*.[chl] SRC/nslookup.help . diff --git a/contrib/bind/bin/nslookup/commands.c b/contrib/bind/bin/nslookup/commands.c index 5564b28..fead60f 100644 --- a/contrib/bind/bin/nslookup/commands.c +++ b/contrib/bind/bin/nslookup/commands.c @@ -317,10 +317,10 @@ static yyconst int yy_ec[256] = 6, 7, 8, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 1, 9, 1, 1, 6, 1, 10, 4, 4, 11, + 1, 9, 1, 1, 10, 1, 11, 4, 4, 12, - 12, 13, 14, 15, 16, 4, 4, 17, 18, 19, - 20, 21, 4, 22, 23, 24, 4, 25, 26, 27, + 13, 14, 15, 16, 17, 4, 4, 18, 19, 20, + 21, 22, 4, 23, 24, 25, 4, 26, 27, 28, 4, 4, 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, @@ -338,38 +338,38 @@ static yyconst int yy_ec[256] = 1, 1, 1, 1, 1 } ; -static yyconst int yy_meta[28] = +static yyconst int yy_meta[29] = { 0, 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 } ; static yyconst short int yy_base[203] = { 0, - 491, 0, 493, 611, 611, 489, 27, 611, 54, 56, - 63, 51, 48, 46, 54, 56, 60, 479, 611, 0, - 611, 446, 77, 0, 61, 70, 62, 64, 74, 76, - 103, 611, 439, 91, 611, 80, 94, 97, 113, 75, - 95, 104, 140, 149, 96, 112, 106, 158, 107, 108, - 73, 126, 110, 166, 611, 173, 182, 142, 0, 152, - 150, 168, 195, 202, 161, 191, 160, 226, 197, 235, - 198, 611, 244, 611, 184, 205, 611, 207, 611, 253, - 213, 219, 236, 237, 611, 237, 264, 273, 282, 291, - 255, 0, 275, 294, 302, 311, 299, 268, 320, 611, - - 327, 266, 611, 336, 345, 322, 611, 354, 611, 363, - 463, 372, 381, 304, 390, 398, 611, 405, 330, 611, - 414, 423, 432, 435, 611, 442, 451, 611, 460, 469, - 478, 481, 611, 488, 497, 338, 0, 347, 611, 500, - 507, 510, 517, 520, 611, 527, 536, 365, 611, 545, - 374, 548, 555, 564, 383, 567, 611, 574, 583, 400, - 0, 592, 601, 407, 611, 416, 611, 425, 611, 611, - 463, 454, 447, 446, 445, 435, 428, 419, 410, 403, - 393, 386, 377, 368, 357, 350, 341, 314, 296, 285, - 278, 240, 229, 222, 218, 191, 177, 145, 137, 129, - - 117, 98 + 504, 0, 497, 626, 626, 484, 28, 626, 56, 58, + 65, 52, 49, 47, 55, 57, 61, 477, 626, 0, + 626, 451, 79, 0, 62, 71, 63, 67, 73, 75, + 103, 626, 450, 94, 626, 90, 74, 96, 113, 95, + 94, 107, 141, 150, 100, 106, 105, 159, 108, 104, + 72, 128, 110, 168, 626, 175, 184, 137, 0, 144, + 160, 152, 193, 200, 153, 187, 185, 225, 195, 235, + 202, 626, 244, 626, 186, 204, 626, 215, 626, 254, + 218, 237, 245, 257, 626, 241, 273, 282, 291, 301, + 263, 0, 284, 265, 312, 322, 283, 277, 331, 626, + + 338, 268, 626, 347, 356, 275, 626, 365, 626, 375, + 466, 384, 393, 314, 402, 411, 626, 418, 333, 626, + 427, 436, 445, 448, 626, 455, 464, 626, 474, 483, + 493, 496, 626, 503, 512, 341, 0, 349, 626, 515, + 522, 525, 532, 535, 626, 542, 551, 358, 626, 560, + 377, 563, 570, 579, 386, 582, 626, 589, 598, 395, + 0, 607, 616, 413, 626, 420, 626, 429, 626, 626, + 460, 459, 458, 448, 441, 440, 439, 432, 423, 416, + 405, 398, 389, 380, 368, 361, 352, 336, 325, 306, + 294, 287, 267, 247, 240, 228, 209, 207, 198, 173, + + 162, 144 } ; static yyconst short int yy_def[203] = @@ -399,152 +399,156 @@ static yyconst short int yy_def[203] = 170, 170 } ; -static yyconst short int yy_nxt[639] = +static yyconst short int yy_nxt[655] = { 0, 6, 7, 8, 9, 6, 6, 6, 10, 9, 9, - 9, 11, 12, 9, 13, 9, 14, 9, 9, 9, - 9, 15, 16, 9, 17, 9, 9, 18, 20, 21, - 22, 18, 18, 18, 23, 22, 22, 22, 24, 25, - 22, 26, 22, 27, 22, 22, 22, 22, 28, 29, - 22, 30, 22, 22, 18, 31, 32, 34, 35, 38, - 18, 18, 18, 18, 31, 32, 37, 41, 39, 18, - 18, 18, 33, 40, 33, 42, 37, 33, 34, 35, - 33, 38, 33, 40, 39, 41, 33, 33, 33, 36, - 33, 42, 34, 35, 50, 45, 33, 67, 163, 33, - - 33, 33, 33, 18, 31, 32, 33, 18, 18, 44, - 18, 18, 46, 47, 48, 53, 51, 162, 52, 60, - 33, 33, 33, 33, 49, 61, 62, 68, 65, 160, - 33, 66, 33, 33, 33, 69, 33, 158, 33, 33, - 18, 54, 55, 71, 72, 153, 18, 18, 18, 18, - 57, 19, 33, 73, 74, 59, 18, 18, 18, 48, - 32, 75, 64, 18, 44, 18, 18, 54, 55, 76, - 77, 86, 70, 18, 54, 55, 33, 146, 33, 18, - 18, 18, 18, 57, 19, 83, 33, 33, 18, 18, - 18, 143, 84, 85, 33, 18, 78, 79, 89, 71, - - 72, 18, 18, 18, 19, 93, 76, 77, 78, 79, - 33, 81, 81, 94, 95, 19, 81, 33, 141, 81, - 96, 19, 136, 33, 81, 82, 18, 68, 32, 134, - 88, 88, 44, 18, 18, 18, 90, 19, 84, 85, - 131, 92, 18, 18, 18, 73, 74, 97, 18, 18, - 44, 18, 18, 18, 78, 79, 106, 107, 98, 18, - 18, 18, 33, 33, 18, 99, 100, 102, 103, 115, - 18, 18, 18, 18, 102, 103, 108, 109, 129, 18, - 18, 18, 18, 89, 32, 126, 105, 105, 44, 18, - 18, 18, 90, 19, 33, 110, 123, 18, 18, 18, - - 111, 33, 18, 95, 19, 130, 18, 18, 18, 18, - 18, 18, 96, 19, 121, 18, 18, 18, 18, 18, - 114, 99, 100, 106, 107, 33, 70, 18, 99, 100, - 33, 119, 120, 18, 18, 18, 18, 116, 117, 148, - 149, 105, 18, 18, 18, 18, 119, 120, 138, 139, - 118, 18, 18, 18, 18, 108, 109, 113, 18, 18, - 122, 18, 18, 18, 110, 19, 148, 149, 112, 18, - 18, 18, 18, 124, 125, 150, 19, 104, 18, 18, - 18, 18, 127, 128, 154, 19, 88, 18, 18, 18, - 18, 115, 32, 101, 18, 18, 44, 18, 18, 116, - - 117, 164, 165, 91, 70, 18, 116, 117, 164, 165, - 87, 18, 18, 18, 18, 132, 133, 166, 167, 80, - 18, 18, 18, 18, 135, 19, 168, 169, 63, 137, - 18, 18, 18, 138, 139, 58, 124, 125, 18, 18, - 18, 140, 18, 124, 125, 56, 43, 33, 18, 18, - 18, 18, 127, 128, 18, 18, 18, 142, 18, 18, - 18, 127, 128, 4, 110, 33, 18, 18, 18, 18, - 130, 32, 33, 18, 18, 44, 18, 18, 18, 144, - 145, 19, 132, 133, 18, 18, 18, 147, 18, 132, - 133, 19, 170, 5, 18, 18, 18, 18, 135, 19, - - 170, 150, 19, 18, 18, 18, 151, 18, 152, 128, - 170, 154, 19, 18, 18, 18, 155, 18, 156, 157, - 170, 144, 145, 18, 18, 18, 70, 18, 144, 145, - 170, 170, 170, 18, 18, 18, 18, 159, 19, 170, - 170, 170, 161, 18, 18, 18, 150, 19, 170, 152, - 128, 18, 18, 18, 142, 18, 152, 128, 170, 170, - 170, 18, 18, 18, 18, 154, 19, 170, 156, 157, - 18, 18, 18, 70, 18, 156, 157, 170, 170, 170, - 18, 18, 18, 18, 159, 19, 170, 170, 170, 18, - 18, 18, 18, 166, 167, 170, 170, 170, 18, 18, - - 18, 18, 168, 169, 170, 170, 170, 18, 18, 18, - 3, 170, 170, 170, 170, 170, 170, 170, 170, 170, + 9, 9, 11, 12, 9, 13, 9, 14, 9, 9, + 9, 9, 15, 16, 9, 17, 9, 9, 18, 20, + 21, 22, 18, 18, 18, 23, 22, 22, 22, 22, + 24, 25, 22, 26, 22, 27, 22, 22, 22, 22, + 28, 29, 22, 30, 22, 22, 18, 31, 32, 34, + 35, 38, 18, 18, 18, 18, 31, 32, 37, 41, + 39, 18, 18, 18, 33, 40, 33, 42, 37, 33, + 34, 35, 33, 38, 33, 41, 39, 40, 33, 33, + 33, 42, 36, 46, 33, 34, 35, 67, 33, 33, + + 33, 33, 33, 18, 31, 32, 45, 18, 18, 44, + 18, 18, 18, 47, 48, 50, 51, 33, 52, 53, + 61, 33, 33, 33, 60, 49, 62, 33, 66, 68, + 65, 33, 33, 33, 33, 33, 69, 33, 71, 72, + 33, 18, 54, 55, 163, 73, 74, 18, 18, 18, + 18, 57, 19, 76, 77, 33, 59, 18, 18, 18, + 48, 32, 162, 64, 18, 44, 18, 18, 18, 54, + 55, 33, 75, 160, 70, 18, 54, 55, 83, 33, + 33, 18, 18, 18, 18, 57, 19, 33, 84, 85, + 18, 18, 18, 18, 78, 79, 89, 86, 158, 18, + + 18, 18, 19, 71, 72, 76, 77, 153, 93, 146, + 81, 81, 33, 33, 33, 81, 78, 79, 81, 95, + 19, 94, 33, 81, 82, 18, 68, 32, 143, 88, + 88, 44, 18, 18, 88, 18, 90, 19, 96, 19, + 141, 92, 18, 18, 18, 73, 74, 136, 18, 18, + 44, 18, 18, 18, 18, 78, 79, 97, 84, 85, + 18, 18, 18, 98, 106, 107, 110, 134, 33, 102, + 103, 111, 33, 18, 99, 100, 106, 107, 115, 18, + 18, 18, 18, 102, 103, 108, 109, 131, 18, 18, + 18, 18, 89, 32, 129, 105, 105, 44, 18, 18, + + 105, 18, 90, 19, 33, 114, 126, 18, 18, 18, + 33, 33, 18, 95, 19, 130, 18, 18, 18, 18, + 18, 18, 18, 96, 19, 123, 18, 18, 18, 18, + 18, 18, 99, 100, 119, 120, 121, 70, 18, 99, + 100, 33, 148, 149, 18, 18, 18, 18, 116, 117, + 138, 139, 105, 18, 18, 18, 18, 119, 120, 148, + 149, 118, 18, 18, 18, 18, 108, 109, 113, 18, + 18, 122, 18, 18, 18, 18, 110, 19, 150, 19, + 112, 18, 18, 18, 18, 124, 125, 154, 19, 104, + 18, 18, 18, 18, 127, 128, 164, 165, 88, 18, + + 18, 18, 18, 115, 32, 101, 18, 18, 44, 18, + 18, 18, 116, 117, 164, 165, 91, 70, 18, 116, + 117, 166, 167, 87, 18, 18, 18, 18, 132, 133, + 168, 169, 80, 18, 18, 18, 18, 135, 19, 63, + 58, 56, 137, 18, 18, 18, 138, 139, 43, 124, + 125, 18, 18, 18, 140, 18, 124, 125, 33, 18, + 4, 18, 18, 18, 18, 127, 128, 110, 18, 18, + 142, 18, 18, 18, 18, 127, 128, 33, 33, 19, + 18, 18, 18, 18, 130, 32, 19, 18, 18, 44, + 18, 18, 18, 18, 144, 145, 170, 132, 133, 18, + + 18, 18, 147, 18, 132, 133, 5, 170, 170, 18, + 18, 18, 18, 135, 19, 170, 150, 19, 18, 18, + 18, 151, 18, 152, 128, 170, 154, 19, 18, 18, + 18, 155, 18, 156, 157, 170, 144, 145, 18, 18, + 18, 70, 18, 144, 145, 170, 170, 170, 18, 18, + 18, 18, 159, 19, 170, 170, 170, 161, 18, 18, + 18, 150, 19, 170, 152, 128, 18, 18, 18, 142, + 18, 152, 128, 170, 170, 170, 18, 18, 18, 18, + 154, 19, 170, 156, 157, 18, 18, 18, 70, 18, + 156, 157, 170, 170, 170, 18, 18, 18, 18, 159, + + 19, 170, 170, 170, 18, 18, 18, 18, 166, 167, + 170, 170, 170, 18, 18, 18, 18, 168, 169, 170, + 170, 170, 18, 18, 18, 3, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, - 170, 170, 170, 170, 170, 170, 170, 170 + 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, + 170, 170, 170, 170 } ; -static yyconst short int yy_chk[639] = +static yyconst short int yy_chk[655] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, + 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 9, 9, 9, 10, 10, 13, - 9, 9, 9, 11, 11, 11, 12, 16, 14, 11, - 11, 11, 14, 15, 13, 17, 25, 12, 23, 23, - 15, 26, 16, 28, 27, 29, 17, 25, 27, 11, - 28, 30, 34, 34, 40, 36, 26, 51, 202, 51, - - 29, 40, 30, 31, 31, 31, 36, 31, 31, 31, - 31, 31, 37, 38, 39, 42, 41, 201, 41, 45, - 37, 41, 45, 38, 39, 46, 47, 52, 49, 200, - 42, 50, 47, 49, 50, 53, 53, 199, 46, 39, - 43, 43, 43, 58, 58, 198, 43, 43, 43, 44, - 44, 44, 52, 60, 60, 44, 44, 44, 48, 48, - 48, 61, 48, 48, 48, 48, 48, 54, 54, 62, - 62, 67, 54, 56, 56, 56, 61, 197, 60, 56, - 56, 56, 57, 57, 57, 65, 67, 65, 57, 57, - 57, 196, 66, 66, 62, 63, 63, 63, 69, 71, - - 71, 63, 63, 63, 64, 75, 76, 76, 78, 78, - 75, 64, 64, 78, 81, 81, 64, 66, 195, 64, - 82, 82, 194, 69, 64, 64, 68, 68, 68, 193, - 68, 68, 68, 68, 68, 70, 70, 70, 84, 84, - 192, 70, 70, 70, 73, 73, 73, 83, 73, 73, - 73, 73, 73, 80, 80, 80, 91, 91, 86, 80, - 80, 80, 83, 86, 87, 87, 87, 102, 102, 98, - 87, 87, 87, 88, 88, 88, 93, 93, 191, 88, - 88, 88, 89, 89, 89, 190, 89, 89, 89, 89, - 89, 90, 90, 90, 98, 94, 189, 90, 90, 90, - - 94, 93, 95, 95, 95, 114, 95, 95, 95, 95, - 95, 96, 96, 96, 188, 96, 96, 96, 96, 96, - 97, 99, 99, 106, 106, 97, 99, 101, 101, 101, - 114, 119, 119, 101, 101, 101, 104, 104, 104, 136, - 136, 187, 104, 104, 104, 105, 105, 105, 138, 138, - 186, 105, 105, 105, 108, 108, 108, 185, 108, 108, - 108, 108, 108, 110, 110, 110, 148, 148, 184, 110, - 110, 110, 112, 112, 112, 151, 151, 183, 112, 112, - 112, 113, 113, 113, 155, 155, 182, 113, 113, 113, - 115, 115, 115, 181, 115, 115, 115, 115, 115, 116, - - 116, 160, 160, 180, 116, 118, 118, 118, 164, 164, - 179, 118, 118, 118, 121, 121, 121, 166, 166, 178, - 121, 121, 121, 122, 122, 122, 168, 168, 177, 122, - 122, 122, 123, 123, 123, 176, 124, 124, 123, 123, - 123, 124, 126, 126, 126, 175, 174, 173, 126, 126, - 126, 127, 127, 127, 172, 127, 127, 127, 127, 127, - 129, 129, 129, 171, 111, 33, 129, 129, 129, 130, - 130, 130, 22, 130, 130, 130, 130, 130, 131, 131, - 131, 18, 132, 132, 131, 131, 131, 132, 134, 134, - 134, 6, 3, 1, 134, 134, 134, 135, 135, 135, - - 0, 140, 140, 135, 135, 135, 140, 141, 141, 141, - 0, 142, 142, 141, 141, 141, 142, 143, 143, 143, - 0, 144, 144, 143, 143, 143, 144, 146, 146, 146, - 0, 0, 0, 146, 146, 146, 147, 147, 147, 0, - 0, 0, 147, 147, 147, 150, 150, 150, 0, 152, - 152, 150, 150, 150, 152, 153, 153, 153, 0, 0, - 0, 153, 153, 153, 154, 154, 154, 0, 156, 156, - 154, 154, 154, 156, 158, 158, 158, 0, 0, 0, - 158, 158, 158, 159, 159, 159, 0, 0, 0, 159, - 159, 159, 162, 162, 162, 0, 0, 0, 162, 162, - - 162, 163, 163, 163, 0, 0, 0, 163, 163, 163, + 7, 7, 7, 7, 7, 7, 9, 9, 9, 10, + 10, 13, 9, 9, 9, 11, 11, 11, 12, 16, + 14, 11, 11, 11, 14, 15, 13, 17, 25, 12, + 23, 23, 15, 26, 16, 29, 27, 28, 17, 25, + 27, 30, 11, 37, 28, 34, 34, 51, 26, 51, + + 29, 37, 30, 31, 31, 31, 36, 31, 31, 31, + 31, 31, 31, 38, 39, 40, 41, 36, 41, 42, + 46, 41, 40, 38, 45, 39, 47, 45, 50, 52, + 49, 50, 47, 46, 42, 49, 53, 53, 58, 58, + 39, 43, 43, 43, 202, 60, 60, 43, 43, 43, + 44, 44, 44, 62, 62, 52, 44, 44, 44, 48, + 48, 48, 201, 48, 48, 48, 48, 48, 48, 54, + 54, 60, 61, 200, 54, 56, 56, 56, 65, 62, + 65, 56, 56, 56, 57, 57, 57, 61, 66, 66, + 57, 57, 57, 63, 63, 63, 69, 67, 199, 63, + + 63, 63, 64, 71, 71, 76, 76, 198, 75, 197, + 64, 64, 67, 75, 66, 64, 78, 78, 64, 81, + 81, 78, 69, 64, 64, 68, 68, 68, 196, 68, + 68, 68, 68, 68, 68, 70, 70, 70, 82, 82, + 195, 70, 70, 70, 73, 73, 73, 194, 73, 73, + 73, 73, 73, 73, 80, 80, 80, 83, 84, 84, + 80, 80, 80, 86, 91, 91, 94, 193, 86, 102, + 102, 94, 83, 87, 87, 87, 106, 106, 98, 87, + 87, 87, 88, 88, 88, 93, 93, 192, 88, 88, + 88, 89, 89, 89, 191, 89, 89, 89, 89, 89, + + 89, 90, 90, 90, 98, 97, 190, 90, 90, 90, + 97, 93, 95, 95, 95, 114, 95, 95, 95, 95, + 95, 95, 96, 96, 96, 189, 96, 96, 96, 96, + 96, 96, 99, 99, 119, 119, 188, 99, 101, 101, + 101, 114, 136, 136, 101, 101, 101, 104, 104, 104, + 138, 138, 187, 104, 104, 104, 105, 105, 105, 148, + 148, 186, 105, 105, 105, 108, 108, 108, 185, 108, + 108, 108, 108, 108, 108, 110, 110, 110, 151, 151, + 184, 110, 110, 110, 112, 112, 112, 155, 155, 183, + 112, 112, 112, 113, 113, 113, 160, 160, 182, 113, + + 113, 113, 115, 115, 115, 181, 115, 115, 115, 115, + 115, 115, 116, 116, 164, 164, 180, 116, 118, 118, + 118, 166, 166, 179, 118, 118, 118, 121, 121, 121, + 168, 168, 178, 121, 121, 121, 122, 122, 122, 177, + 176, 175, 122, 122, 122, 123, 123, 123, 174, 124, + 124, 123, 123, 123, 124, 126, 126, 126, 173, 172, + 171, 126, 126, 126, 127, 127, 127, 111, 127, 127, + 127, 127, 127, 127, 129, 129, 129, 33, 22, 18, + 129, 129, 129, 130, 130, 130, 6, 130, 130, 130, + 130, 130, 130, 131, 131, 131, 3, 132, 132, 131, + + 131, 131, 132, 134, 134, 134, 1, 0, 0, 134, + 134, 134, 135, 135, 135, 0, 140, 140, 135, 135, + 135, 140, 141, 141, 141, 0, 142, 142, 141, 141, + 141, 142, 143, 143, 143, 0, 144, 144, 143, 143, + 143, 144, 146, 146, 146, 0, 0, 0, 146, 146, + 146, 147, 147, 147, 0, 0, 0, 147, 147, 147, + 150, 150, 150, 0, 152, 152, 150, 150, 150, 152, + 153, 153, 153, 0, 0, 0, 153, 153, 153, 154, + 154, 154, 0, 156, 156, 154, 154, 154, 156, 158, + 158, 158, 0, 0, 0, 158, 158, 158, 159, 159, + + 159, 0, 0, 0, 159, 159, 159, 162, 162, 162, + 0, 0, 0, 162, 162, 162, 163, 163, 163, 0, + 0, 0, 163, 163, 163, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, - 170, 170, 170, 170, 170, 170, 170, 170 + 170, 170, 170, 170 } ; static yy_state_type yy_last_accepting_state; @@ -662,6 +666,7 @@ static char sccsid[] = "@(#)commands.l 5.13 (Berkeley) 7/24/90"; extern char rootServerName[]; extern void PrintHelp(); +extern void ViewList(char *); /* Macros after this point can all be overridden by user definitions in @@ -816,7 +821,7 @@ YY_DECL register char *yy_cp, *yy_bp; register int yy_act; -#line 109 "commands.l" +#line 110 "commands.l" if ( yy_init ) @@ -875,7 +880,7 @@ yy_match: yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } - while ( yy_base[yy_current_state] != 611 ); + while ( yy_base[yy_current_state] != 626 ); yy_find_action: yy_act = yy_accept[yy_current_state]; @@ -906,7 +911,7 @@ case 1: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 110 "commands.l" +#line 111 "commands.l" { /* * 0 == use current server to find @@ -923,7 +928,7 @@ case 2: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 120 "commands.l" +#line 121 "commands.l" { SetDefaultServer(yytext, 1); return(1); @@ -934,7 +939,7 @@ case 3: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 124 "commands.l" +#line 125 "commands.l" { return(0); } @@ -944,7 +949,7 @@ case 4: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 127 "commands.l" +#line 128 "commands.l" { SetDefaultServer(rootServerName, 1); return(1); @@ -955,7 +960,7 @@ case 5: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 131 "commands.l" +#line 132 "commands.l" { /* * 2nd arg. @@ -971,7 +976,7 @@ case 6: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 140 "commands.l" +#line 141 "commands.l" { Finger(yytext, 0); return(1); @@ -982,9 +987,9 @@ case 7: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 144 "commands.l" +#line 145 "commands.l" { - ViewList(yytext); + ViewList((char *)yytext); return(1); } YY_BREAK @@ -993,7 +998,7 @@ case 8: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 148 "commands.l" +#line 149 "commands.l" { /* * 2nd arg. @@ -1009,7 +1014,7 @@ case 9: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 157 "commands.l" +#line 158 "commands.l" { ListHosts(yytext, 0); return(1); @@ -1020,7 +1025,7 @@ case 10: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 161 "commands.l" +#line 162 "commands.l" { /* * 2nd arg. @@ -1036,7 +1041,7 @@ case 11: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 170 "commands.l" +#line 171 "commands.l" { ListHostsByType(yytext, 0); return(1); @@ -1047,7 +1052,7 @@ case 12: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 174 "commands.l" +#line 175 "commands.l" { SetOption(yytext); return(1); @@ -1058,7 +1063,7 @@ case 13: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 178 "commands.l" +#line 179 "commands.l" { PrintHelp(); return(1); @@ -1069,7 +1074,7 @@ case 14: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 182 "commands.l" +#line 183 "commands.l" { extern void PrintHelp(); @@ -1082,7 +1087,7 @@ case 15: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 188 "commands.l" +#line 189 "commands.l" { /* * 0 == output to stdout @@ -1097,7 +1102,7 @@ case 16: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 196 "commands.l" +#line 197 "commands.l" { LookupHost(yytext, 0); return(1); @@ -1108,7 +1113,7 @@ case 17: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 200 "commands.l" +#line 201 "commands.l" { /* * 0 == output to stdout @@ -1123,7 +1128,7 @@ case 18: yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 208 "commands.l" +#line 209 "commands.l" { LookupHostWithServer(yytext, 0); return(1); @@ -1131,14 +1136,14 @@ YY_RULE_SETUP YY_BREAK case 19: YY_RULE_SETUP -#line 212 "commands.l" +#line 213 "commands.l" { return(1); } YY_BREAK case 20: YY_RULE_SETUP -#line 215 "commands.l" +#line 216 "commands.l" { printf("Unrecognized command: %s", yytext); @@ -1147,12 +1152,12 @@ YY_RULE_SETUP YY_BREAK case 21: YY_RULE_SETUP -#line 220 "commands.l" +#line 221 "commands.l" { ; } YY_BREAK case 22: YY_RULE_SETUP -#line 221 "commands.l" +#line 222 "commands.l" ECHO; YY_BREAK case YY_STATE_EOF(INITIAL): @@ -2032,5 +2037,5 @@ int main() return 0; } #endif -#line 221 "commands.l" +#line 222 "commands.l" diff --git a/contrib/bind/bin/nslookup/commands.l b/contrib/bind/bin/nslookup/commands.l index c3a220a..286ae95 100644 --- a/contrib/bind/bin/nslookup/commands.l +++ b/contrib/bind/bin/nslookup/commands.l @@ -100,10 +100,11 @@ static char sccsid[] = "@(#)commands.l 5.13 (Berkeley) 7/24/90"; extern char rootServerName[]; extern void PrintHelp(); +extern void ViewList(char *); %} WS [ \t] -FLET [A-Za-z0-9.*\\] +FLET [A-Za-z0-9.*\\_] LET [A-Za-z0-9.*] NAME [A-Za-z0-9.*=_/-] %% @@ -142,7 +143,7 @@ NAME [A-Za-z0-9.*=_/-] return(1); } ^{WS}*view{WS}+{NAME}+{WS}*$ { - ViewList(yytext); + ViewList((char *)yytext); return(1); } ^{WS}*ls{WS}+(("-a"|"-d"|"-h"|"-m"|"-s"){WS}+)?{LET}{NAME}*{WS}+>>?{WS}+{NAME}+{WS}*$ { diff --git a/contrib/bind/bin/nslookup/debug.c b/contrib/bind/bin/nslookup/debug.c index 76260e0..2448381 100644 --- a/contrib/bind/bin/nslookup/debug.c +++ b/contrib/bind/bin/nslookup/debug.c @@ -52,8 +52,8 @@ */ #ifndef lint -static char sccsid[] = "@(#)debug.c 5.26 (Berkeley) 3/21/91"; -static char rcsid[] = "$Id: debug.c,v 8.11 1998/03/19 19:30:54 halley Exp $"; +static const char sccsid[] = "@(#)debug.c 5.26 (Berkeley) 3/21/91"; +static const char rcsid[] = "$Id: debug.c,v 8.15 1999/10/13 16:39:16 vixie Exp $"; #endif /* not lint */ /* @@ -88,7 +88,6 @@ static char rcsid[] = "$Id: debug.c,v 8.11 1998/03/19 19:30:54 halley Exp $"; /* * Imported from res_debug.c */ -extern char *_res_resultcodes[]; extern char *_res_opcodes[]; /* @@ -119,11 +118,11 @@ Fprint_query(const u_char *msg, const u_char *eom, int printHeader, FILE *file) */ hp = (HEADER *)msg; cp = msg + HFIXEDSZ; - if (printHeader || (_res.options & RES_DEBUG2)) { + if (printHeader || (res.options & RES_DEBUG2)) { fprintf(file," HEADER:\n"); fprintf(file,"\topcode = %s", _res_opcodes[hp->opcode]); fprintf(file,", id = %d", ntohs(hp->id)); - fprintf(file,", rcode = %s\n", _res_resultcodes[hp->rcode]); + fprintf(file,", rcode = %s\n", p_rcode(hp->rcode)); fprintf(file,"\theader flags: "); if (hp->qr) { fprintf(file," response"); @@ -280,9 +279,9 @@ Print_rr(const u_char *ocp, const u_char *msg, const u_char *eom, FILE *file) { NS_GET16(dlen, cp); BOUNDS_CHECK(cp, dlen); - debug = _res.options & (RES_DEBUG|RES_DEBUG2); + debug = res.options & (RES_DEBUG|RES_DEBUG2); if (debug) { - if (_res.options & RES_DEBUG2) + if (res.options & RES_DEBUG2) fprintf(file,"\n\ttype = %s, class = %s, dlen = %d", p_type(type), p_class(class), dlen); if (type == T_SOA) @@ -622,8 +621,9 @@ Print_rr(const u_char *ocp, const u_char *msg, const u_char *eom, FILE *file) { default: { char buf[2048]; /* XXX need to malloc/realloc. */ - if (ns_sprintrrf(msg, eom - msg, "?", class, type, rrttl, - cp1, dlen, NULL, NULL, buf, sizeof buf) < 0) { + if (ns_sprintrrf(msg, eom - msg, "?", (ns_class)class, + (ns_type)type, rrttl, cp1, dlen, NULL, NULL, + buf, sizeof buf) < 0) { perror("ns_sprintrrf"); } else { fprintf(file, @@ -633,7 +633,7 @@ Print_rr(const u_char *ocp, const u_char *msg, const u_char *eom, FILE *file) { cp += dlen; } } - if (_res.options & RES_DEBUG && type != T_SOA) { + if (res.options & RES_DEBUG && type != T_SOA) { fprintf(file,"\tttl = %lu (%s)\n", rrttl, p_time(rrttl)); } if (cp != cp1 + dlen) { diff --git a/contrib/bind/bin/nslookup/getinfo.c b/contrib/bind/bin/nslookup/getinfo.c index 20601e5..6f4ecff 100644 --- a/contrib/bind/bin/nslookup/getinfo.c +++ b/contrib/bind/bin/nslookup/getinfo.c @@ -52,8 +52,8 @@ */ #ifndef lint -static char sccsid[] = "@(#)getinfo.c 5.26 (Berkeley) 3/21/91"; -static char rcsid[] = "$Id: getinfo.c,v 8.11 1998/03/19 19:30:55 halley Exp $"; +static const char sccsid[] = "@(#)getinfo.c 5.26 (Berkeley) 3/21/91"; +static const char rcsid[] = "$Id: getinfo.c,v 8.15 1999/10/13 16:39:16 vixie Exp $"; #endif /* not lint */ /* @@ -82,12 +82,12 @@ static char rcsid[] = "$Id: getinfo.c,v 8.11 1998/03/19 19:30:55 halley Exp $"; #include <resolv.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include "port_after.h" #include "res.h" -extern char *_res_resultcodes[]; extern char *res_skip(); static char *addr_list[MAXADDRS + 1]; @@ -108,7 +108,7 @@ ServerTable server[MAXSERVERS]; typedef union { HEADER qb1; - u_char qb2[PACKETSZ*2]; + u_char qb2[64*1024]; } querybuf; typedef union { @@ -161,10 +161,10 @@ GetAnswer(nsAddrPtr, queryType, msg, msglen, iquery, hostPtr, isServer) int numAliases = 0; int numAddresses = 0; int n, i, j; - int len; int dlen; int status; int numServers; + size_t s; Boolean haveAnswer; Boolean printedAnswers = FALSE; @@ -178,7 +178,7 @@ GetAnswer(nsAddrPtr, queryType, msg, msglen, iquery, hostPtr, isServer) sizeof(answer), &n); if (status != SUCCESS) { - if (_res.options & RES_DEBUG2) + if (res.options & RES_DEBUG2) printf("SendRequest failed\n"); return (status); } @@ -267,11 +267,11 @@ GetAnswer(nsAddrPtr, queryType, msg, msglen, iquery, hostPtr, isServer) continue; } *aliasPtr++ = (char *)bp; - n = strlen((char *)bp) + 1; - host_aliases_len[numAliases] = n; + s = strlen((char *)bp) + 1; + host_aliases_len[numAliases] = s; numAliases++; - bp += n; - buflen -= n; + bp += s; + buflen -= s; continue; } else if (type == T_PTR) { /* @@ -283,9 +283,9 @@ GetAnswer(nsAddrPtr, queryType, msg, msglen, iquery, hostPtr, isServer) continue; } cp += n; - len = strlen((char *)bp) + 1; - hostPtr->name = Calloc(1, len); - memcpy(hostPtr->name, bp, len); + s = strlen((char *)bp) + 1; + hostPtr->name = Calloc(1, s); + memcpy(hostPtr->name, bp, s); haveAnswer = TRUE; break; } else if (type != T_A) { @@ -315,14 +315,14 @@ GetAnswer(nsAddrPtr, queryType, msg, msglen, iquery, hostPtr, isServer) hostPtr->addrLen = dlen; origClass = class; hostPtr->addrType = (class == C_IN) ? AF_INET : AF_UNSPEC; - len = strlen((char *)bp) + 1; - hostPtr->name = Calloc(1, len); - memcpy(hostPtr->name, bp, len); + s = strlen((char *)bp) + 1; + hostPtr->name = Calloc(1, s); + memcpy(hostPtr->name, bp, s); } bp += (((u_int32_t)bp) % sizeof(align)); if (bp + dlen >= &hostbuf[sizeof(hostbuf)]) { - if (_res.options & RES_DEBUG) { + if (res.options & RES_DEBUG) { printf("Size (%d) too big\n", dlen); } break; @@ -416,9 +416,9 @@ GetAnswer(nsAddrPtr, queryType, msg, msglen, iquery, hostPtr, isServer) return(ERROR); } cp += n; - len = strlen((char *)bp) + 1; - dnamePtr = Calloc(1, len); /* domain name */ - memcpy(dnamePtr, bp, len); + s = strlen((char *)bp) + 1; + dnamePtr = Calloc(1, s); /* domain name */ + memcpy(dnamePtr, bp, s); if (cp + 3 * INT16SZ + INT32SZ > eom) return (ERROR); @@ -439,9 +439,9 @@ GetAnswer(nsAddrPtr, queryType, msg, msglen, iquery, hostPtr, isServer) return(ERROR); } cp += n; - len = strlen((char *)bp) + 1; - namePtr = Calloc(1, len); /* server host name */ - memcpy(namePtr, bp, len); + s = strlen((char *)bp) + 1; + namePtr = Calloc(1, s); /* server host name */ + memcpy(namePtr, bp, s); /* * Store the information keyed by the server host name. @@ -578,10 +578,10 @@ GetAnswer(nsAddrPtr, queryType, msg, msglen, iquery, hostPtr, isServer) * Retrieves host name, address and alias information * for a domain. * -* Algorithm from res_search(). +* Algorithm from res_nsearch(). * * Results: -* ERROR - res_mkquery failed. +* ERROR - res_nmkquery failed. * + return values from GetAnswer() * ******************************************************************************* @@ -603,6 +603,7 @@ GetHostInfoByName(nsAddrPtr, queryClass, queryType, name, hostPtr, isServer) Boolean got_nodata = FALSE; struct in_addr ina; Boolean tried_as_is = FALSE; + char tmp[NS_MAXDNAME]; /* Catch explicit addresses */ if ((queryType == T_A) && IsAddr(name, &ina)) { @@ -623,7 +624,7 @@ GetHostInfoByName(nsAddrPtr, queryClass, queryType, name, hostPtr, isServer) for (cp = name, n = 0; *cp; cp++) if (*cp == '.') n++; - if (n == 0 && (cp = hostalias(name))) { + if (n == 0 && (cp = res_hostalias(&res, name, tmp, sizeof tmp))) { printf("Aliased to \"%s\"\n\n", cp); return (GetHostDomain(nsAddrPtr, queryClass, queryType, cp, (char *)NULL, hostPtr, isServer)); @@ -633,7 +634,7 @@ GetHostInfoByName(nsAddrPtr, queryClass, queryType, name, hostPtr, isServer) * If there are dots in the name already, let's just give it a try * 'as is'. The threshold can be set with the "ndots" option. */ - if (n >= (int)_res.ndots) { + if (n >= (int)res.ndots) { result = GetHostDomain(nsAddrPtr, queryClass, queryType, name, (char *)NULL, hostPtr, isServer); if (result == SUCCESS) @@ -649,9 +650,9 @@ GetHostInfoByName(nsAddrPtr, queryClass, queryType, name, hostPtr, isServer) * - there is at least one dot, there is no trailing dot, * and RES_DNSRCH is set. */ - if ((n == 0 && _res.options & RES_DEFNAMES) || - (n != 0 && *--cp != '.' && _res.options & RES_DNSRCH)) - for (domain = _res.dnsrch; *domain; domain++) { + if ((n == 0 && res.options & RES_DEFNAMES) || + (n != 0 && *--cp != '.' && res.options & RES_DNSRCH)) + for (domain = res.dnsrch; *domain; domain++) { result = GetHostDomain(nsAddrPtr, queryClass, queryType, name, *domain, hostPtr, isServer); /* @@ -671,7 +672,7 @@ GetHostInfoByName(nsAddrPtr, queryClass, queryType, name, hostPtr, isServer) if (result == NO_INFO) got_nodata++; if ((result != NXDOMAIN && result != NO_INFO) || - (_res.options & RES_DNSRCH) == 0) + (res.options & RES_DNSRCH) == 0) break; } /* if we have not already tried the name "as is", do that now. @@ -721,11 +722,11 @@ GetHostDomain(nsAddrPtr, queryClass, queryType, name, domain, hostPtr, isServer) MAXDNAME, name, MAXDNAME, domain); longname = nbuf; } - n = res_mkquery(QUERY, longname, queryClass, queryType, - NULL, 0, 0, buf.qb2, sizeof(buf)); + n = res_nmkquery(&res, QUERY, longname, queryClass, queryType, + NULL, 0, 0, buf.qb2, sizeof(buf)); if (n < 0) { - if (_res.options & RES_DEBUG) { - printf("Res_mkquery failed\n"); + if (res.options & RES_DEBUG) { + printf("Res_nmkquery failed\n"); } return (ERROR); } @@ -737,7 +738,8 @@ GetHostDomain(nsAddrPtr, queryClass, queryType, name, domain, hostPtr, isServer) */ if (n == NONAUTH) { if (hostPtr->name == NULL) { - int len = strlen(longname) + 1; + size_t len = strlen(longname) + 1; + hostPtr->name = Calloc(len, sizeof(char)); memcpy(hostPtr->name, longname, len); } @@ -755,7 +757,7 @@ GetHostDomain(nsAddrPtr, queryClass, queryType, name, domain, hostPtr, isServer) * that corresponds to the given address. * * Results: -* ERROR - res_mkquery failed. +* ERROR - res_nmkquery failed. * + return values from GetAnswer() * ******************************************************************************* @@ -777,11 +779,11 @@ GetHostInfoByAddr(nsAddrPtr, address, hostPtr) ((unsigned)p[2] & 0xff), ((unsigned)p[1] & 0xff), ((unsigned)p[0] & 0xff)); - n = res_mkquery(QUERY, qbuf, C_IN, T_PTR, NULL, 0, NULL, - buf.qb2, sizeof buf); + n = res_nmkquery(&res, QUERY, qbuf, C_IN, T_PTR, NULL, 0, NULL, + buf.qb2, sizeof buf); if (n < 0) { - if (_res.options & RES_DEBUG) { - printf("res_mkquery() failed\n"); + if (res.options & RES_DEBUG) { + printf("res_nmkquery() failed\n"); } return (ERROR); } diff --git a/contrib/bind/bin/nslookup/list.c b/contrib/bind/bin/nslookup/list.c index 6d23e57..1b7f452 100644 --- a/contrib/bind/bin/nslookup/list.c +++ b/contrib/bind/bin/nslookup/list.c @@ -52,8 +52,8 @@ */ #ifndef lint -static char sccsid[] = "@(#)list.c 5.23 (Berkeley) 3/21/91"; -static char rcsid[] = "$Id: list.c,v 8.13 1997/11/18 00:32:33 halley Exp $"; +static const char sccsid[] = "@(#)list.c 5.23 (Berkeley) 3/21/91"; +static const char rcsid[] = "$Id: list.c,v 8.21 1999/10/15 19:49:08 vixie Exp $"; #endif /* not lint */ /* @@ -91,7 +91,6 @@ static char rcsid[] = "$Id: list.c,v 8.13 1997/11/18 00:32:33 halley Exp $"; #include "res.h" -extern char *_res_resultcodes[]; /* res_debug.c */ extern char *pager; typedef union { @@ -151,14 +150,28 @@ int ListSubr(); void ListHostsByType(char *string, int putToFile) { char *namePtr, name[NAME_LEN], option[NAME_LEN]; - int i, qtype, result; + int i, j, qtype, result; /* * Parse the command line. It maybe of the form "ls -t domain" * or "ls -t type domain". */ - i = sscanf(string, " ls -t %s %s", option, name); + /* simulate sscanf(string, " ls -t %s %s", option, name) */ + i = matchString(" ls -t ", string); + if (i > 0) { + j = pickString(string + i, option, sizeof option); + if (j > 0) { + j = pickString(string + i + j, name, sizeof name); + if (j > 0) + i = 2; + else + i = 1; + } else { + i = 0; + } + } + if (putToFile && i == 2 && name[0] == '>') i--; if (i == 2) { @@ -182,13 +195,28 @@ ListHostsByType(char *string, int putToFile) { void ListHosts(char *string, int putToFile) { char *namePtr, name[NAME_LEN], option[NAME_LEN]; - int i, qtype, result; + int i, j, qtype, result; /* * Parse the command line. It maybe of the form "ls domain", * "ls -X domain". */ - i = sscanf(string, " ls %s %s", option, name); + + /* simulate i = sscanf(string, " ls %s %s", option, name) */ + i = matchString(" ls ", string); + if (i > 0) { + j = pickString(string + i, option, sizeof option); + if (j > 0) { + j = pickString(string + i + j, name, sizeof name); + if (j > 0) + i = 2; + else + i = 1; + } else { + i = 0; + } + } + if (putToFile && i == 2 && name[0] == '>') i--; if (i == 2) { @@ -236,18 +264,18 @@ ListSubr(int qtype, char *domain, char *cmd) { int numAnswers = 0; int numRecords = 0; u_char tmp[INT16SZ], *cp; - char soaname[2][NAME_LEN], file[NAME_LEN]; + char soaname[2][NAME_LEN], file[PATH_MAX]; enum { NO_ERRORS, ERR_READING_LEN, ERR_READING_MSG, ERR_PRINTING } error = NO_ERRORS; /* * Create a query packet for the requested domain name. */ - msglen = res_mkquery(QUERY, domain, queryClass, T_AXFR, - NULL, 0, 0, buf.qb2, sizeof buf); + msglen = res_nmkquery(&res, QUERY, domain, queryClass, T_AXFR, + NULL, 0, 0, buf.qb2, sizeof buf); if (msglen < 0) { if (_res.options & RES_DEBUG) - fprintf(stderr, "*** ls: res_mkquery failed\n"); + fprintf(stderr, "*** ls: res_nmkquery failed\n"); return (ERROR); } @@ -308,7 +336,7 @@ ListSubr(int qtype, char *domain, char *cmd) { if (cmd == NULL) { filePtr = stdout; } else { - filePtr = OpenFile(cmd, file); + filePtr = OpenFile(cmd, file, sizeof file); if (filePtr == NULL) { fprintf(stderr, "*** Can't open %s for writing\n", file); @@ -405,7 +433,7 @@ ListSubr(int qtype, char *domain, char *cmd) { break; } strcpy(name_ctx, name); - numAnswers++; + numRecords++; fputs(buf, filePtr); fputc('\n', filePtr); } @@ -413,9 +441,13 @@ ListSubr(int qtype, char *domain, char *cmd) { strcpy(soaname[soacnt], name); if (soacnt == 0) soacnt = 1; - else if (strcasecmp(soaname[0], - soaname[1]) == 0) { + else if (ns_samename(soaname[0], + soaname[1]) == 1) { soacnt = 2; + /* This means we're finished. + * But we've to reset origin and + * name_ctx now ! */ + origin[0] = name_ctx[0] ='\0'; } } } @@ -456,7 +488,7 @@ ListSubr(int qtype, char *domain, char *cmd) { fprintf(stderr,"*** ls: error receiving zone transfer:\n"); fprintf(stderr, " result: %s, answers = %d, authority = %d, additional = %d\n", - _res_resultcodes[headerPtr->rcode], + p_rcode(headerPtr->rcode), ntohs(headerPtr->ancount), ntohs(headerPtr->nscount), ntohs(headerPtr->arcount)); return (ERROR); @@ -476,14 +508,46 @@ ListSubr(int qtype, char *domain, char *cmd) { ******************************************************************************* */ -ViewList(string) - char *string; -{ +void +ViewList(char *string) { char file[PATH_MAX]; char command[PATH_MAX]; + int i, j; + char soafile[PATH_MAX]; + + /* sscanf(string, " view %s", file); */ + i = matchString(" view ", string); + if (i > 0) { + j = pickString(string + i, file, sizeof file); + if (j == 0) { + fprintf(stderr, "*** invalid file name: %s\n", string + i); + return ; + } + } - sscanf(string, " view %s", file); - (void)sprintf(command, "grep \"^ \" %s | sort | %s", file, pager); + if ( !mktemp(strcpy(soafile,"/var/tmp/nslookup_tmpXXXXXX"))) { + fprintf(stderr, "*** cannot create temp file\n"); + return ; + } + (void)sprintf(command, "sed '\ +/^$/,${\ +/@/,$d\ +}\ +/^[^ ]/{\ +h\ +s/^\\([^ ]* *\\).*/\\1/\ +x\ +}\ +1,/^$/{\ +w %s\ +d\ +}\ +/^ /{\ +G\ +s/^ *//\ +s/^\\(.*\\)\\n\\(.*\\)$/\\2\\1/\ +}' %s | sort | (cat %s -; rm %s) | %s", + soafile, file, soafile, soafile, pager); system(command); } @@ -515,7 +579,8 @@ Finger(string, putToFile) int c; int lastc; char name[NAME_LEN]; - char file[NAME_LEN]; + char file[PATH_MAX]; + int i; /* * We need a valid current host info to get an inet address. @@ -525,7 +590,20 @@ Finger(string, putToFile) return (ERROR); } - if (sscanf(string, " finger %s", name) == 1) { + /* simulate: sscanf("finger %s") ; */ + + i = matchString(" finger ", string); + if (i > 0) { + i = pickString(string + i, name, sizeof name); + if (i > 0) { + i = 1 ; + } + /* note that if the argument to the finger command is + bigger than sizeof name it will be treated as if there + was no argument. */ + } + + if (i == 1) { if (putToFile && (name[0] == '>')) { name[0] = '\0'; } @@ -566,7 +644,7 @@ Finger(string, putToFile) if (!putToFile) { filePtr = stdout; } else { - filePtr = OpenFile(string, file); + filePtr = OpenFile(string, file, sizeof file); if (filePtr == NULL) { fprintf(stderr, "*** Can't open %s for writing\n", file); close(sockFD); @@ -613,6 +691,7 @@ Finger(string, putToFile) return (SUCCESS); } +void ListHost_close() { if (sockFD != -1) { diff --git a/contrib/bind/bin/nslookup/main.c b/contrib/bind/bin/nslookup/main.c index 3c97afe..d36c0f4 100644 --- a/contrib/bind/bin/nslookup/main.c +++ b/contrib/bind/bin/nslookup/main.c @@ -51,15 +51,33 @@ * 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. + */ + #ifndef lint char copyright[] = "@(#) Copyright (c) 1985,1989 Regents of the University of California.\n\ - All rights reserved.\n"; + All rights reserved.\n\ + @(#) Portions Copyright (c) 1996-1999 Internet Software Consortium.\n"; #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)main.c 5.42 (Berkeley) 3/3/91"; -static char rcsid[] = "$Id: main.c,v 8.7 1997/04/25 00:27:18 vixie Exp $"; +static const char sccsid[] = "@(#)main.c 5.42 (Berkeley) 3/3/91"; +static const char rcsid[] = "$Id: main.c,v 8.13 1999/10/13 16:39:19 vixie Exp $"; #endif /* not lint */ /* @@ -113,10 +131,10 @@ static char rcsid[] = "$Id: main.c,v 8.7 1997/04/25 00:27:18 vixie Exp $"; char rootServerName[NAME_LEN] = ROOT_SERVER; /* - * Import the state information from the resolver library. + * Declare a resolver context. */ -extern struct __res_state _res; +struct __res_state res; /* @@ -160,6 +178,13 @@ char *pager; static void CvtAddrToPtr(); static void ReadRC(); +/* + * Forward declarations. + */ +void LocalServer(HostInfo *defaultPtr); +void res_re_init(void); +void res_dnsrch(char *cp); + /* ****************************************************************************** @@ -187,7 +212,7 @@ main(argc, argv) * Initialize the resolver library routines. */ - if (res_init() == -1) { + if (res_ninit(&res) == -1) { fprintf(stderr,"*** Can't initialize resolver.\n"); exit(1); } @@ -245,8 +270,8 @@ main(argc, argv) */ if (inet_aton(*++argv, &addr)) { - _res.nscount = 1; - _res.nsaddr.sin_addr = addr; + res.nscount = 1; + res.nsaddr.sin_addr = addr; } else { hp = gethostbyname(*argv); if (hp == NULL) { @@ -256,33 +281,33 @@ main(argc, argv) fputc('\n', stderr); } else { for (i = 0; i < MAXNS && hp->h_addr_list[i] != NULL; i++) { - memcpy(&_res.nsaddr_list[i].sin_addr, hp->h_addr_list[i], + memcpy(&res.nsaddr_list[i].sin_addr, hp->h_addr_list[i], hp->h_length); } - _res.nscount = i; + res.nscount = i; } } } - if (_res.nscount == 0 || useLocalServer) { + if (res.nscount == 0 || useLocalServer) { LocalServer(defaultPtr); } else { - for (i = 0; i < _res.nscount; i++) { - if (_res.nsaddr_list[i].sin_addr.s_addr == INADDR_ANY) { + for (i = 0; i < res.nscount; i++) { + if (res.nsaddr_list[i].sin_addr.s_addr == INADDR_ANY) { LocalServer(defaultPtr); break; } else { - result = GetHostInfoByAddr(&(_res.nsaddr_list[i].sin_addr), - &(_res.nsaddr_list[i].sin_addr), + result = GetHostInfoByAddr(&(res.nsaddr_list[i].sin_addr), + &(res.nsaddr_list[i].sin_addr), defaultPtr); if (result != SUCCESS) { fprintf(stderr, "*** Can't find server name for address %s: %s\n", - inet_ntoa(_res.nsaddr_list[i].sin_addr), + inet_ntoa(res.nsaddr_list[i].sin_addr), DecodeError(result)); } else { - defaultAddr = _res.nsaddr_list[i].sin_addr; + defaultAddr = res.nsaddr_list[i].sin_addr; break; } } @@ -293,7 +318,7 @@ main(argc, argv) * command line argument to specify an address. */ - if (i == _res.nscount) { + if (i == res.nscount) { fprintf(stderr, "*** Default servers are not available\n"); exit(1); } @@ -304,10 +329,10 @@ main(argc, argv) #ifdef DEBUG #ifdef DEBUG2 - _res.options |= RES_DEBUG2; + res.options |= RES_DEBUG2; #endif - _res.options |= RES_DEBUG; - _res.retry = 2; + res.options |= RES_DEBUG; + res.retry = 2; #endif /* DEBUG */ /* @@ -355,6 +380,7 @@ main(argc, argv) } +void LocalServer(defaultPtr) HostInfo *defaultPtr; { @@ -464,6 +490,7 @@ SetDefaultServer(string, local) char newServer[NAME_LEN]; int result; int i; + int j; /* * Parse the command line. It maybe of the form "server name", @@ -471,13 +498,32 @@ SetDefaultServer(string, local) */ if (local) { - i = sscanf(string, " lserver %s", newServer); + i = matchString (" lserver ", string); + if (i > 0) { + j = pickString(string + i, newServer, sizeof newServer); + if (j == 0) { /* value was too big for newServer variable */ + fprintf(stderr, + "SetDefaultServer: invalid name: %s\n", + string + i); + return(ERROR); + } + } } else { - i = sscanf(string, " server %s", newServer); + i = matchString(" server ", string); + if (i > 0) { + j = pickString(string + i, newServer, sizeof newServer); + if (j == 0) { /* value was too big for newServer variable */ + fprintf(stderr, + "SetDefaultServer: invalid name: %s\n", + string + i); + return(ERROR); + } + } } - if (i != 1) { - i = sscanf(string, " %s", newServer); - if (i != 1) { + + if (i == 0) { + i = pickString(string, newServer, sizeof newServer); + if (i == 0) { /* value was too big for newServer variable */ fprintf(stderr,"SetDefaultServer: invalid name: %s\n", string); return(ERROR); } @@ -667,6 +713,7 @@ LookupHost(string, putToFile) char host[NAME_LEN]; char file[PATH_MAX]; int result; + int i; /* * Invalidate the current host information to prevent Finger @@ -681,11 +728,16 @@ LookupHost(string, putToFile) * */ - sscanf(string, " %s", host); /* removes white space */ + i = pickString(string, host, sizeof host); + if (i == 0) { /* string was too long for host variable */ + fprintf(stderr, "*** invalid name: %s\n", string); + return(ERROR); + } + if (!putToFile) { filePtr = stdout; } else { - filePtr = OpenFile(string, file); + filePtr = OpenFile(string, file, sizeof file); if (filePtr == NULL) { fprintf(stderr, "*** Can't open %s for writing\n", file); return(ERROR); @@ -739,14 +791,27 @@ LookupHostWithServer(string, putToFile) char server[NAME_LEN]; int result; static HostInfo serverInfo; + int i; + int j; curHostValid = FALSE; - sscanf(string, " %s %s", host, server); + i = pickString(string, host, sizeof host); + if (i == 0) { /* value was too big for host variable */ + fprintf(stderr, "*** invalid name: %s\n", string); + return(ERROR); + } + + j = pickString(string + i, server, sizeof server); + if (j == 0) { /* value was too big for server variable */ + fprintf(stderr, "*** invalid server name: %s\n", string + i); + return(ERROR); + } + if (!putToFile) { filePtr = stdout; } else { - filePtr = OpenFile(string, file); + filePtr = OpenFile(string, file, sizeof file); if (filePtr == NULL) { fprintf(stderr, "*** Can't open %s for writing\n", file); return(ERROR); @@ -823,6 +888,7 @@ SetOption(option) char type[NAME_LEN]; char *ptr; int tmp; + int i; while (isspace(*option)) ++option; @@ -840,28 +906,34 @@ SetOption(option) } else if (strncmp(option, "ALL", 3) == 0) { ShowOptions(); } else if (strncmp(option, "d2", 2) == 0) { /* d2 (more debug) */ - _res.options |= (RES_DEBUG | RES_DEBUG2); + res.options |= (RES_DEBUG | RES_DEBUG2); } else if (strncmp(option, "nod2", 4) == 0) { - _res.options &= ~RES_DEBUG2; + res.options &= ~RES_DEBUG2; printf("d2 mode disabled; still in debug mode\n"); } else if (strncmp(option, "def", 3) == 0) { /* defname */ - _res.options |= RES_DEFNAMES; + res.options |= RES_DEFNAMES; } else if (strncmp(option, "nodef", 5) == 0) { - _res.options &= ~RES_DEFNAMES; + res.options &= ~RES_DEFNAMES; } else if (strncmp(option, "do", 2) == 0) { /* domain */ ptr = strchr(option, '='); if (ptr != NULL) { - sscanf(++ptr, "%s", _res.defdname); + i = pickString(++ptr, res.defdname, sizeof res.defdname); + if (i == 0) { /* name too long or nothing there */ + fprintf(stderr, "** invalid 'domain' value: %s\n", + ptr) ; + return(ERROR); + } + res_re_init(); } } else if (strncmp(option, "deb", 1) == 0) { /* debug */ - _res.options |= RES_DEBUG; + res.options |= RES_DEBUG; } else if (strncmp(option, "nodeb", 5) == 0) { - _res.options &= ~(RES_DEBUG | RES_DEBUG2); + res.options &= ~(RES_DEBUG | RES_DEBUG2); } else if (strncmp(option, "ig", 2) == 0) { /* ignore */ - _res.options |= RES_IGNTC; + res.options |= RES_IGNTC; } else if (strncmp(option, "noig", 4) == 0) { - _res.options &= ~RES_IGNTC; + res.options &= ~RES_IGNTC; } else if (strncmp(option, "po", 2) == 0) { /* port */ ptr = strchr(option, '='); if (ptr != NULL) { @@ -869,44 +941,61 @@ SetOption(option) } #ifdef deprecated } else if (strncmp(option, "pri", 3) == 0) { /* primary */ - _res.options |= RES_PRIMARY; + res.options |= RES_PRIMARY; } else if (strncmp(option, "nopri", 5) == 0) { - _res.options &= ~RES_PRIMARY; + res.options &= ~RES_PRIMARY; #endif } else if (strncmp(option, "q", 1) == 0 || /* querytype */ strncmp(option, "ty", 2) == 0) { /* type */ ptr = strchr(option, '='); if (ptr != NULL) { - sscanf(++ptr, "%s", type); + i = pickString(++ptr, type, sizeof type); + if (i == 0) { /* value too big or nothing there */ + fprintf(stderr, "*** invalid type value: %s\n", + ptr) ; + return(ERROR); + } + queryType = StringToType(type, queryType, stderr); } } else if (strncmp(option, "cl", 2) == 0) { /* query class */ ptr = strchr(option, '='); if (ptr != NULL) { - sscanf(++ptr, "%s", type); + i = pickString(++ptr, type, sizeof type); + if (i == 0) { /* value too big or nothing there */ + fprintf(stderr, "*** invalid class : %s\n", + ptr) ; + return(ERROR); + } + queryClass = StringToClass(type, queryClass, stderr); } } else if (strncmp(option, "rec", 3) == 0) { /* recurse */ - _res.options |= RES_RECURSE; + res.options |= RES_RECURSE; } else if (strncmp(option, "norec", 5) == 0) { - _res.options &= ~RES_RECURSE; + res.options &= ~RES_RECURSE; } else if (strncmp(option, "ret", 3) == 0) { /* retry */ ptr = strchr(option, '='); if (ptr != NULL) { sscanf(++ptr, "%d", &tmp); if (tmp >= 0) { - _res.retry = tmp; + res.retry = tmp; } } } else if (strncmp(option, "ro", 2) == 0) { /* root */ ptr = strchr(option, '='); if (ptr != NULL) { - sscanf(++ptr, "%s", rootServerName); + i = pickString(++ptr, rootServerName, sizeof rootServerName); + if (i == 0) { /* value too big or nothing there */ + fprintf(stderr, "*** invalid root server name : %s\n", + ptr) ; + return(ERROR) ; + } } } else if (strncmp(option, "sea", 3) == 0) { /* search list */ - _res.options |= RES_DNSRCH; + res.options |= RES_DNSRCH; } else if (strncmp(option, "nosea", 5) == 0) { - _res.options &= ~RES_DNSRCH; + res.options &= ~RES_DNSRCH; } else if (strncmp(option, "srchl", 5) == 0) { /* domain search list */ ptr = strchr(option, '='); if (ptr != NULL) { @@ -917,13 +1006,13 @@ SetOption(option) if (ptr != NULL) { sscanf(++ptr, "%d", &tmp); if (tmp >= 0) { - _res.retrans = tmp; + res.retrans = tmp; } } } else if (strncmp(option, "v", 1) == 0) { /* vc */ - _res.options |= RES_USEVC; + res.options |= RES_USEVC; } else if (strncmp(option, "nov", 3) == 0) { - _res.options &= ~RES_USEVC; + res.options &= ~RES_USEVC; } else { fprintf(stderr, "*** Invalid option: %s\n", option); return(ERROR); @@ -935,45 +1024,45 @@ SetOption(option) /* * Fake a reinitialization when the domain is changed. */ -res_re_init() -{ +void +res_re_init(void) { register char *cp, **pp; int n; /* find components of local domain that might be searched */ - pp = _res.dnsrch; - *pp++ = _res.defdname; - for (cp = _res.defdname, n = 0; *cp; cp++) + pp = res.dnsrch; + *pp++ = res.defdname; + for (cp = res.defdname, n = 0; *cp; cp++) if (*cp == '.') n++; - cp = _res.defdname; - for (; n >= LOCALDOMAINPARTS && pp < _res.dnsrch + MAXDFLSRCH; n--) { + cp = res.defdname; + for (; n >= LOCALDOMAINPARTS && pp < res.dnsrch + MAXDFLSRCH; n--) { cp = strchr(cp, '.'); *pp++ = ++cp; } *pp = 0; - _res.options |= RES_INIT; + res.options |= RES_INIT; } #define SRCHLIST_SEP '/' -res_dnsrch(cp) - register char *cp; -{ - register char **pp; +void +res_dnsrch(char *cp) { + char **pp; int n; - (void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1); - if ((cp = strchr(_res.defdname, '\n')) != NULL) + (void)strncpy(res.defdname, cp, sizeof(res.defdname) - 1); + res.defdname[sizeof(res.defdname) - 1] = '\0'; + if ((cp = strchr(res.defdname, '\n')) != NULL) *cp = '\0'; /* * Set search list to be blank-separated strings * on rest of line. */ - cp = _res.defdname; - pp = _res.dnsrch; + cp = res.defdname; + pp = res.dnsrch; *pp++ = cp; - for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) { + for (n = 0; *cp && pp < res.dnsrch + MAXDNSRCH; cp++) { if (*cp == SRCHLIST_SEP) { *cp = '\0'; n = 1; @@ -1011,24 +1100,24 @@ ShowOptions() } printf("Set options:\n"); - printf(" %sdebug \t", (_res.options & RES_DEBUG) ? "" : "no"); - printf(" %sdefname\t", (_res.options & RES_DEFNAMES) ? "" : "no"); - printf(" %ssearch\t", (_res.options & RES_DNSRCH) ? "" : "no"); - printf(" %srecurse\n", (_res.options & RES_RECURSE) ? "" : "no"); - - printf(" %sd2\t\t", (_res.options & RES_DEBUG2) ? "" : "no"); - printf(" %svc\t\t", (_res.options & RES_USEVC) ? "" : "no"); - printf(" %signoretc\t", (_res.options & RES_IGNTC) ? "" : "no"); + printf(" %sdebug \t", (res.options & RES_DEBUG) ? "" : "no"); + printf(" %sdefname\t", (res.options & RES_DEFNAMES) ? "" : "no"); + printf(" %ssearch\t", (res.options & RES_DNSRCH) ? "" : "no"); + printf(" %srecurse\n", (res.options & RES_RECURSE) ? "" : "no"); + + printf(" %sd2\t\t", (res.options & RES_DEBUG2) ? "" : "no"); + printf(" %svc\t\t", (res.options & RES_USEVC) ? "" : "no"); + printf(" %signoretc\t", (res.options & RES_IGNTC) ? "" : "no"); printf(" port=%u\n", nsport); printf(" querytype=%s\t", p_type(queryType)); printf(" class=%s\t", p_class(queryClass)); - printf(" timeout=%d\t", _res.retrans); - printf(" retry=%d\n", _res.retry); + printf(" timeout=%d\t", res.retrans); + printf(" retry=%d\n", res.retry); printf(" root=%s\n", rootServerName); - printf(" domain=%s\n", _res.defdname); + printf(" domain=%s\n", res.defdname); - cp = _res.dnsrch; + cp = res.dnsrch; if (cp != NULL) { printf(" srchlist=%s", *cp); for (cp++; *cp; cp++) { @@ -1076,7 +1165,7 @@ static void CvtAddrToPtr(name) char *name; { - char *p; + const char *p; int ip[4]; struct in_addr addr; diff --git a/contrib/bind/bin/nslookup/res.h b/contrib/bind/bin/nslookup/res.h index cffbe3c..5ffd6ce 100644 --- a/contrib/bind/bin/nslookup/res.h +++ b/contrib/bind/bin/nslookup/res.h @@ -55,7 +55,7 @@ /* * @(#)res.h 5.10 (Berkeley) 6/1/90 - * $Id: res.h,v 8.4 1996/12/04 09:38:59 vixie Exp $ + * $Id: res.h,v 8.5 1998/09/16 17:03:17 vixie Exp $ */ /* @@ -156,6 +156,11 @@ extern FILE *filePtr; extern unsigned short nsport; /* + * Our resolver context. + */ +extern struct __res_state res; + +/* * External routines: */ diff --git a/contrib/bind/bin/nslookup/send.c b/contrib/bind/bin/nslookup/send.c index e9ca590..61a8751 100644 --- a/contrib/bind/bin/nslookup/send.c +++ b/contrib/bind/bin/nslookup/send.c @@ -52,8 +52,8 @@ */ #ifndef lint -static char sccsid[] = "@(#)send.c 5.18 (Berkeley) 3/2/91"; -static char rcsid[] = "$Id: send.c,v 8.6 1997/05/21 19:49:58 halley Exp $"; +static const char sccsid[] = "@(#)send.c 5.18 (Berkeley) 3/2/91"; +static const char rcsid[] = "$Id: send.c,v 8.9 1999/10/13 16:39:19 vixie Exp $"; #endif /* not lint */ /* @@ -95,18 +95,6 @@ static char rcsid[] = "$Id: send.c,v 8.6 1997/05/21 19:49:58 halley Exp $"; static int s = -1; /* socket used for communications */ - -#ifndef FD_SET -#define NFDBITS 32 -#define FD_SETSIZE 32 -#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) -#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) -#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) -#define FD_ZERO(p) memset((p), 0, sizeof(*(p))) -#endif - - - unsigned short nsport = NAMESERVER_PORT; @@ -148,19 +136,19 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen, char junk[512]; struct sockaddr_in sin, sa; - if (_res.options & RES_DEBUG2) { + if (res.options & RES_DEBUG2) { printf("------------\nSendRequest(), len %d\n", buflen); Print_query(buf, buf + buflen, 1); } sin.sin_family = AF_INET; sin.sin_port = htons(nsport); sin.sin_addr = *nsAddrPtr; - v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; + v_circuit = (res.options & RES_USEVC) || buflen > PACKETSZ; id = hp->id; /* * Send request, RETRY times, or until successful */ - for (try = 0; try < _res.retry; try++) { + for (try = 0; try < res.retry; try++) { usevc: if (v_circuit) { int truncated = 0; @@ -169,19 +157,19 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen, * Use virtual circuit; * at most one attempt per server. */ - try = _res.retry; + try = res.retry; if (s < 0) { s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) { terrno = errno; - if (_res.options & RES_DEBUG) + if (res.options & RES_DEBUG) perror("socket (vc) failed"); continue; } if (connect(s, (struct sockaddr *)&sin, sizeof(struct sockaddr)) < 0) { terrno = errno; - if (_res.options & RES_DEBUG) + if (res.options & RES_DEBUG) perror("connect failed"); (void) close(s); s = -1; @@ -198,7 +186,7 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen, iov[1].iov_len = buflen; if (writev(s, iov, 2) != INT16SZ + buflen) { terrno = errno; - if (_res.options & RES_DEBUG) + if (res.options & RES_DEBUG) perror("write failed"); (void) close(s); s = -1; @@ -216,7 +204,7 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen, } if (n <= 0) { terrno = errno; - if (_res.options & RES_DEBUG) + if (res.options & RES_DEBUG) perror("read failed"); (void) close(s); s = -1; @@ -236,7 +224,7 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen, } cp = answer; if ((resplen = ns_get16((u_char*)cp)) > anslen) { - if (_res.options & RES_DEBUG) + if (res.options & RES_DEBUG) fprintf(stderr, "response truncated\n"); len = anslen; truncated = 1; @@ -249,7 +237,7 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen, } if (n <= 0) { terrno = errno; - if (_res.options & RES_DEBUG) + if (res.options & RES_DEBUG) perror("read failed"); (void) close(s); s = -1; @@ -279,7 +267,7 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen, s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { terrno = errno; - if (_res.options & RES_DEBUG) + if (res.options & RES_DEBUG) perror("socket (dg) failed"); continue; } @@ -288,14 +276,14 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen, if (connected == 0) { if (connect(s, (struct sockaddr *)&sin, sizeof sin) < 0) { - if (_res.options & RES_DEBUG) + if (res.options & RES_DEBUG) perror("connect"); continue; } connected = 1; } if (send(s, buf, buflen, 0) != buflen) { - if (_res.options & RES_DEBUG) + if (res.options & RES_DEBUG) perror("send"); continue; } @@ -303,7 +291,7 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen, if (sendto(s, (const char *)buf, buflen, 0, (struct sockaddr *) &sin, sizeof sin) != buflen) { - if (_res.options & RES_DEBUG) + if (res.options & RES_DEBUG) perror("sendto"); continue; } @@ -312,7 +300,7 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen, /* * Wait for reply */ - timeout.tv_sec = (_res.retrans << try); + timeout.tv_sec = (res.retrans << try); if (timeout.tv_sec <= 0) timeout.tv_sec = 1; timeout.tv_usec = 0; @@ -322,7 +310,7 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen, n = select(s+1, &dsmask, (fd_set *)NULL, (fd_set *)NULL, &timeout); if (n < 0) { - if (_res.options & RES_DEBUG) + if (res.options & RES_DEBUG) perror("select"); continue; } @@ -330,7 +318,7 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen, /* * timeout */ - if (_res.options & RES_DEBUG) + if (res.options & RES_DEBUG) printf("timeout\n"); #if BSD >= 43 gotsomewhere = 1; @@ -342,7 +330,7 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen, resplen = recvfrom(s, (char *)answer, anslen, 0, (struct sockaddr *)&sa, &salen); if (resplen <= 0) { - if (_res.options & RES_DEBUG) + if (res.options & RES_DEBUG) perror("recvfrom"); continue; } @@ -351,18 +339,18 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen, /* * response from old query, ignore it */ - if (_res.options & RES_DEBUG2) { + if (res.options & RES_DEBUG2) { printf("------------\nOld answer:\n"); Print_query(answer, answer+resplen, 1); } goto wait; } - if (!(_res.options & RES_IGNTC) && anhp->tc) { + if (!(res.options & RES_IGNTC) && anhp->tc) { /* * get rest of answer; * use TCP with same server. */ - if (_res.options & RES_DEBUG) + if (res.options & RES_DEBUG) printf("truncated answer\n"); (void) close(s); s = -1; @@ -370,8 +358,8 @@ SendRequest(struct in_addr *nsAddrPtr, const u_char *buf, int buflen, goto usevc; } } - if (_res.options & RES_DEBUG) { - if (_res.options & RES_DEBUG2) + if (res.options & RES_DEBUG) { + if (res.options & RES_DEBUG2) printf("------------\nGot answer (%d bytes):\n", resplen); else diff --git a/contrib/bind/bin/nslookup/skip.c b/contrib/bind/bin/nslookup/skip.c index 0290d98..5318ef6 100644 --- a/contrib/bind/bin/nslookup/skip.c +++ b/contrib/bind/bin/nslookup/skip.c @@ -52,8 +52,8 @@ */ #ifndef lint -static char sccsid[] = "@(#)skip.c 5.12 (Berkeley) 3/21/91"; -static char rcsid[] = "$Id: skip.c,v 8.4 1997/04/25 00:27:19 vixie Exp $"; +static const char sccsid[] = "@(#)skip.c 5.12 (Berkeley) 3/21/91"; +static const char rcsid[] = "$Id: skip.c,v 8.5 1999/10/13 16:39:20 vixie Exp $"; #endif /* not lint */ /* diff --git a/contrib/bind/bin/nslookup/subr.c b/contrib/bind/bin/nslookup/subr.c index cefc2eb..a3b9f96 100644 --- a/contrib/bind/bin/nslookup/subr.c +++ b/contrib/bind/bin/nslookup/subr.c @@ -52,8 +52,8 @@ */ #ifndef lint -static char sccsid[] = "@(#)subr.c 5.24 (Berkeley) 3/2/91"; -static char rcsid[] = "$Id: subr.c,v 8.9 1997/04/25 00:27:19 vixie Exp $"; +static const char sccsid[] = "@(#)subr.c 5.24 (Berkeley) 3/2/91"; +static const char rcsid[] = "$Id: subr.c,v 8.13 1999/10/13 16:39:20 vixie Exp $"; #endif /* not lint */ /* @@ -126,6 +126,7 @@ IntrHandler() extern FILE *yyin; /* scanner input file */ extern void yyrestart(); /* routine to restart scanner after interrupt */ #endif + extern void ListHost_close(void); SendRequest_close(); ListHost_close(); @@ -204,9 +205,8 @@ Malloc(size) fflush(stderr); abort(); /*NOTREACHED*/ - } else { - return(ptr); } + return (ptr); } char * @@ -324,7 +324,8 @@ PrintHostInfo(file, title, hp) * OpenFile -- * * Parses a command string for a file name and opens - * the file. + * the file. The file name is copued to the argument FILE. The + * parameter SIZE parameter includes space for a null byte. * * Results: * file pointer - the open was successful. @@ -335,12 +336,14 @@ PrintHostInfo(file, title, hp) */ FILE * -OpenFile(string, file) +OpenFile(string, file, size) char *string; char *file; + size_t size; { char *redirect; FILE *tmpPtr; + int i; /* * Open an output file if we see '>' or >>'. @@ -351,12 +354,18 @@ OpenFile(string, file) if (redirect == NULL) { return(NULL); } + + tmpPtr = NULL; if (redirect[1] == '>') { - sscanf(redirect, ">> %s", file); - tmpPtr = fopen(file, "a+"); + i = pickString(redirect + 2, file, size); + if (i > 0) { + tmpPtr = fopen(file, "a+"); + } } else { - sscanf(redirect, "> %s", file); - tmpPtr = fopen(file, "w"); + i = pickString(redirect + 1, file, size); + if (i > 0) { + tmpPtr = fopen(file, "w"); + } } if (tmpPtr != NULL) { @@ -473,3 +482,110 @@ DecodeType(type) return (sym_ntop(__p_type_syms, type, (int *)0)); } + + + + +/* + * Skip over leading white space in SRC and then copy the next sequence of + * non-whitespace characters into DEST. No more than (DEST_SIZE - 1) + * characters are copied. DEST is always null-terminated. Returns 0 if no + * characters could be copied into DEST. Returns the number of characters + * in SRC that were processed (i.e. the count of characters in the leading + * white space and the first non-whitespace sequence). + * + * int i; + * char *p = " foo bar ", *q; + * char buf[100]; + * + * q = p + pickString(p, buf, sizeof buff); + * assert (strcmp (q, " bar ") == 0) ; + * + */ + +int +pickString(const char *src, char *dest, size_t dest_size) { + const char *start; + const char *end ; + size_t sublen ; + + if (dest_size == 0 || dest == NULL || src == NULL) + return 0; + + for (start = src ; isspace(*start) ; start++) + /* nada */ ; + + for (end = start ; *end != '\0' && !isspace(*end) ; end++) + /* nada */ ; + + sublen = end - start ; + + if (sublen == 0 || sublen > (dest_size - 1)) + return 0; + + strncpy (dest, start, sublen); + + dest[sublen] = '\0' ; + + return (end - src); +} + + + + +/* + * match the string FORMAT against the string SRC. Leading whitespace in + * FORMAT will match any amount of (including no) leading whitespace in + * SRC. Any amount of whitespace inside FORMAT matches any non-zero amount + * of whitespace in SRC. Value returned is 0 if match didn't occur, or the + * amount of characters in SRC that did match + * + * int i ; + * + * i = matchString(" a b c", "a b c") ; + * assert (i == 5) ; + * i = matchString("a b c", " a b c"); + * assert (i == 0) ; becasue no leading white space in format + * i = matchString(" a b c", " a b c"); + * assert(i == 12); + * i = matchString("aa bb ", "aa bb ddd sd"); + * assert(i == 16); + */ +int +matchString (const char *format, const char *src) { + const char *f = format; + const char *s = src; + + if (f == NULL || s == NULL) + goto notfound; + + if (isspace(*f)) { + while (isspace(*f)) + f++ ; + while (isspace(*s)) + s++ ; + } + + while (1) { + if (isspace(*f)) { + if (!isspace(*s)) + goto notfound; + while(isspace(*s)) + s++; + /* any amount of whitespace in the format string + will match any amount of space in the source + string. */ + while (isspace(*f)) + f++; + } else if (*f == '\0') { + return (s - src); + } else if (*f != *s) { + goto notfound; + } else { + s++ ; + f++ ; + } + } + notfound: + return 0 ; +} diff --git a/contrib/bind/bin/nsupdate/Makefile b/contrib/bind/bin/nsupdate/Makefile index 46806b6..b3b07c0 100644 --- a/contrib/bind/bin/nsupdate/Makefile +++ b/contrib/bind/bin/nsupdate/Makefile @@ -1,4 +1,4 @@ -## Copyright (c) 1996 by Internet Software Consortium +## 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 @@ -13,7 +13,7 @@ ## ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ## SOFTWARE. -# $Id: Makefile,v 8.18 1997/06/19 03:22:11 halley Exp $ +# $Id: Makefile,v 8.24 1999/08/08 17:51:02 vixie Exp $ DESTDIR= CC= cc @@ -29,15 +29,17 @@ PORTINCL = ${TOP}/port/${SYSTYPE}/include LIBBIND = ${TOP}/lib/libbind.a A=a O=o +EXE= LEX = lex -I SYSLIBS = -ll -lutil -PIDDIR = /var/run DESTBIN = /usr/local/bin DESTSBIN = /usr/local/sbin DESTEXEC = /usr/local/libexec DESTMAN = /usr/share/man DESTHELP= /usr/share/misc STRIP=-s +INSTALL_EXEC= +INSTALL_LIB=-o bin -g bin LDFLAGS= CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL} @@ -46,26 +48,29 @@ PROG= nsupdate SRCS= ${PROG}.c OBJS= ${PROG}.${O} -all: ${PROG} +all: ${PROG}${EXE} -${PROG}: ${OBJS} ${LIBBIND} Makefile - ${CC} ${CDEBUG} ${LDFLAGS} -o ${PROG} ${OBJS} \ +${PROG}${EXE}: ${OBJS} ${LIBBIND} Makefile + ${CC} ${CDEBUG} ${LDFLAGS} ${BOUNDS} -o ${PROG}${EXE} ${OBJS} \ ${LIBBIND} ${SYSLIBS} +.c.${O}: + ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c + distclean: clean clean: FRC - rm -f ${PROG} ${OBJS} core .depend + rm -f ${PROG}${EXE} ${OBJS} core .depend rm -f *.BAK *.CKP *~ *.orig depend: ${SRCS} - mkdep -p ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS} + mkdep ${CPPFLAGS} -I${INCL} -I${PORTINCL} ${SRCS} ${DESTDIR}${DESTBIN}: mkdir -p ${DESTDIR}${DESTBIN} -install: ${DESTDIR}${DESTBIN} ${PROG} - ${INSTALL} ${STRIP} -c -m 755 ${PROG} ${DESTDIR}${DESTBIN}/${PROG} +install: ${DESTDIR}${DESTBIN} ${PROG}${EXE} + ${INSTALL} ${STRIP} -c ${INSTALL_EXEC} -m 755 ${PROG}${EXE} ${DESTDIR}${DESTBIN}/${PROG}${EXE} links: FRC @set -e; ln -s SRC/*.[ch] . diff --git a/contrib/bind/bin/nsupdate/nsupdate.c b/contrib/bind/bin/nsupdate/nsupdate.c index 2b31716..a02d0ad 100644 --- a/contrib/bind/bin/nsupdate/nsupdate.c +++ b/contrib/bind/bin/nsupdate/nsupdate.c @@ -1,9 +1,9 @@ #if !defined(lint) && !defined(SABER) -static char rcsid[] = "$Id: nsupdate.c,v 8.5 1998/02/14 20:54:48 halley Exp $"; +static const char rcsid[] = "$Id: nsupdate.c,v 8.21 1999/10/19 22:22:59 cyarnell Exp $"; #endif /* not lint */ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -20,20 +20,28 @@ static char rcsid[] = "$Id: nsupdate.c,v 8.5 1998/02/14 20:54:48 halley Exp $"; */ #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 <limits.h> #include <netdb.h> #include <resolv.h> +#include <res_update.h> #include <stdio.h> #include <stdlib.h> +#include <unistd.h> #include <string.h> #include <ctype.h> +#include <isc/dst.h> #include "port_after.h" +#include "../named/db_defs.h" /* XXX all of this stuff should come from libbind.a */ @@ -74,8 +82,19 @@ struct map type_strs[] = { { "rt", T_RT }, { "nsap", T_NSAP }, { "nsap_ptr", T_NSAP_PTR }, + { "sig", T_SIG }, + { "key", T_KEY }, { "px", T_PX }, { "loc", T_LOC }, + { "nxt", T_NXT }, + { "eid", T_EID }, + { "nimloc", T_NIMLOC }, + { "srv", T_SRV }, + { "atma", T_ATMA }, + { "naptr", T_NAPTR }, + { "kx", ns_t_kx }, + { "cert", ns_t_cert }, + { "aaaa", ns_t_aaaa }, }; #define M_TYPE_CNT (sizeof(type_strs) / sizeof(struct map)) @@ -97,12 +116,17 @@ struct map opcode_strs[] = { }; #define M_OPCODE_CNT (sizeof(opcode_strs) / sizeof(struct map)) +static int getcharstring(char *, char *, int, int, int); static char *progname; -static FILE *log; static void usage(void); static int getword_str(char *, int, char **, char *); +static struct __res_state res; + +int dns_findprimary (res_state, char *, struct ns_tsig_key *, char *, + int, struct in_addr *); + /* * format of file read by nsupdate is kept the same as the log * file generated by updates, so that the log file can be fed @@ -123,27 +147,32 @@ main(argc, argv) { FILE *fp = NULL; char buf[BUFSIZ], buf2[BUFSIZ], hostbuf[100], filebuf[100]; - char dnbuf[MAXDNAME]; + char dnbuf[MAXDNAME], data[MAXDATA]; u_char packet[PACKETSZ], answer[PACKETSZ]; char *host = hostbuf, *batchfile = filebuf; char *r_dname, *cp, *startp, *endp, *svstartp; char section[15], opcode[10]; int i, c, n, n1, inside, lineno = 0, vc = 0, debug = 0, r_size, r_section, r_opcode, - prompt = 0, ret = 0; + prompt = 0, ret = 0, stringtobin = 0; int16_t r_class, r_type; u_int32_t r_ttl; struct map *mp; - ns_updrec *rrecp_start = NULL, *rrecp, *tmprrecp; + ns_updrec *rrecp; + ns_updque listuprec; struct in_addr hostaddr; extern int getopt(); extern char *optarg; extern int optind, opterr, optopt; + ns_tsig_key key; + char *keyfile=NULL, *keyname=NULL, *p, *pp; + int file_major, file_minor, alg; + progname = argv[0]; - while ((c = getopt(argc, argv, "dv")) != EOF) { + while ((c = getopt(argc, argv, "dsvk:n:")) != -1) { switch (c) { case 'v': vc = 1; @@ -151,11 +180,130 @@ main(argc, argv) case 'd': debug = 1; break; + case 's': + stringtobin = 1; + break; + case 'k': { + /* -k keydir:keyname */ + char *colon; + + if ((colon=strchr(optarg, ':'))==NULL) { + fprintf(stderr, "key option argument should be keydir:keyname\n"); + exit(1); + } + keyname=colon+1; + keyfile=optarg; + *colon='\0'; + break; + } + case 'n': + keyname=optarg; + break; default: usage(); } } + if (keyfile) { +#ifdef PARSE_KEYFILE + if ((fp=fopen(keyfile, "r"))==NULL) { + perror("open keyfile"); + exit(1); + } + /* now read the header info from the file */ + if ((i=fread(buf, 1, BUFSIZ, fp)) < 5) { + fclose(fp); + exit(1); + } + fclose(fp); + fp=NULL; + + p=buf; + + n=strlen(p); /* get length of strings */ + n1=strlen("Private-key-format: v"); + if (n1 > n || strncmp(buf, "Private-key-format: v", n1)) { + fprintf(stderr, "Invalid key file format\n"); + exit(1); /* not a match */ + } + p+=n1; /* advance pointer */ + sscanf((char *)p, "%d.%d", &file_major, &file_minor); + /* should do some error checking with these someday */ + while (*p++!='\n'); /* skip to end of line */ + + n=strlen(p); /* get length of strings */ + n1=strlen("Algorithm: "); + if (n1 > n || strncmp(p, "Algorithm: ", n1)) { + fprintf(stderr, "Invalid key file format\n"); + exit(1); /* not a match */ + } + p+=n1; /* advance pointer */ + if (sscanf((char *)p, "%d", &alg)!=1) { + fprintf(stderr, "Invalid key file format\n"); + exit(1); + } + while (*p++!='\n'); /* skip to end of line */ + + n=strlen(p); /* get length of strings */ + n1=strlen("Key: "); + if (n1 > n || strncmp(p, "Key: ", n1)) { + fprintf(stderr, "Invalid key file format\n"); + exit(1); /* not a match */ + } + p+=n1; /* advance pointer */ + pp=p; + while (*pp++!='\n'); /* skip to end of line, terminate it */ + *--pp='\0'; + + key.data=malloc(1024*sizeof(char)); + key.len=b64_pton(p, key.data, 1024); + + strcpy(key.name, keyname); + strcpy(key.alg, "HMAC-MD5.SIG-ALG.REG.INT"); +#else + /* use the dst* routines to parse the key files + * + * This requires that both the .key and the .private files + * exist in your cwd, so the keyfile parmeter here is + * assumed to be a path in which the K*.{key,private} files + * exist. + */ + DST_KEY *dst_key; + char cwd[PATH_MAX+1]; + + if (getcwd(cwd, PATH_MAX)==NULL) { + perror("unable to get current directory"); + exit(1); + } + if (chdir(keyfile)<0) { + fprintf(stderr, "unable to chdir to %s: %s\n", keyfile, + strerror(errno)); + exit(1); + } + + dst_init(); + dst_key = dst_read_key(keyname, + 0 /* not used for private keys */, + KEY_HMAC_MD5, DST_PRIVATE); + if (!dst_key) { + fprintf(stderr, "dst_read_key: error reading key\n"); + exit(1); + } + key.data=malloc(1024*sizeof(char)); + dst_key_to_buffer(dst_key, key.data, 1024); + key.len=dst_key->dk_key_size; + + strcpy(key.name, keyname); + strcpy(key.alg, "HMAC-MD5.SIG-ALG.REG.INT"); + + if (chdir(cwd)<0) { + fprintf(stderr, "unable to chdir to %s: %s\n", cwd, + strerror(errno)); + exit(1); + } +#endif + } + if ((argc - optind) == 0) { /* no file specified, read from stdin */ ret = system("tty -s"); @@ -383,7 +531,7 @@ main(argc, argv) break; default: fprintf(stderr, - "unknown operation in update section\"%s\"\n", opcode); + "unknown operation in update section \"%s\"\n", opcode); exit (1); } break; @@ -396,38 +544,60 @@ main(argc, argv) if ( !(rrecp = res_mkupdrec(r_section, r_dname, r_class, r_type, r_ttl)) || (r_size > 0 && !(rrecp->r_data = (u_char *)malloc(r_size))) ) { + if (rrecp) + res_freeupdrec(rrecp); fprintf(stderr, "saverrec error\n"); exit (1); } + if (stringtobin) { + switch(r_opcode) { + case T_HINFO: + if (!getcharstring(buf,(char *)data,2,2,lineno)) + exit(1); + cp = data; + break; + case T_ISDN: + if (!getcharstring(buf,(char *)data,1,2,lineno)) + exit(1); + cp = data; + break; + case T_TXT: + if (!getcharstring(buf,(char *)data,1,0,lineno)) + exit(1); + cp = data; + break; + case T_X25: + if (!getcharstring(buf,(char *)data,1,1,lineno)) + exit(1); + cp = data; + break; + default: + break; + } + } rrecp->r_opcode = r_opcode; rrecp->r_size = r_size; (void) strncpy((char *)rrecp->r_data, cp, r_size); - /* append current record to the end of linked list of - * records seen so far */ - if (rrecp_start == NULL) - rrecp_start = rrecp; - else { - tmprrecp = rrecp_start; - while (tmprrecp->r_next != NULL) - tmprrecp = tmprrecp->r_next; - tmprrecp->r_next = rrecp; - } + APPEND(listuprec, rrecp, r_link); } else { /* end of an update packet */ - (void) res_init(); + (void) res_ninit(&res); if (vc) - _res.options |= RES_USEVC | RES_STAYOPEN; + res.options |= RES_USEVC | RES_STAYOPEN; if (debug) - _res.options |= RES_DEBUG; - if (rrecp_start) { - if ((n = res_update(rrecp_start)) < 0) - fprintf(stderr, "failed update packet\n"); - /* free malloc'ed memory */ - while(rrecp_start) { - tmprrecp = rrecp_start; - rrecp_start = rrecp_start->r_next; - free((char *)tmprrecp->r_dname); - free((char *)tmprrecp); - } + res.options |= RES_DEBUG; + if (!EMPTY(listuprec)) { + n = res_nupdate(&res, HEAD(listuprec), + keyfile != NULL ? &key : NULL); + if (n < 0) + fprintf(stderr, "failed update packet\n"); + while (!EMPTY(listuprec)) { + ns_updrec *tmprrecp = HEAD(listuprec); + + UNLINK(listuprec, tmprrecp, r_link); + if (tmprrecp->r_size != 0) + free((char *)tmprrecp->r_data); + res_freeupdrec(tmprrecp); + } } } } /* for */ @@ -436,7 +606,7 @@ main(argc, argv) static void usage() { - fprintf(stderr, "Usage: %s [-d] [-v] [file]\n", + fprintf(stderr, "Usage: %s [ -k keydir:keyname ] [-d] [-v] [file]\n", progname); exit(1); } @@ -469,3 +639,51 @@ getword_str(char *buf, int size, char **startpp, char *endp) { *cp = '\0'; return (cp != buf); } + +#define MAXCHARSTRING 255 + +static int +getcharstring(char *buf, char *data, + int minfields, int maxfields, int lineno) +{ + int nfield = 0, n = 0, i; + + do { + nfield++; + i = 0; + if (*buf == '"') { + buf++; + while(buf[i] && buf[i] != '"') + i++; + } else { + while(isspace(*buf)) + i++; + } + if (i > MAXCHARSTRING) { + fprintf(stderr, + "%d: RDATA field %d too long", + lineno, nfield); + return(0); + } + if (n + i + 1 > MAXDATA) { + fprintf(stderr, + "%d: total RDATA too long", lineno); + return(0); + } + data[n]=i; + memmove(data + 1 + n, buf, i); + buf += i + 1; + n += i + 1; + while(*buf && isspace(*buf)) + buf++; + } while (nfield < maxfields && *buf); + + if (nfield < minfields) { + fprintf(stderr, + "%d: expected %d RDATA fields, only saw %d", + lineno, minfields, nfield); + return (0); + } + + return (n); +} diff --git a/contrib/bind/doc/bog/00title.me b/contrib/bind/doc/bog/00title.me index be95d8b..5048969 100644 --- a/contrib/bind/doc/bog/00title.me +++ b/contrib/bind/doc/bog/00title.me @@ -1,5 +1,3 @@ -.\" ++Copyright++ 1986, 1988 -.\" - .\" Copyright (c) 1986, 1988 .\" The Regents of the University of California. All rights reserved. .\" @@ -30,7 +28,7 @@ .\" 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 @@ -48,9 +46,6 @@ .\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS .\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS .\" SOFTWARE. -.\" - -.\" --Copyright-- -.\" .+c .(l C .sz 14 diff --git a/contrib/bind/doc/bog/ack.me b/contrib/bind/doc/bog/ack.me index 5c02c14..c9d7d85 100644 --- a/contrib/bind/doc/bog/ack.me +++ b/contrib/bind/doc/bog/ack.me @@ -1,5 +1,3 @@ -.\" ++Copyright++ 1986, 1988 -.\" - .\" Copyright (c) 1986, 1988 .\" The Regents of the University of California. All rights reserved. .\" @@ -30,7 +28,7 @@ .\" 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 @@ -48,8 +46,6 @@ .\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS .\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS .\" SOFTWARE. -.\" - -.\" --Copyright-- .\" .\" @(#)ack.me .\" diff --git a/contrib/bind/doc/html/acl.html b/contrib/bind/doc/html/acl.html index cf684b4..57cf869 100644 --- a/contrib/bind/doc/html/acl.html +++ b/contrib/bind/doc/html/acl.html @@ -52,12 +52,12 @@ Allows any host on a network for which the system has an interface. <HR> <CENTER><P>[ <A HREF="config.html">BIND Config. File</A> -| <A HREF="http://www.vix.com/isc/bind.html">BIND Home</A> -| <A HREF="http://www.isc.org">ISC</A> ]</P></CENTER> +| <A HREF="http://www.isc.org/products/BIND/">BIND Home</A> +| <A HREF="http://www.isc.org/">ISC</A> ]</P></CENTER> <HR> <ADDRESS> -Last Updated: $Id: acl.html,v 1.4 1998/03/21 01:03:10 halley Exp $ +Last Updated: $Id: acl.html,v 1.5 1999/09/15 20:28:00 cyarnell Exp $ </ADDRESS> </BODY> </HTML> diff --git a/contrib/bind/doc/html/address_list.html b/contrib/bind/doc/html/address_list.html index 894ef04..ec39138 100644 --- a/contrib/bind/doc/html/address_list.html +++ b/contrib/bind/doc/html/address_list.html @@ -14,14 +14,18 @@ <PRE> <VAR>address_match_list</VAR> = 1*<VAR>address_match_element</VAR> -<VAR>address_match_element</VAR> = [ "!" ] (<VAR><A HREF="docdef.html">ip_address</A></VAR> / <VAR><A HREF="docdef.html">ip_prefix</A></VAR> / <VAR><A HREF="acl.html">acl_name</A></VAR> / <VAR>address_match_list</VAR>) ";" +<VAR>address_match_element</VAR> = [ "!" ] (<VAR><A HREF="docdef.html">address_match_list</A></VAR> / <VAR><A HREF="docdef.html">ip_address</A></VAR> / <VAR><A HREF="docdef.html">ip_prefix</A></VAR> / <VAR><A HREF="acl.html">acl_name</A></VAR> / <VAR><A HREF="docdef.html">"key" key_id</A></VAR>) ";" </PRE> <HR> <A NAME="Usage"><H3>Definition and Usage</H3></A> -<P>Address match lists are lists of elements. The elements can be any +<P>Address match lists are primarily used to determine access control for +various server operations. They are also used to define priorities +for querying other nameservers and to set the addresses on which +<CODE>named</CODE> will listen for queries. +The elements which constitute an address match list can be any of the following:</P> <UL> @@ -29,34 +33,43 @@ of the following:</P> <LI>an IP prefix (in the '/'-notation),</LI> +<LI>a key ID, as defined by the +<A HREF="key.html"><CODE>key</CODE></A> statement, or + <LI>the name of an address match list previously defined with -the <A HREF="acl.html"><CODE>acl</CODE></A> statment.</LI> +the <A HREF="acl.html"><CODE>acl</CODE></A> statment, or</LI> -<LI>an IP address match list</LI> +<LI>another <VAR>address_match_list</VAR></LI> </UL> -<P>The ACLs "any", "none", "localhost" and "localnets" are -predefined. More information can be found in the description of the -<A HREF="acl.html"><CODE>acl</CODE></A> statement. +<P>Elements can be negated with a leading exclamation mark ("!"), and +the match list names "any", "none", "localhost" and "localnets" are +predefined. More information on those names can be found in the +description of the <A HREF="acl.html"><CODE>acl</CODE></A> statement. -<P>Elements can be negated with a leading "!". +<P>The addition of the <CODE>key</CODE> +clause made the name of this syntactic element something of a +misnomer, since security keys can be used to validate access without +regard to a host or network address. Nonetheless, the term "address +match list" is still used throughout the documentation.</P> <P>When a given IP address or prefix is compared to an address match -list, the list is traversed in order and the first match (regardless -of negation) is used. The interpretation of a match depends on -whether the list is being used for access control or as a -topology.</P> +list, the list is traversed in order until an element matches. The +interpretation of a match depends on whether the list is being used +for access control, defining <CODE>listen-on</CODE> ports, or as a +topology, and whether the element was negated.</P> <P>When used as an access control list, a non-negated match allows access and a negated match denies access. If there is no match, access is denied. The clauses <CODE>allow-query</CODE>, -<CODE>allow-transfer</CODE> and <CODE>allow-update</CODE> all use -address match lists like this. Similarly, the <CODE>listen-on</CODE> -clause can use negation to define local addresses which should not be -used to accept nameserver connections.</P> +<CODE>allow-transfer</CODE>, <CODE>allow-update</CODE> and +<CODE>blackhole</CODE> all use address match lists like this. +Similarly, the <CODE>listen-on</CODE> +option will cause the server to not accept queries on any of the +machine's addresses which do not match the list. <P>When used with the <CODE>topology</CODE> clause, a non-negated -match returns a distance based on its postion on the list (the closer +match returns a distance based on its position on the list (the closer the match is to the start of the list, the shorter the distance is between it and the server). A negated match will be assigned the maximum distance from the server. If there is no match, the address @@ -76,12 +89,12 @@ fall through. <HR> <CENTER><P>[ <A HREF="config.html">BIND Config. File</A> -| <A HREF="http://www.vix.com/isc/bind.html">BIND Home</A> -| <A HREF="http://www.isc.org">ISC</A> ]</P></CENTER> +| <A HREF="http://www.isc.org/products/BIND/">BIND Home</A> +| <A HREF="http://www.isc.org/">ISC</A> ]</P></CENTER> <HR> <ADDRESS> -Last Updated: $Id: address_list.html,v 1.5 1998/03/21 01:03:10 halley Exp $ +Last Updated: $Id: address_list.html,v 1.8 1999/09/15 20:28:00 cyarnell Exp $ </ADDRESS> </BODY> </HTML> diff --git a/contrib/bind/doc/html/comments.html b/contrib/bind/doc/html/comments.html index 8ada6b0..a064c1c 100644 --- a/contrib/bind/doc/html/comments.html +++ b/contrib/bind/doc/html/comments.html @@ -73,12 +73,12 @@ statement.</P> <HR> <CENTER><P>[ <A HREF="config.html">BIND Config. File</A> -| <A HREF="http://www.vix.com/isc/bind.html">BIND Home</A> -| <A HREF="http://www.isc.org">ISC</A> ]</P></CENTER> +| <A HREF="http://www.isc.org/products/BIND/">BIND Home</A> +| <A HREF="http://www.isc.org/">ISC</A> ]</P></CENTER> <HR> <ADDRESS> -Last Updated: $Id: comments.html,v 1.4 1998/03/21 01:03:11 halley Exp $ +Last Updated: $Id: comments.html,v 1.5 1999/09/15 20:28:00 cyarnell Exp $ </ADDRESS> </BODY> </HTML> diff --git a/contrib/bind/doc/html/config.html b/contrib/bind/doc/html/config.html index dd8e0b4..97f3a1b 100644 --- a/contrib/bind/doc/html/config.html +++ b/contrib/bind/doc/html/config.html @@ -47,13 +47,22 @@ specifies what the server logs, and where the log messages are sent <DT><CODE><A HREF="options.html">options</A></CODE> <DD> -controls global server configuation options and sets defaults for other +controls global server configuration options and sets defaults for other statements +<DT><CODE><A HREF="controls.html">controls</A></CODE> +<DD> +declares control channels to be used by the <VAR>ndc</VAR> utility + <DT><CODE><A HREF="server.html">server</A></CODE> <DD> sets certain configuration options on a per-server basis +<DT><CODE><A HREF="trusted-keys.html">trusted-keys</A></CODE> +<DD> +defines DNSSEC keys that are preconfigured into the server and implicitly +trusted + <DT><CODE><A HREF="zone.html">zone</A></CODE> <DD> defines a zone @@ -62,22 +71,27 @@ defines a zone <P>The <CODE>logging</CODE> and <CODE>options</CODE> statements may only occur once per configuration. -<H4><A HREF="comments.html">Comments</A></H4> +<H4>Comments</H4> + +The BIND 8 <A HREF="comments.html">comment syntax</A> allows for +comments to appear anywhere that whitespace may appear in a BIND +configuration file. To appeal to programmers of all kinds, they can +be written in C, C++, or shell/perl constructs. <H3>Converting from BIND 4.9.x</H3> -<P>BIND 4.9.x configuration files can be converted to the new format -by using <CODE>src/bin/named/named-bootconf.pl</CODE>, a perl script that -is part of the BIND 8.1 source kit. +<p>BIND 4.9.x configuration files can be converted to the new format by +using <code>src/bin/named/named-bootconf</code>, a shell script that is part of +the BIND 8.2.x source kits. <HR> -<CENTER><P>[ <A HREF="http://www.vix.com/isc/bind.html">BIND Home</A> -| <A HREF="http://www.isc.org">ISC</A> ]</P></CENTER> +<CENTER><P>[ <A HREF="http://www.isc.org/products/BIND/">BIND Home</A> +| <A HREF="http://www.isc.org/">ISC</A> ]</P></CENTER> <HR> <ADDRESS> -Last Updated: $Id: config.html,v 1.4 1998/03/21 01:03:11 halley Exp $ +Last Updated: $Id: config.html,v 1.10 1999/09/15 20:28:01 cyarnell Exp $ </ADDRESS> </BODY> </HTML> diff --git a/contrib/bind/doc/html/controls.html b/contrib/bind/doc/html/controls.html new file mode 100644 index 0000000..9261926 --- /dev/null +++ b/contrib/bind/doc/html/controls.html @@ -0,0 +1,70 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"> +<HTML> +<HEAD> + <TITLE>BIND controls Statement</TITLE> +</HEAD> + +<BODY> +<H2>BIND Configuration File Guide--<CODE>controls</CODE> Statement</H2> + +<HR> + +<A NAME="Syntax"><H3>Syntax</H3></A> + +<PRE> +controls { + [ inet <VAR><A HREF="docdef.html">ip_addr</A></VAR> + port <VAR><A HREF="docdef.html">ip_port</A></VAR> + allow { <VAR><A HREF="address_list.html">address_match_list</A></VAR>; }; ] + [ unix <VAR><A HREF="docdef.html">path_name</A></VAR> + perm <VAR><A HREF="docdef.html">number</A></VAR> + owner <VAR><A HREF="docdef.html">number</A></VAR> + group <VAR><A HREF="docdef.html">number</A></VAR>; ] +}; +</PRE> + +<HR> + +<A NAME="Usage"><H3>Definition and Usage</H3></A> + +<P>The <CODE>controls</CODE> statement declares control channels +to be used by system +administrators to affect the operation of the local name server. These +control channels are used by the <CODE>ndc</CODE> utility to send commands +to and retrieve non-DNS results from a name server.</P> + +<P>A <CODE>unix</CODE> control channel is a FIFO in the file system, +and access to it is +controlled by normal file system permissions. +It is created by <CODE>named</CODE> with the specified file mode bits (see +the <CODE>chmod</CODE>(1) manual page), user and group owner. +Note that, unlike <CODE>chmod</CODE>, the mode bits specified for +<CODE>perm</CODE> will normally have a leading 0 so the number +is interpreted as octal. Also note that the user and group +ownership specified as <CODE>owner</CODE> and <CODE>group</CODE> +must be given as numbers, not names. +It is recommended that the +permissions be restricted to administrative personnel only, or else any +user on the system might be able to manage the local name server.</P> + +<P>An <CODE>inet</CODE> control channel is a TCP/IP socket accessible +to the Internet, created at the specified <VAR>ip_port</VAR> on the +specified <VAR>ip_addr</VAR>. +Modern <VAR>telnet</VAR> clients are capable of speaking directly to these +sockets, and the control protocol is ARPAnet-style text. It is recommended +that 127.0.0.1 be the only <VAR>ip_addr</VAR> used, and this only if you +trust all non-privileged users on the local host to manage your name +server.</P> + +<HR> + +<CENTER><P>[ <A HREF="config.html">BIND Config. File</A> +| <A HREF="http://www.isc.org/products/BIND/">BIND Home</A> +| <A HREF="http://www.isc.org/">ISC</A> ]</P></CENTER> + +<HR> +<ADDRESS> +Last Updated: $Id: controls.html,v 1.4 1999/09/15 20:28:01 cyarnell Exp $ +</ADDRESS> +</BODY> +</HTML> diff --git a/contrib/bind/doc/html/docdef.html b/contrib/bind/doc/html/docdef.html index da0c9d5..0885c1f 100644 --- a/contrib/bind/doc/html/docdef.html +++ b/contrib/bind/doc/html/docdef.html @@ -23,8 +23,8 @@ as defined by the <A HREF="acl.html">acl</A> statement. <DT><VAR>address_match_list</VAR> <DD> -A list of one or more <VAR>ip_address</VAR>, <VAR>ip_prefix</VAR> or -<VAR>acl_name</VAR> elements, as described in the +A list of one or more <VAR>ip_address</VAR>, <VAR>ip_prefix</VAR> +<VAR>key_id</VAR> or <VAR>acl_name</VAR> elements, as described in the <A HREF="address_list.html">Address Match Lists</A> section. <DT><VAR>dotted-decimal</VAR> @@ -52,7 +52,8 @@ An IP address in with exactly four elements in <DD> An IP port <VAR>number</VAR>. <VAR>number</VAR> is limited to 0 through 65535, with values below 1024 typically restricted to -root-owned processes. +root-owned processes. In some cases an asterisk (``*'') character +can be used as a placeholder to select a random high-numbered port. <DT><VAR>ip_prefix</VAR> <DD> @@ -62,6 +63,11 @@ the network <CODE>127.0.0.0</CODE> with netmask <CODE>255.0.0.0</CODE>. <CODE>1.2.3.0/24</CODE> is network <CODE>1.2.3.0</CODE> with netmask <CODE>255.255.255.0</CODE>. +<DT><VAR>key_id</VAR> +<DD> +A string representing the name of a shared key, to be used for transaction +security. + <DT><VAR>number</VAR> <DD> A non-negative integer with an entire range limited by the range of a @@ -101,12 +107,12 @@ numbers <CODE>1</CODE> and <CODE>0</CODE>. <HR> <CENTER><P>[ <A HREF="config.html">BIND Config. File</A> -| <A HREF="http://www.vix.com/isc/bind.html">BIND Home</A> -| <A HREF="http://www.isc.org">ISC</A> ]</P></CENTER> +| <A HREF="http://www.isc.org/products/BIND/">BIND Home</A> +| <A HREF="http://www.isc.org/">ISC</A> ]</P></CENTER> <HR> <ADDRESS> -Last Updated: $Id: docdef.html,v 1.4 1998/03/21 01:03:12 halley Exp $ +Last Updated: $Id: docdef.html,v 1.8 1999/09/15 20:28:01 cyarnell Exp $ </ADDRESS> </BODY> </HTML> diff --git a/contrib/bind/doc/html/example.html b/contrib/bind/doc/html/example.html index 729b980..a147828 100644 --- a/contrib/bind/doc/html/example.html +++ b/contrib/bind/doc/html/example.html @@ -15,13 +15,18 @@ * A simple BIND 8 configuration */ +logging { + category lame-servers { null; }; + category cname { null; }; +}; + options { directory "/var/named"; }; -logging { - category lame-servers { null; }; - category cname { null; }; +controls { + inet * port 52 allow { localnets; }; // a BAD idea + unix "/var/run/ndc" perm 0600 owner 0 group 0; // the default }; zone "isc.org" in { @@ -42,18 +47,19 @@ zone "." in { zone "0.0.127.in-addr.arpa" in { type master; + notify no; file "master/127.0.0"; }; </PRE> <HR> -<CENTER><P>[ <A HREF="http://www.vix.com/isc/bind.html">BIND Home</A> -| <A HREF="http://www.isc.org">ISC</A> ]</P></CENTER> +<CENTER><P>[ <A HREF="http://www.isc.org/products/BIND/">BIND Home</A> +| <A HREF="http://www.isc.org/">ISC</A> ]</P></CENTER> <HR> <ADDRESS> -Last Updated: $Id: example.html,v 1.1 1997/05/06 22:11:31 vixie Exp $ +Last Updated: $Id: example.html,v 1.5 1999/09/15 20:28:01 cyarnell Exp $ </ADDRESS> </BODY> </HTML> diff --git a/contrib/bind/doc/html/include.html b/contrib/bind/doc/html/include.html index 4184210..421d97b 100644 --- a/contrib/bind/doc/html/include.html +++ b/contrib/bind/doc/html/include.html @@ -11,7 +11,9 @@ <A NAME="Syntax"><H3>Syntax</H3></A> -<P><CODE>include <VAR><A HREF="docdef.html">path_name</A></VAR>;</CODE></P> +<PRE> +include <VAR><A HREF="docdef.html">path_name</A></VAR>; +</PRE> <HR> @@ -20,16 +22,18 @@ <P>The <CODE>include</CODE> statement inserts the specified file at the point that the <CODE>include</CODE> statement is encountered. It cannot be used within another statement, though, so a line such as -<CODE>acl internal_hosts { "include internal_hosts.acl" }</CODE> is -not allowed.</P> +<PRE> +acl internal_hosts { include "internal_hosts.acl"; }; +</PRE> +is not allowed.</P> <P>Use <CODE>include</CODE> to break the configuration up into -easily-managed chunks. For example:</P> +easily-managed chunks. For example: -<UL COMPACT> -<LI><CODE>include "/etc/security/keys.bind";</CODE></LI> -<LI><CODE>include "/etc/acls.bind";</CODE></LI> -</UL> +<PRE> +include "/etc/security/keys.bind"; +include "/etc/acls.bind"; +</PRE> <P>could be used at the top of a BIND configuration file in order to include any ACL or key information.</P> @@ -42,12 +46,12 @@ comment.</P> <HR> <CENTER><P>[ <A HREF="config.html">BIND Config. File</A> -| <A HREF="http://www.vix.com/isc/bind.html">BIND Home</A> -| <A HREF="http://www.isc.org">ISC</A> ]</P></CENTER> +| <A HREF="http://www.isc.org/products/BIND/">BIND Home</A> +| <A HREF="http://www.isc.org/">ISC</A> ]</P></CENTER> <HR> <ADDRESS> -Last Updated: $Id: include.html,v 1.5 1998/03/21 01:03:12 halley Exp $ +Last Updated: $Id: include.html,v 1.7 1999/09/15 20:28:01 cyarnell Exp $ </ADDRESS> </BODY> </HTML> diff --git a/contrib/bind/doc/html/index.html b/contrib/bind/doc/html/index.html index ca8c73c..f19464b 100644 --- a/contrib/bind/doc/html/index.html +++ b/contrib/bind/doc/html/index.html @@ -26,6 +26,8 @@ updates that may be specified on a zone-by-zone basis</LI> <H3><A HREF="config.html">Configuration File Guide</A></H3> +<H3><A HREF="master.html">Master File Format</A></H3> + <H3>Kits</H3> <UL> <LI><A HREF="ftp://ftp.isc.org/isc/bind/src/cur"> @@ -56,7 +58,7 @@ and generally kind hearted folk such as yourself. <HR> <ADDRESS> -Last Updated: $Id: index.html,v 1.4 1998/03/21 01:03:12 halley Exp $ +Last Updated: $Id: index.html,v 1.5 1998/11/24 01:44:43 marka Exp $ </ADDRESS> </BODY> diff --git a/contrib/bind/doc/html/key.html b/contrib/bind/doc/html/key.html index bac6a96..bf2e3d1 100644 --- a/contrib/bind/doc/html/key.html +++ b/contrib/bind/doc/html/key.html @@ -23,28 +23,35 @@ key <VAR>key_id</VAR> { <A NAME="Usage"><H3>Definition and Usage</H3></A> <P>The <CODE>key</CODE> statement defines a key ID which can be used -in a <A HREF="server.html"><CODE>server</CODE> statement</A> to +in a <A HREF="server.html"><CODE>server</CODE></A> statement to associate an authentication method with a particular name server. <P>A key ID must be created with the <CODE>key</CODE> statement before it can be used in a <CODE>server</CODE> -definition.</P> +definition or an address match list.</P> <P>The <VAR>algorithm_id</VAR> is a string that specifies a -security/authentication algorithm. -<VAR>secret_string</VAR> is the secret to be used by the algorithm. - -<P>The <CODE>key</CODE> statement is intended for future use by the -server. It is checked for syntax but is otherwise ignored. +security/authentication algorithm. The only supported +algorithm is "hmac-md5". + +<P><VAR>secret_string</VAR> is the secret to be used by the algorithm, +and is treated as a base-64 encoded string. This may be generated +using dnskeygen or another utility or created manually. + +<P>The <CODE>key</CODE> statement is intended for use in transaction +security. Unless included in a <A HREF="server.html"><CODE>server</CODE></A> +statement, it is not used to sign any requests. It is used to verify +requests matching the <VAR>key_id</VAR> and <VAR>algorithm_id</VAR>, +and sign replies to those requests. <HR> <CENTER><P>[ <A HREF="config.html">BIND Config. File</A> -| <A HREF="http://www.vix.com/isc/bind.html">BIND Home</A> -| <A HREF="http://www.isc.org">ISC</A> ]</P></CENTER> +| <A HREF="http://www.isc.org/products/BIND/">BIND Home</A> +| <A HREF="http://www.isc.org/">ISC</A> ]</P></CENTER> <HR> <ADDRESS> -Last Updated: $Id: key.html,v 1.5 1998/03/21 01:03:13 halley Exp $ +Last Updated: $Id: key.html,v 1.10 1999/09/15 20:28:02 cyarnell Exp $ </ADDRESS> </BODY> </HTML> diff --git a/contrib/bind/doc/html/logging.html b/contrib/bind/doc/html/logging.html index 4d00219..10e2168 100644 --- a/contrib/bind/doc/html/logging.html +++ b/contrib/bind/doc/html/logging.html @@ -60,6 +60,15 @@ the logging configuration will be:</P> }; </PRE> +The logging configuration is established as soon as the +<CODE>logging</CODE> statement is parsed. If you want to redirect +messages about processing of the entire configuration file, the +<CODE>logging</CODE>statement must appear first. Even if you do not +redirect configuration file parsing messages, we recommend +always putting the <CODE>logging</CODE> statement first so that this +rule need not be consciously recalled if you ever do need want the +parser's messages relocated. + <H4>The <CODE>channel</CODE> phrase</H4> <P>All log output goes to one or more "channels"; you can make as many @@ -82,26 +91,37 @@ large the file is allowed to become, and how many versions of the file will be saved each time the file is opened. <P>The <CODE>size</CODE> option for files is simply a hard ceiling on -log growth. If the file ever exceeds the size, then +log growth. If the file ever exceeds the size, <CODE>named</CODE> will just not write anything more to it until the file is reopened; exceeding the size does not automatically trigger a reopen. The default behavior is to not limit the size of the file.</P> -<P>If you use the <CODE>version</CODE> logfile option, then +<P>If you use the <CODE>version</CODE> logfile option, <CODE>named</CODE> will retain that many backup versions of the file by renaming them when opening. For example, if you choose to keep 3 old versions of the file "lamers.log" then just before it is opened lamers.log.1 is renamed to lames.log.2, lamers.log.0 is renamed to lamers.log.1, and lamers.log is renamed to lamers.log.0. No rolled -versions are kept by default. The <CODE>unlimited</CODE> keyword is -synonymous with <CODE>99</CODE> in current BIND releases.</P> +versions are kept by default; any existing log file is simply +appended. The <CODE>unlimited</CODE> keyword is synonymous with +<CODE>99</CODE> in current BIND releases.</P> + +<P>Example usage of the size and versions options: + +<PRE> + channel an_example_level { + file "lamers.log" versions 3 size 20m; + print-time yes; + print-category yes; + }; +</PRE> <P>The argument for the <CODE>syslog</CODE> clause is a syslog facility as described in the <CODE>syslog</CODE> manual page. How <CODE>syslogd</CODE> will handle messages sent to this facility is described in the <CODE>syslog.conf</CODE> manual page. If you have a system which uses a very old version of <CODE>syslog</CODE> that only -uses two arguments to the <CODE>openlog()</CODE> function, then this +uses two arguments to the <CODE>openlog()</CODE> function, this clause is silently ignored.</P> <P>The <CODE>severity</CODE> clause works like <CODE>syslog</CODE>'s @@ -111,7 +131,7 @@ which are not at least of the severity level given will not be selected for the channel; messages of higher severity levels will be accepted.</P> -<P>If you are using <CODE>syslog</CODE>, then the +<P>If you are using <CODE>syslog</CODE>, the <CODE>syslog.conf</CODE> priorities will also determine what eventually passes through. For example, defining a channel facility and severity as <CODE>daemon</CODE> and <CODE>debug</CODE> but only @@ -119,18 +139,19 @@ logging <CODE>daemon.warning</CODE> via <CODE>syslog.conf</CODE> will cause messages of severity <CODE>info</CODE> and <CODE>notice</CODE> to be dropped. If the situation were reversed, with <CODE>named</CODE> writing messages of only <CODE>warning</CODE> or -higher, then <CODE>syslogd</CODE> would print all messages it received +higher, <CODE>syslogd</CODE> would print all messages it received from the channel.</P> <P>The server can supply extensive debugging information when it is in debugging mode. If the server's global debug level is greater than -zero, then debugging mode will be active. The global debug level is -set either by starting the server with the "-d" flag followed by a -positive integer, or by sending the server the SIGUSR1 signal (for -example, by using "ndc trace"). The global debug level can be set to -zero, and debugging mode turned off, by sending the server the SIGUSR2 -signal ("ndc notrace". All debugging messages in the server have a -debug level, and higher debug levels give more more detailed output. +zero, debugging mode will be active. The global debug level is +set either by starting the <CODE>named</CODE> server with the "-d" +flag followed by a positive integer, or by sending the running server the +SIGUSR1 signal (for example, by using "ndc trace"). The global debug +level can be set to zero, and debugging mode turned off, by sending +the server the SIGUSR2 signal ("ndc notrace"). All debugging messages +in the server have a debug level, and higher debug levels give more +more detailed output. Channels that specify a specific debug severity, e.g. <PRE> @@ -145,12 +166,12 @@ server is in debugging mode, regardless of the global debugging level. Channels with <code>dynamic</code> severity use the server's global level to determine what messages to print. -<P>If <CODE>print-time</CODE> has been turned on, then the date and +<P>If <CODE>print-time</CODE> has been turned on, the date and time will be logged. <CODE>print-time</CODE> may be specified for a syslog channel, but is usually pointless since syslog also prints the date and time. If <CODE>print-category</CODE> is requested, then the category of the message will be logged as well. Finally, if -<CODE>print-severity</CODE> is on, then the severity level of the +<CODE>print-severity</CODE> is on, the severity level of the message will be logged. The <CODE>print-</CODE> options may be used in any combination, and will always be printed in the following order: time, category, severity. Here is an example where all three @@ -197,7 +218,7 @@ logging by pointing categories at channels you have defined.</P> <P>There are many categories, so you can send the logs you want to see wherever you want, without seeing logs you don't want. If you don't specify -a list of channels for a category, then log messages in that category will +a list of channels for a category, log messages in that category will be sent to the <CODE>default</CODE> category instead. If you don't specify a default category, the following "default default" is used: @@ -337,12 +358,12 @@ Messages arising from response checking, such as <HR> <CENTER><P>[ <A HREF="config.html">BIND Config. File</A> -| <A HREF="http://www.vix.com/isc/bind.html">BIND Home</A> -| <A HREF="http://www.isc.org">ISC</A> ]</P></CENTER> +| <A HREF="http://www.isc.org/products/BIND/">BIND Home</A> +| <A HREF="http://www.isc.org/">ISC</A> ]</P></CENTER> <HR> <ADDRESS> -Last Updated: $Id: logging.html,v 1.7 1998/04/23 19:58:35 halley Exp $ +Last Updated: $Id: logging.html,v 1.12 1999/09/30 17:58:35 cyarnell Exp $ </ADDRESS> </BODY> </HTML> diff --git a/contrib/bind/doc/html/master.html b/contrib/bind/doc/html/master.html new file mode 100644 index 0000000..ff4ba0a --- /dev/null +++ b/contrib/bind/doc/html/master.html @@ -0,0 +1,166 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"> +<HTML> +<HEAD> + <TITLE>Master File Format</TITLE> +</HEAD> + +<BODY> +<H2>BIND Configuration Guide -- Master File Format</H2> + +<HR> + +<P> +The Master File Format was initially defined in +<A HREF=http://ds.internic.net/rfc/rfc1035.txt>RFC 1035</A> +and has subsequently been extended. +<P> +While the Master File Format is class independent all records in a +Master File must be of the same class. + +<H3>Master File Directives</H3> +<H4>$ORIGIN</H4> +Syntax: <CODE>$ORIGIN <domain-name> [<comment>]</CODE> +<P> +<CODE>$ORIGIN</CODE> set the domain name that will be appended to any +unqualified records. +When a zone is first read in there is an implict <CODE>$ORIGIN</CODE> +<zone-name>. +The current <CODE>$ORIGIN</CODE> is appended to the domain specified in the +<CODE>$ORIGIN</CODE> argument if it is not absolute. + +<PRE> +$ORIGIN EXAMPLE. +$ORIGIN MYZONE +WWW CNAME MAIN-SERVER +</PRE> +is equivlent to +<PRE> +WWW.MYZONE.EXAMPLE. CNAME MAIN-SERVER.MYZONE.EXAMPLE. +</PRE> + +<H4>$INCLUDE</H4> +Syntax: <CODE>$INCLUDE <filename> [<origin>] [<comment>]</CODE> +<P> +Read and process the file filename as if it was included into the file at this +point. If origin is specified the file is processed with <CODE>$ORIGIN</CODE> +set to that value otherwise the current <CODE>$ORIGIN</CODE> is used. +<I>NOTE: The behaviour when <origin> is specified differs from that +described in +<A HREF=http://ds.internic.net/rfc/rfc1035.txt>RFC 1035</A>.</I> +<P> +The origin and current domain revert to the values they were prior to the +<CODE>$INCLUDE</CODE> once the file has been read. +<H4>$TTL</H4> +Syntax: <CODE>$TTL <default-ttl> [<comment>]</CODE> +<P> +Set the default Time To Live (TTL) for subsequent records with undefined +TTL's. Valid TTL's are of the range 0-2147483647. +<P> +<CODE>$TTL</CODE> is defined in +<A HREF=http://ds.internic.net/rfc/rfc2308.txt>RFC 2308</A>. +<H3>BIND Master File Extentions</H3> +<H4>$GENERATE</H4> +Syntax: <CODE>$GENERATE <range> <lhs> <type> <rhs> +[<comment>]</CODE> +<P> +<CODE>$GENERATE</CODE> is used to create a series of resource records +that only differ from each other by an iterator. <CODE>$GENERATE</CODE> +can be used to easily generate the sets of records required to support +sub /24 reverse delegations described in +<A HREF=http://ds.internic.net/rfc/rfc2317.txt>RFC 2317: Classless IN-ADDR.ARPA delegation</A>. + +<PRE> +$ORIGIN 0.0.192.IN-ADDR.ARPA. +$GENERATE 1-2 0 NS SERVER$.EXAMPLE. +$GENERATE 1-127 $ CNAME $.0 +</PRE> +is equivalent to +<PRE> +0.0.0.192.IN-ADDR.ARPA NS SERVER1.EXAMPLE. +0.0.0.192.IN-ADDR.ARPA NS SERVER2.EXAMPLE. +1.0.0.192.IN-ADDR.ARPA CNAME 1.0.0.0.192.IN-ADDR.ARPA. +2.0.0.192.IN-ADDR.ARPA CNAME 2.0.0.0.192.IN-ADDR.ARPA. +... +127.0.0.192.IN-ADDR.ARPA CNAME 127.0.0.0.192.IN-ADDR.ARPA. +</PRE> +<DL> +<DT>range</DT> +<DD> +This can be one of two forms: +<I>start</I>-<I>stop</I> +or +<I>start</I>-<I>stop</I>/<I>step</I>. If the first form is +used then step is set to 1. All of start, stop and step must be positive. +<DT>lhs</DT> +<DD> +Lhs describes the owner name of the resource records to be created. +Any single $ symbols within the LHS side are replaced by the iterator value. +To get a $ in the output use \$. If the lhs is not absolute +the current $ORIGIN is appended to the name, when appropriate. +You can also apply an offset to the iterator by using ${offset} where +offset is a decimal value to add to the iterator. +And you can also change the format of the iterator by using a printf +like string. The format is ${offset,width,radix} where offset is as before +(use 0 for no change), width is the minimum field width (always zero padded) +radix is one of d, o, x, or X to change the radix to decimal, octal, hex, or hex +with capital letters. +The default is ${0,1,d}. +For example: ${16,3} will add 16 to the iterator and be replaced by +a 3 digit decimal representation. ${0,2,x} will be replaced by a 2 digit +hex representation. To get a { character inserted into the text +immediately after the iterator, use $\{. +<DT>type</DT> +<DD> +At present the only supported types are A, AAAA, PTR, CNAME and NS. +<DT>rhs</DT> +<DD> +Rhs is the data. It is processed similarly to the lhs. +<DD> +</DL> +<H2>Resource Records</H2> +Syntax: <CODE>{<domain>|@|<blank>} +[<ttl>] [<class>] <type> <rdata> +[<comment>]</CODE> +<P> +All resource records have the same basic syntax. +<DL> +<DT><CODE>domain</CODE></DT> +<DD> +Specify the domain name for this record. If it is not absolute the +current <CODE>$ORIGIN</CODE> is appended. +<DT><CODE>@</CODE></DT> +<DD> +Use the current <CODE>$ORIGIN</CODE> for the domain name for this record. +<DT><CODE>blank</CODE></DT> +<DD> +Use the last specified domainname. +<DT><CODE>ttl</CODE></DT> +<DD> +This specifies how long this record will be cached by caching servers. +The valid range is 0-2147483647. +<DT><CODE>class</CODE></DT> +<DD> +Specify the class of this record. This is usually redundent as the +class of a zone is specfied in the configuration file prior to reading +the zone file. +<DT><CODE>type</CODE></DT> +<DD> +Specify the type of this record. This describes the contents of the rdata +section. +<DT><CODE>rdata</CODE></DT> +<DD> +This is the value of the resource record. +</DL> +<H2>Time Values: Alternate Specification format (BIND Enhancement)</H2> +<P> +Many time values within the MASTER file may be specified in multiples +of weeks, days, hours, minutes and seconds rather than just seconds. +<P> +The format for this is <CODE>#w#d#h#m#s</CODE>. To specify 1 week you would +use <CODE>1w</CODE> or two weeks and 1 hour <CODE>2w1h</CODE>. +<P> +This format applies to TTL values, and SOA REFRESH, RETRY, EXPIRE and MINIMUM +values. +</P> +</BODY> +</HTML> diff --git a/contrib/bind/doc/html/options.html b/contrib/bind/doc/html/options.html index 515ee96..e3e09ef 100644 --- a/contrib/bind/doc/html/options.html +++ b/contrib/bind/doc/html/options.html @@ -13,6 +13,7 @@ <PRE> options { + [ version <VAR>version_string</VAR>; ] [ directory <VAR>path_name</VAR>; ] [ named-xfer <VAR>path_name</VAR>; ] [ dump-file <VAR>path_name</VAR>; ] @@ -21,37 +22,55 @@ options { [ statistics-file <VAR>path_name</VAR>; ] [ auth-nxdomain <VAR><A HREF="docdef.html">yes_or_no</A></VAR>; ] [ deallocate-on-exit <VAR><A HREF="docdef.html">yes_or_no</A></VAR>; ] + [ dialup <VAR><A HREF="docdef.html">yes_or_no</A></VAR>; ] [ fake-iquery <VAR><A HREF="docdef.html">yes_or_no</A></VAR>; ] [ fetch-glue <VAR><A HREF="docdef.html">yes_or_no</A></VAR>; ] + [ has-old-clients <VAR><A HREF="docdef.html">yes_or_no</A></VAR>; ] [ host-statistics <VAR><A HREF="docdef.html">yes_or_no</A></VAR>; ] [ multiple-cnames <VAR><A HREF="docdef.html">yes_or_no</A></VAR>; ] [ notify <VAR><A HREF="docdef.html">yes_or_no</A></VAR>; ] [ recursion <VAR><A HREF="docdef.html">yes_or_no</A></VAR>; ] + [ rfc2308-type1 <VAR><A HREF="docdef.html">yes_or_no</A></VAR>; ] + [ use-id-pool <VAR><A HREF="docdef.html">yes_or_no</A></VAR>; ] + [ treat-cr-as-space <VAR><A HREF="docdef.html">yes_or_no</A></VAR>; ] + [ also-notify { <VAR><A HREF="docdef.html">ip_addr</A></VAR>; [ <VAR><A HREF="docdef.html">ip_addr</A></VAR>; ... ] }; [ forward ( only | first ); ] [ forwarders { [ <VAR><A HREF="docdef.html">in_addr</A></VAR> ; [ <VAR><A HREF="docdef.html">in_addr</A></VAR> ; ... ] ] }; ] [ check-names ( master | slave | response ) ( warn | fail | ignore); ] [ allow-query { <VAR>address_match_list</VAR> }; ] [ allow-transfer { <VAR>address_match_list</VAR> }; ] + [ allow-recursion { <VAR>address_match_list</VAR> }; ] + [ blackhole { <VAR>address_match_list</VAR> }; ] [ listen-on [ port <VAR><A HREF="docdef.html">ip_port</A></VAR> ] { <VAR>address_match_list</VAR> }; ] [ query-source [ address ( <VAR><A HREF="docdef.html">ip_addr</A></VAR> | * ) ] [ port ( <VAR><A HREF="docdef.html">ip_port</A></VAR> | * ) ] ; ] + [ lame-ttl <VAR>number</VAR>; ] [ max-transfer-time-in <VAR>number</VAR>; ] + [ max-ncache-ttl <VAR>number</VAR>; ] + [ min-roots <VAR>number</VAR>; ] + [ serial-queries <VAR>number</VAR>; ] [ transfer-format ( one-answer | many-answers ); ] [ transfers-in <VAR>number</VAR>; ] [ transfers-out <VAR>number</VAR>; ] [ transfers-per-ns <VAR>number</VAR>; ] + [ transfer-source <VAR><A HREF="docdef.html">ip_addr</A></VAR>; ] + [ maintain-ixfr-base <VAR><A HREF="docdef.html">yes_or_no</A></VAR>; ] + [ max-ixfr-log-size <VAR>number</VAR>; ] [ coresize <VAR><A HREF="docdef.html">size_spec</A></VAR> ; ] [ datasize <VAR><A HREF="docdef.html">size_spec</A></VAR> ; ] [ files <VAR><A HREF="docdef.html">size_spec</A></VAR> ; ] [ stacksize <VAR><A HREF="docdef.html">size_spec</A></VAR> ; ] [ cleaning-interval <VAR>number</VAR>; ] + [ heartbeat-interval <VAR>number</VAR>; ] [ interface-interval <VAR>number</VAR>; ] [ statistics-interval <VAR>number</VAR>; ] - [ topology { <VAR>address_match_list</VAR> }; ] + [ <A HREF="#topology">topology</A> { <VAR>address_match_list</VAR> }; ] + [ <A HREF="#sortlist">sortlist</A> { <VAR>address_match_list</VAR> }; ] + [ rrset-order { <VAR>order_spec</VAR> ; [ <VAR>order_spec</VAR> ; ... ] ] }; }; </PRE> <HR> -<A NAME="Usage"><H3>Definition and Use</H3></A> +<A NAME="Usage"><H3>Definition and Usage</H3></A> <P>The options statement sets up global options to be used by BIND. This statement may appear at only once in a @@ -63,6 +82,13 @@ an options block with each option set to its default will be used.</P> <H4>Pathnames</H4> <DL> +<DT><CODE>version</CODE> +<DD> +The version the server should report via the <VAR>ndc</VAR> command +or via a query of name <CODE>version.bind</CODE> in class <I>chaos</I>. +The default is the real version number of the server, but some server +operators prefer the string <CODE>"surely you must be joking"</CODE>. + <DT><CODE>directory</CODE> <DD> The working directory of the server. Any non-absolute @@ -86,7 +112,7 @@ specified, the default is "named_dump.db". <DT><CODE>memstatistics-file</CODE> <DD> -The pathname of the file the server writes memory usage statistics to on exit, +The pathname of the file the server writes memory usage statistics to, on exit, if <CODE>deallocate-on-exit</CODE> is <CODE>yes</CODE>. If not specified, the default is "named.memstats". @@ -110,7 +136,7 @@ specified, the default is "named.stats". <DL> <DT><CODE>auth-nxdomain</CODE> <DD> -If <CODE>yes</CODE>, then the <CODE>AA</CODE> bit is always set on +If <CODE>yes</CODE>, the <CODE>AA</CODE> bit is always set on NXDOMAIN responses, even if the server is not actually authoritative. The default is <CODE>yes</CODE>. Do not turn off <CODE>auth-nxdomain</CODE> unless you are sure you know what you are @@ -118,12 +144,36 @@ doing, as some older software won't like it. <DT><CODE>deallocate-on-exit</CODE> <DD> -If <CODE>yes</CODE>, then when the server exits it will painstakingly -deallocate every object it allocated, and then write a memory usage report to +If <CODE>yes</CODE>, the server will painstakingly deallocate every object it +it allocated, when it exits, and then write a memory usage report to the <CODE>memstatistics-file</CODE>. The default is <CODE>no</CODE>, because it is faster to let the operating system clean up. <CODE>deallocate-on-exit</CODE> is handy for detecting memory leaks. +<DT><CODE>dialup</CODE> +<DD> +If <CODE>yes</CODE>, the server treats all zones as if they are +doing zone transfers across a dial on demand dialup link, which can +be brought up by traffic originating from this server. This has +different effects according to zone type and concentrates the zone +maintenance so that it all happens in a short interval, once every +<CODE>heartbeat-interval</CODE> and hopefully during the one call. +It also suppresses some of the normal zone maintainance traffic. +The default is <CODE>no</CODE>. The <CODE>dialup</CODE> +option may also be specified in the <CODE>zone</CODE> statement, in which +case it overrides the <CODE>options dialup</CODE> statement. + +<P> +If the zone is a <CODE>master</CODE> zone, the server will send out +NOTIFY request to all the slaves. This will trigger the "zone up to +date checking" in the slave (providing it supports NOTIFY), allowing +the <CODE>slave</CODE> to verify the zone while the call us up. + +<P> +If the zone is a <CODE>slave</CODE> or <CODE>stub</CODE> zone, the server +will suppress the regular "zone up to date" queries and only perform +them when the <CODE>heartbeat-interval</CODE> expires. + <DT><CODE>fake-iquery</CODE> <DD> If <CODE>yes</CODE>, the server will simulate the obsolete DNS query type @@ -137,15 +187,29 @@ a response. <CODE>fetch-glue no</CODE> can be used in conjunction with <CODE>recursion no</CODE> to prevent the server's cache from growing or becoming corrupted (at the cost of requiring more work from the client). +<DT><CODE>has-old-clients</CODE> +<DD> +Setting the option to <CODE>yes</CODE> is equivalent to setting the follow +three options <CODE>auth-nxdomain yes;</CODE>, <CODE>maintain-ixfr-base +yes;</CODE> and <CODE>rfc2308-type1 no;</CODE>. +The use of <CODE>has-old-clients</CODE> with <CODE>auth-nxdomain</CODE>, +<CODE>maintain-ixfr-base</CODE> and <CODE>rfc2308-type1</CODE> is order +dependant. + <DT><CODE>host-statistics</CODE> <DD> -If <CODE>yes</CODE>, then statistics are kept for every host that the +If <CODE>yes</CODE>, statistics are kept for every host that the the nameserver interacts with. The default is <CODE>no</CODE>. <I>Note:</I> turning on <CODE>host-statistics</CODE> can consume huge amounts of memory. +<DT><CODE>maintain-ixfr-base</CODE> +<DD> +If <CODE>yes</CODE>, a transaction log is kept for +Incremental Zone Transfer. The default is <CODE>no</CODE>. + <DT><CODE>multiple-cnames</CODE> <DD> -If <CODE>yes</CODE>, then multiple CNAME resource records will be +If <CODE>yes</CODE>, multiple CNAME resource records will be allowed for a domain name. The default is <CODE>no</CODE>. Allowing multiple CNAME records is against standards and is not recommended. Multiple CNAME support is available because previous versions of BIND @@ -157,24 +221,62 @@ balancing by a number of sites. If <CODE>yes</CODE> (the default), DNS NOTIFY messages are sent when a zone the server is authoritative for changes. The use of NOTIFY speeds convergence between the master and its slaves. Slave servers -that receive a NOTIFY message and understand it will contact the -master server for the zone and see if they need to do a zone transfer, and -if they do, they will initiate it immediately. The <CODE>notify</CODE> +that receive a NOTIFY message, and understand it, will contact the +master server for the zone to see if they need to do a zone transfer. If +they do, they will initiate it immediately. The <CODE>notify</CODE> option may also be specified in the <CODE>zone</CODE> statement, in which case it overrides the <CODE>options notify</CODE> statement. <DT><CODE>recursion</CODE> <DD> -If <CODE>yes</CODE>, and a DNS query requests recursion, then the +If <CODE>yes</CODE>, and a DNS query requests recursion, the server will attempt to do all the work required to answer the query. If recursion is not on, the server will return a referral to the client if it doesn't know the answer. The default is <CODE>yes</CODE>. See also <CODE>fetch-glue</CODE> above. + +<DT><CODE>rfc2308-type1</CODE> +<DD> +If <CODE>yes</CODE>, the server will send NS records along with the SOA +record for negative answers. +You need to set this to <CODE>no</CODE> if you have an old BIND +server using you as a forwarder that does not understand negative answers +which contain both SOA and NS records or you have an old version of sendmail. +The correct fix is to upgrade the broken server or sendmail. +The default is <CODE>no</CODE>. + +<DT><CODE>use-id-pool</CODE> +<DD> +If <CODE>yes</CODE>, the server will keep track of its own outstanding +query ID's to avoid duplication and increase randomness. This will result +in 128KB more memory being consumed by the server. +The default is <CODE>no</CODE>. + +<DT><CODE>treat-cr-as-space</CODE> +<DD> +If <CODE>yes</CODE>, the server will treat '\r' characters the same way it +treats a ' ' or '\t'. This may be necessary when loading zone files on a +UNIX system that were generated on an NT or DOS machine. The default is <CODE>no</CODE>. + </DL> -<H4>Forwarding</H4> +<A NAME="Also-notify"><H4>Also-Notify</H4></A> + +<DT><CODE>also-notify</CODE> +<P> +Defines a global list of IP addresses that also get sent NOTIFY messages +whenever a fresh copy of the zone is loaded. This helps to ensure that +copies of the zones will quickly converge on ``stealth'' servers. +If an <CODE>also-notify</CODE> list is given in a <CODE>zone</CODE> +statement, it will override the <CODE>options also-notify</CODE> statement. +When a <CODE>zone notify</CODE> statement is set to <CODE>no</CODE>, +the IP addresses in the global <CODE>also-notify</CODE> list will not get +sent NOTIFY messages for that zone. +The default is the empty list (no global notification list). + +<A NAME="Forwarding"><H4>Forwarding</H4></A> -<P>The forwarding facility can be used to create a large sitewide +<P>The forwarding facility can be used to create a large site-wide cache on a few servers, reducing traffic over links to external nameservers. It can also be used to allow queries by servers that do not have direct access to the Internet, but wish to look up exterior @@ -197,6 +299,13 @@ Specifies the IP addresses to be used for forwarding. The default is the empty list (no forwarding). </DL> +<P>Forwarding can also be configured on a per-zone basis, allowing for +the global forwarding options to be overridden in a variety of ways. +You can set particular zones to use different forwarders, or have +different <CODE>forward only/first</CODE> behavior, or to not forward +at all. See the <A HREF="zone.html"><CODE>zone</CODE></A> statement +for more information. + <P>Future versions of BIND 8 will provide a more powerful forwarding system. The syntax described above will continue to be supported. @@ -239,7 +348,8 @@ client. check-names response ignore; </PRE> -<P><CODE>check-names</CODE> may also be specified in the <CODE>zone</CODE> +<P><CODE>check-names</CODE> may also be specified in the +<A HREF="zone.html"><CODE>zone</CODE></A> statement, in which case it overrides the <CODE>options check-names</CODE> statement. When used in a <CODE>zone</CODE> statement, the area is not specified (because it can be deduced from the zone type). @@ -267,6 +377,18 @@ server. <CODE>allow-transfer</CODE> may also be specified in the <CODE>zone</CODE> statement, in which case it overrides the <CODE>options allow-transfer</CODE> statement. If not specified, the default is to allow transfers from all hosts. + +<DT><CODE>allow-recursion</CODE> +<DD> +Specifies which hosts are allowed to make recursive queries through this +server. If not specified, the default is to allow recursive queries from +all hosts. + +<DT><CODE>blackhole</CODE> +<DD> +Specifies a list of addresses that the server will not accept queries from +or use to resolve a query. Queries from these addresses will not be +responded to. </DL> <H4>Interfaces</H4> @@ -285,6 +407,10 @@ not specified, port 53 will be used. listen-on port 1234 { !1.2.3.4; 1.2/16; }; </PRE> +will enable the nameserver on port 53 for the IP address 5.6.7.8, and +on port 1234 of an address on the machine in net 1.2 that is not +1.2.3.4. + <P>If no <CODE>listen-on</CODE> is specified, the server will listen on port 53 on all interfaces. @@ -321,7 +447,7 @@ The server supports two zone transfer methods. <CODE>one-answer</CODE> uses one DNS message per resource record transferred. <CODE>many-answers</CODE> packs as many resource records as possible into a message. <CODE>many-answers</CODE> is more -efficient, but is only known to be understood by BIND 8.1 and patched +efficient, but is only known to be understood by BIND 8.1+ and patched versions of BIND 4.9.5. The default is <CODE>one-answer</CODE>. <CODE>transfer-format</CODE> may be overridden on a per-server basis by using the <CODE>server</CODE> statement. @@ -349,6 +475,36 @@ zones, but it also may increase the load on the remote nameserver. <CODE>transfers-per-ns</CODE> may be overridden on a per-server basis by using the <CODE>transfers</CODE> phrase of the <CODE>server</CODE> statement. + +<DT><CODE>transfer-source</CODE> +<DD> +<CODE>transfer-source</CODE> determines which local address will be bound +to the TCP connection used to fetch all zones transferred inbound by the +server. If not set, it defaults to a system controlled value which will +usually be the address of the interface ``closest to'' the remote end. +This address must appear in the remote end's <CODE>allow-transfer</CODE> +option for the zone being transferred, if one is specified. This statement +sets the <CODE>transfer-source</CODE> for all zones, but can be overridden +on a per-zone basis by including a <CODE>transfer-source</CODE> statement +within the zone block in the configuration file. + +<DT><CODE>serial-queries</CODE> +<DD> +Slave servers will periodically query master servers to find out if zone +serial numbers have changed. Each such query uses a minute amount of the +slave server's network bandwidth, but more importantly each query uses a +small amount of <I>memory</I> in the slave server while waiting for the +master server to respond. The <CODE>serial-queries</CODE> option sets the +maximum number of concurrent serial-number queries allowed to be outstanding +at any given time. The default is four (4). +<B>Note:</B> +If a server loads a large (tens or hundreds of thousands) number of slave +zones, this limit should be raised to the high hundreds or low +thousands -- otherwise the slave server may never actually become aware of +zone changes in the master servers. Beware, though, that setting this limit +arbitrarily high can spend a considerable amount of your slave server's +network, CPU, and memory resources. As with all tunable limits, this one +should be changed gently and monitored for its effects. </DL> <H4>Resource Limits</H4> @@ -366,7 +522,7 @@ example, <CODE>1G</CODE> can be used instead of <CODE>unlimited</CODE> requests unlimited use, or the maximum available amount. <CODE>default</CODE> uses the limit that was in force when the server was started. See -<VAR><AHREF="docdef.html">size_spec</A></VAR> for more details. +<VAR><A HREF="docdef.html">size_spec</A></VAR> for more details. <DL> <DT><CODE>coresize</CODE> @@ -380,7 +536,7 @@ The maximum amount of data memory the server may use. The default is <DT><CODE>files</CODE> <DD> -The maximum number of files ther server may have open concurrently. +The maximum number of files the server may have open concurrently. The default is <CODE>unlimited</CODE>. <I>Note:</I> on some operating systems the server cannot set an unlimited value and cannot determine the maximum number of open files the kernel can support. On such @@ -390,6 +546,12 @@ and the value returned by <CODE>sysconf(_SC_OPEN_MAX)</CODE>. If the actual kernel limit is larger than this value, use <CODE>limit files</CODE> to specify the limit explicitly. +<DT><CODE>max-ixfr-log-size</CODE> +<DD> +The <CODE>max-ixfr-log-size</CODE> will be used in a future release of +the server to limit the size of the +transaction log kept for Incremental Zone Transfer. + <DT><CODE>stacksize</CODE> <DD> The maximum amount of stack memory the server may use. The default is @@ -405,6 +567,12 @@ The server will remove expired resource records from the cache every <CODE>cleaning-interval</CODE> minutes. The default is 60 minutes. If set to 0, no periodic cleaning will occur. +<DT><CODE>heartbeat-interval</CODE> +<DD> +The server will perform zone maintenance tasks for all zones marked +<CODE>dialup yes</CODE> whenever this interval expires. +The default is 60 minutes. Reasonable values are up to 1 day (1440 minutes). +If set to 0, no zone maintenance for these zones will occur. <DT><CODE>interface-interval</CODE> <DD> The server will scan the network interface list every @@ -417,11 +585,11 @@ cleaned up. <DT><CODE>statistics-interval</CODE> <DD> -Nameserver statisitics will be logged every <CODE>statistics-interval</CODE> +Nameserver statistics will be logged every <CODE>statistics-interval</CODE> minutes. The default is 60. If set to 0, no statistics will be logged. </DL> -<H4>Topology</H4> +<H4><A NAME="topology">Topology</A></H4> <P>All other things being equal, when the server chooses a nameserver to query from a list of nameservers, it prefers the one that is @@ -455,15 +623,192 @@ of all. topology { localhost; localnets; }; </PRE> +<H4><A NAME="sortlist">Resource Record sorting</A></H4> + +<P> +When returning multiple RRs, +the nameserver will normally return them in +<B>Round Robin</B>, +i.e. after each request, the first RR is put to the end of the list. +As the order of RRs is not defined, this should not cause any problems. +</P> +<P> +The client resolver code should re-arrange the RRs as appropriate, +i.e. using any addresses on the local net in preference to other addresses. +However, not all resolvers can do this, or are not correctly configured. +</P> +<P> +When a client is using a local server, the sorting can be performed in the +server, based on the client's address. +This only requires configuring the nameservers, not all the clients. +</P> +<P> +The sortlist statement takes an address match list and interprets it even +more specially than the <A HREF="#topology">topology</A> statement does. +</P> +<P> +Each top level statement in the sortlist must itself be an explicit +address match list with one or two elements. The first element +(which may be an IP address, an IP prefix, an ACL name or nested +address match list) of each top level list is checked against the +source address of the query until a match is found. +</P> +<P> +Once the source address of the query has been matched, if the top level +statement contains only one element, the actual primitive element that +matched the source address is used to select the address in the response +to move to the beginning of the response. If the statement is a list +of two elements, the second element is treated like the address +match list in a topology statement. Each top level element is assigned +a distance and the address in the response with the minimum distance is +moved to the beginning of the response. +</P> +<P> +In the following example, any queries received from any of the addresses +of the host itself will get responses preferring addresses on any of +the locally connected networks. Next most preferred are addresses on +the 192.168.1/24 network, and after that either the 192.168.2/24 or +192.168.3/24 network with no preference shown between these two networks. +Queries received from a host on the 192.168.1/24 network will prefer +other addresses on that network to the 192.168.2/24 and 192.168.3/24 +networks. Queries received from a host on the 192.168.4/24 or the +192.168.5/24 network will only prefer other addresses on their +directly connected networks. +<PRE> +sortlist { + { localhost; // IF the local host + { localnets; // THEN first fit on the + 192.168.1/24; // following nets + { 192,168.2/24; 192.168.3/24; }; }; }; + { 192.168.1/24; // IF on class C 192.168.1 + { 192.168.1/24; // THEN use .1, or .2 or .3 + { 192.168.2/24; 192.168.3/24; }; }; }; + { 192.168.2/24; // IF on class C 192.168.2 + { 192.168.2/24; // THEN use .2, or .1 or .3 + { 192.168.1/24; 192.168.3/24; }; }; }; + { 192.168.3/24; // IF on class C 192.168.3 + { 192.168.3/24; // THEN use .3, or .1 or .2 + { 192.168.1/24; 192.168.2/24; }; }; }; + { { 192.168.4/24; 192.168.5/24; }; // if .4 or .5, prefer that net + }; +}; +</PRE> +The following example will give reasonable behaviour for the local host +and hosts on directly connected networks. It is similar to the behavior +of the address sort in BIND 4.9.x. Responses sent to queries from the +local host will favor any of the directly connected networks. Responses +sent to queries from any other hosts on a directly connected network will +prefer addresses on that same network. Responses to other queries will +not be sorted. +<PRE> +sortlist { + { localhost; localnets; }; + { localnets; }; +}; +</PRE> +<!-- + * XXX - it would be nice to have an ACL called "source" that matched the + * source address of a query so that a host could be configured to + * automatically prefer itself, and an ACL called "sourcenet", that + * would return the primitive IP match element that matched the source + * address so that you could do: + * { localnets; { sourcenet; { other stuff ...}; }; + * and automatically get similar behaviour to what you get with: + * { localnets; }; +--> +</P> + +<a name="RrsetOrder"> +<H4>RRset Ordering</H4> + +<P>When multiple records are returned in an answer it may be useful to +configure the order the records are placed into the response. For example the +records for a zone might be configured to always be returned in the order they +are defined in the zone file. Or perhaps a <i>random</i> shuffle of the +records as they are returned is wanted. The <var>rrset-order</var> statement +permits configuration of the ordering made of the records in a multiple record +response. The default, if no ordering is defined, is a cyclic ordering (round +robin). + +<P>An <var>order_spec</var> is defined as follows: + +<PRE> + [ <var>class</var> class_name ][ <var>type</var> type_name ][ <var>name</var> "FQDN" ] <var>order</var> ordering +</PRE> + +<P>If no <var>class</var> is specified, the default is <code>ANY</code>. If no +<var>type</var> is specified, the default is <code>ANY</code>. If no +<var>name</var> is specified, the default is <code>"*"</code>. + +<P>The legal values for <code>ordering</code> are: + +<DL> +<DT><code>fixed</code> +<DD>Records are returned in the order they are defined in the zone file. + +<DT><code>random</code> +<DD>Records are returned in some random order. + +<DT><code>cyclic</code> +<DD>Records are returned in a round-robin order. + +</DL> + + +<P>For example: + +<PRE> + rrset-order { + class IN type A name "rc.vix.com" order random; + order cyclic; + }; +</PRE> + +<P>will cause any responses for type <VAR>A</VAR> records in class +<VAR>IN</VAR> that have "rc.vix.com" as a suffix, to always be returned in +random order. All other records are returned in cyclic order. + +<P>If multiple <code>rrset-order</code> statements appear, they are not +combined--the last one applies. + +<P>If no <code>rrset-order</code> statement is specified, a default one +of: + +<pre> + rrset-order { class ANY type ANY name "*" order cyclic ; }; +</pre> + +<P>is used. + +<H4>Tuning</H4> + +<DL> +<DT><CODE>lame-ttl</CODE> +<DD> +Sets the number of seconds to cache a lame server indication. +0 disables caching. Default is 600 (10 minutes). Maximum value is 1800 (30 minutes). +<DT><CODE>max-ncache-ttl</CODE> +<DD> +To reduce network traffic and increase performance the server stores negative +answers. <CODE>max-ncache-ttl</CODE> is used to set a maximum retention time +for these answers in the server is seconds. The default <CODE>max-ncache-ttl</CODE> is +10800 seconds (3 hours). <CODE>max-ncache-ttl</CODE> cannot exceed the +maximum retention time for ordinary (positive) answers (7 days) and will be +silently truncated to 7 days if set to a value which is greater that 7 days. +<DT><CODE>min-roots</CODE> +<DD> +The minimum number of root servers that is required for a +request for the root servers to be accepted. Default 2. +</DL> <HR> <CENTER><P>[ <A HREF="config.html">BIND Config. File</A> -| <A HREF="http://www.vix.com/isc/bind.html">BIND Home</A> -| <A HREF="http://www.isc.org">ISC</A> ]</P></CENTER> +| <A HREF="http://www.isc.org/products/BIND/">BIND Home</A> +| <A HREF="http://www.isc.org/">ISC</A> ]</P></CENTER> <HR> <ADDRESS> -Last Updated: $Id: options.html,v 1.10 1998/05/05 19:50:28 halley Exp $ +Last Updated: $Id: options.html,v 1.36 1999/10/13 20:57:05 cyarnell Exp $ </ADDRESS> </BODY> </HTML> diff --git a/contrib/bind/doc/html/server.html b/contrib/bind/doc/html/server.html index 0eb4dca..eba350b 100644 --- a/contrib/bind/doc/html/server.html +++ b/contrib/bind/doc/html/server.html @@ -14,6 +14,7 @@ <PRE> server <VAR><A HREF="docdef.html">ip_addr</A></VAR> { [ bogus <VAR><A HREF="docdef.html">yes_or_no</A></VAR>; ] + [ support-ixfr <VAR><A HREF="docdef.html">yes_or_no</A></VAR>; ] [ transfers <VAR><A HREF="docdef.html">number</A></VAR>; ] [ transfer-format ( one-answer | many-answers ); ] [ keys { <VAR><A HREF="key.html">key_id</A></VAR> [<VAR>key_id</VAR> ... ] }; ] @@ -45,18 +46,24 @@ specified by the <CODE>options</CODE> statement will be used. to limit the number of concurrent in-bound zone transfers from the specified server. It is checked for syntax but is otherwise ignored. -<P>The <CODE>keys</CODE> statement is intended for future use by the -server. It is checked for syntax but is otherwise ignored. +<P>The <CODE>keys</CODE> clause is used to identify a +<VAR>key_id</VAR> defined by the <CODE>key</CODE> statement, to be +used for transaction security when talking to the remote server. +The <CODE>key</CODE> statememnt must come before the <CODE>server</CODE> +statement that references it. When a request is sent to the remote server, +a request signature will be generated using the key specified here and +appended to the message. A request originating from the remote server is not +required to be signed by this key. <HR> <CENTER><P>[ <A HREF="config.html">BIND Config. File</A> -| <A HREF="http://www.vix.com/isc/bind.html">BIND Home</A> -| <A HREF="http://www.isc.org">ISC</A> ]</P></CENTER> +| <A HREF="http://www.isc.org/products/BIND/">BIND Home</A> +| <A HREF="http://www.isc.org/">ISC</A> ]</P></CENTER> <HR> <ADDRESS> -Last Updated: $Id: server.html,v 1.6 1998/03/21 01:03:13 halley Exp $ +Last Updated: $Id: server.html,v 1.10 1999/09/15 20:28:02 cyarnell Exp $ </ADDRESS> </BODY> </HTML> diff --git a/contrib/bind/doc/html/trusted-keys.html b/contrib/bind/doc/html/trusted-keys.html new file mode 100644 index 0000000..acf2bed --- /dev/null +++ b/contrib/bind/doc/html/trusted-keys.html @@ -0,0 +1,58 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"> +<HTML> +<HEAD> + <TITLE>BIND trusted-keys Statement</TITLE> +</HEAD> + +<BODY> +<H2>BIND Configuration File Guide--<CODE>trusted-keys</CODE> Statement</H2> + +<HR> + +<A NAME="Syntax"><H3>Syntax</H3></A> + +<PRE> +trusted-keys { + [ <VAR><A HREF="docdef.html">domain_name</A></VAR> <VAR><A HREF="docdef.html">number</A></VAR> <VAR><A HREF="docdef.html">number</A></VAR> <VAR><A HREF="docdef.html">number</A></VAR> <VAR>string</VAR>; ] +}; + +</PRE> + +<HR> + +<A NAME="Usage"><H3>Definition and Usage</H3></A> + +The <CODE>trusted-keys</CODE> +statement is for use with DNSSEC-style security, originally specified +in RFC 2065. DNSSEC is meant to +provide three distinct services: key distribution, data origin +authentication, and transaction and request authentication. A +complete description of DNSSEC and its use is beyond the scope of this +document, and readers interested in more information should start with +<A HREF="http://info.internet.isi.edu/in-notes/rfc/files/rfc2065.txt"> +RFC 2065</A> and then continue with the +<A HREF="http://www.ietf.org/ids.by.wg/dnssec.html"> +Internet Drafts</A>.</P> + +<P>Each trusted key is associated with a domain name. Its attributes are +the non-negative integral <VAR>flags</VAR>, <VAR>protocol</VAR>, and +<VAR>algorithm</VAR>, as well as a base-64 encoded string representing +the key.</P> + +A trusted key is added when a public key for a non-authoritative zone is +known, but cannot be securely obtained through DNS. This occurs when +a signed zone is a child of an unsigned zone. Adding the trusted +key here allows data signed by that zone to be considered secure.</P> + +<HR> + +<CENTER><P>[ <A HREF="config.html">BIND Config. File</A> +| <A HREF="http://www.isc.org/products/BIND/">BIND Home</A> +| <A HREF="http://www.isc.org/">ISC</A> ]</P></CENTER> + +<HR> +<ADDRESS> +Last Updated: $Id: trusted-keys.html,v 1.4 1999/09/15 20:28:02 cyarnell Exp $ +</ADDRESS> +</BODY> +</HTML> diff --git a/contrib/bind/doc/html/zone.html b/contrib/bind/doc/html/zone.html index b6edb38..8d90a45 100644 --- a/contrib/bind/doc/html/zone.html +++ b/contrib/bind/doc/html/zone.html @@ -15,25 +15,43 @@ zone <VAR><A HREF="docdef.html">domain_name</A></VAR> [ ( in | hs | hesiod | chaos ) ] { type master; file <VAR><A HREF="docdef.html">path_name</A></VAR>; + [ forward ( only | first ); ] + [ forwarders { [ <VAR><A HREF="docdef.html">ip_addr</A></VAR> ; [ <VAR>ip_addr</VAR> ; ... ] ] }; ] [ check-names ( warn | fail | ignore ); ] - [ allow-update { <VAR><A NAME="address_list.html">address_match_list</A></VAR> }; ] - [ allow-query { <VAR><A NAME="address_list.html">address_match_list</A></VAR> }; ] - [ allow-transfer { <VAR><A NAME="address_list.html">address_match_list</A></VAR> }; ] + [ allow-update { <VAR><A HREF="address_list.html">address_match_list</A></VAR> }; ] + [ allow-query { <VAR><A HREF="address_list.html">address_match_list</A></VAR> }; ] + [ allow-transfer { <VAR><A HREF="address_list.html">address_match_list</A></VAR> }; ] + [ dialup <VAR><A HREF="docdef.html">yes_or_no</A></VAR>; ] [ notify <VAR><A HREF="docdef.html">yes_or_no</A></VAR>; ] [ also-notify { <VAR><A HREF="docdef.html">ip_addr</A></VAR>; [ <VAR>ip_addr</VAR>; ... ] }; + [ ixfr-base <VAR><A HREF="docdef.html">path_name</A></VAR>; ] + [ pubkey <VAR><A HREF="docdef.html">number</A></VAR> <VAR><A HREF="docdef.html">number</A></VAR> <VAR><A HREF="docdef.html">number</A></VAR> <VAR>string</VAR>; ] }; zone <VAR><A HREF="docdef.html">domain_name</A></VAR> [ ( in | hs | hesiod | chaos ) ] { type ( slave | stub ); [ file <VAR><A HREF="docdef.html">path_name</A></VAR>; ] - masters { <VAR><A HREF="docdef.html">ip_addr</A></VAR>; [ <VAR>ip_addr</VAR>; ... ] }; + [ ixfr-base <VAR><A HREF="docdef.html">path_name</A></VAR>; ] + masters [ port <VAR><A HREF="docdef.html">ip_port</A></VAR> ] { <VAR><A HREF="docdef.html">ip_addr</A></VAR>; [ <VAR>ip_addr</VAR>; ... ] }; + [ forward ( only | first ); ] + [ forwarders { [ <VAR><A HREF="docdef.html">ip_addr</A></VAR> ; [ <VAR>ip_addr</VAR> ; ... ] ] }; ] [ check-names ( warn | fail | ignore ); ] - [ allow-update { <VAR><A NAME="address_list.html">address_match_list</A></VAR> }; ] - [ allow-query { <VAR><A NAME="address_list.html">address_match_list</A></VAR> }; ] - [ allow-transfer { <VAR><A NAME="address_list.html">address_match_list</A></VAR> }; ] + [ allow-update { <VAR><A HREF="address_list.html">address_match_list</A></VAR> }; ] + [ allow-query { <VAR><A HREF="address_list.html">address_match_list</A></VAR> }; ] + [ allow-transfer { <VAR><A HREF="address_list.html">address_match_list</A></VAR> }; ] + [ transfer-source <VAR><A HREF="docdef.html">ip_addr</A></VAR>; ] + [ dialup <VAR><A HREF="docdef.html">yes_or_no</A></VAR>; ] [ max-transfer-time-in <VAR>number</VAR>; ] [ notify <VAR><A HREF="docdef.html">yes_or_no</A></VAR>; ] [ also-notify { <VAR><A HREF="docdef.html">ip_addr</A></VAR>; [ <VAR>ip_addr</VAR>; ... ] }; + [ pubkey <VAR><A HREF="docdef.html">number</A></VAR> <VAR><A HREF="docdef.html">number</A></VAR> <VAR><A HREF="docdef.html">number</A></VAR> <VAR>string</VAR>; ] +}; + +zone <VAR><A HREF="docdef.html">domain_name</A></VAR> [ ( in | hs | hesiod | chaos ) ] { + type forward; + [ forward ( only | first ); ] + [ forwarders { [ <VAR><A HREF="docdef.html">ip_addr</A></VAR> ; [ <VAR>ip_addr</VAR> ; ... ] ] }; ] + [ check-names ( warn | fail | ignore ); ] }; zone "." [ ( in | hs | hesiod | chaos ) ] { @@ -52,22 +70,50 @@ zone "." [ ( in | hs | hesiod | chaos ) ] { <DL> <DT><CODE>master</CODE> <DD> -The master copy of the data in a zone. +The server has a master copy of the data for the zone and will be able +to provide authoritative answers for it. + <DT><CODE>slave</CODE> <DD> A <CODE>slave</CODE> zone is a replica of a master zone. The <CODE>masters</CODE> list specifies one or more IP addresses that the -slave contacts to update its copy of the zone. If <CODE>file</CODE> -is specified, then the replica will be written to the file. Use of +slave contacts to update its copy of the zone. If a <CODE>port</CODE> +is specified then checks to see if the zone is current and zone transfers +will be done to the port given. If <CODE>file</CODE> +is specified, the replica will be written to this file whenever +the zone is changed, and reloaded from this file on a server restart. +Use of <CODE>file</CODE> is recommended, since it often speeds server startup -and eliminates a needless waste of bandwidth. +and eliminates a needless waste of bandwidth. Note that for large numbers +(in the tens or hundreds of thousands) of zones per server, it is best to +use a two level naming scheme for zone file names. For example, a slave +server for the zone <CODE>vix.com</CODE> might place the zone contents into +a file called <CODE>"vi/vix.com"</CODE> where <CODE>vi/</CODE> is just the +first two letters of the zone name. (Most operating systems behave very +slowly if you put 100K files into a single directory.) <DT><CODE>stub</CODE> <DD> A <CODE>stub</CODE> zone is like a slave zone, except that it replicates only the NS records of a master zone instead of the entire zone. +<DT><CODE>forward</CODE> +<DD> +A <CODE>forward</CODE> zone is used to <A HREF="options.html#Forwarding"> +direct all queries</A> in it to other servers. The specification of +options in such a zone will override any global options +declared in the <A HREF="options.html#Forwarding">options</A> statement. + +<P>If either no <CODE>forwarders</CODE> statement is present in the +zone or an empty list for <CODE>forwarders</CODE> is given, no +forwarding will be done for the zone, cancelling the effects of any +<CODE>forwarders</CODE> in the <CODE>options</CODE> statement. +Thus if you want to use this +type of zone to change the behavior of the global <CODE>forward</CODE> +option, and not the servers used, you also need to respecify the +global forwarders. + <DT><CODE>hint</CODE> <DD> The initial set of root nameservers is specified using a @@ -81,8 +127,22 @@ a hint zone.</P> <H4>Class</H4> -<P>The zone's name may optionally be followed by a class. If a class is not -specified, class <CODE>in</CODE> is used. +<P>The zone's name may optionally be followed by a class. If a class +is not specified, class <CODE>in</CODE> (for "internet"), is assumed. +This is correct for the vast majority of cases. + +<P>The <CODE>hesiod</CODE> class is for an information service from MIT's +Project Athena. It is used to share information about various systems +databases, such as users, groups, printers and so on. More +information can be found at +<A HREF="ftp://athena-dist.mit.edu/pub/ATHENA/usenix/athena_changes.PS">MIT</A>. +The keyword <CODE>hs</CODE> is a synonym for <CODE>hesiod</CODE>.</P> + +<P>Another MIT development was CHAOSnet, a LAN protocol created in the +mid-1970s. It is still sometimes seen on LISP stations and other +hardware in the AI community, and zone data for it can be specified +with the +<CODE>chaos</CODE> class.</P> <H4>Options</H4> @@ -94,7 +154,10 @@ See <A HREF="options.html#NameChecking">Name Checking</A>. <DT><CODE>allow-query</CODE> <DD> See the description of <CODE>allow-query</CODE> in the -<A HREF="options.html#AccessControl">Access Control</A> section. +<A HREF="options.html#AccessControl">Access Control</A> section. Note that +this should in general be <I>more restrictive</I> than the similar global +option of the same name; otherwise, confusing and nonworthwhile delegations +will be returned. <DT><CODE>allow-update</CODE> <DD> @@ -106,11 +169,29 @@ server. The default is to deny updates from all hosts. See the description of <CODE>allow-transfer</CODE> in the <A HREF="options.html#AccessControl">Access Control</A> section. +<DT><CODE>transfer-source</CODE> +<DD> +<CODE>transfer-source</CODE> determines which local address will be bound to +the TCP connection used to fetch this zone. If not set, it defaults to a +system controlled value which will usually be the address of the interface +``closest to'' the remote end. This address must appear in the remote end's +<CODE>allow-transfer</CODE> option for this zone if one is specified. + +<DT><CODE>ixfr-base</CODE> +<DD> +<CODE>ixfr-base</CODE> +specifies the file name used for IXFR transaction log file. + <DT><CODE>max-transfer-time-in</CODE> <DD> See the description of <CODE>max-transfer-time-in</CODE> in the <A HREF="options.html#ZoneTransfers">Zone Transfers</A> section. +<DT><CODE>dialup</CODE> +<DD> +See the description of <CODE>dialup</CODE> in +the <A HREF="options.html#BooleanOptions">Boolean Options</A> section. + <DT><CODE>notify</CODE> <DD> See the description of <CODE>notify</CODE> in @@ -124,17 +205,40 @@ NOTIFY message for this zone is made up of all the listed nameservers for the zone (other than the primary master) plus any IP addresses specified with <CODE>also-notify</CODE>. <CODE>also-notify</CODE> is not meaningful for <CODE>stub</CODE> zones. The default is the empty list. -</DL> +<DT><CODE>forward</CODE> +<DD> +<CODE>forward</CODE> is only meaningful if the zone has a +<CODE>forwarders</CODE> list. The <CODE>only</CODE> value causes the +lookup to fail after trying the <CODE>forwarders</CODE> and getting no +answer, while <CODE>first</CODE> would allow a normal lookup to be tried. + +<DT><CODE>forwarders</CODE> +<DD> +The <CODE>forwarders</CODE> option in a zone is used to override the +list of global forwarders. If it is not specified in a zone of type +<CODE>forward</CODE>, <STRONG>no</STRONG> forwarding is done for the +zone; the global options are not used. + +<DT><CODE>pubkey</CODE> +<DD> +A pubkey represents a public key for this zone. It is needed when this is the +top level authoritative zone served by this server and there is no chain of +trust to a <A HREF="trusted-keys.html">trusted key</A>. It is considered +secure, so that data that it signs will be considered secure. The DNSSEC +flags, protocol, and algorithm are specified, as well as a base-64 encoded +string representing the key. + +</DL> <HR> <CENTER><P>[ <A HREF="config.html">BIND Config. File</A> -| <A HREF="http://www.vix.com/isc/bind.html">BIND Home</A> -| <A HREF="http://www.isc.org">ISC</A> ]</P></CENTER> +| <A HREF="http://www.isc.org/products/BIND/">BIND Home</A> +| <A HREF="http://www.isc.org/">ISC</A> ]</P></CENTER> <HR> <ADDRESS> -Last Updated: $Id: zone.html,v 1.6 1998/03/21 01:03:14 halley Exp $ +Last Updated: $Id: zone.html,v 1.23 1999/09/30 17:58:41 cyarnell Exp $ </ADDRESS> </BODY> </HTML> diff --git a/contrib/bind/doc/man/Makefile b/contrib/bind/doc/man/Makefile index 4ac138f..b792ef9 100644 --- a/contrib/bind/doc/man/Makefile +++ b/contrib/bind/doc/man/Makefile @@ -16,7 +16,7 @@ ## ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ## SOFTWARE. -## Portions Copyright (c) 1996 by Internet Software Consortium +## 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 @@ -32,7 +32,7 @@ ## SOFTWARE. # -# Makefile to install the BIND 4.9 manual entries. +# Makefile to install the BIND manual entries. # # Default Configuration: # There are a set of default assignments immediately following this @@ -228,18 +228,16 @@ SYS_OPS_OUT_EXT = ${OUT_EXT}${SYS_OPS_EXT} # # User command manual entries # -CMD_BASE = dig host dnsquery +CMD_BASE = dig host dnsquery dnskeygen CMD_SRC_EXT = 1 CMD_SRC = dig.${CMD_SRC_EXT} \ host.${CMD_SRC_EXT} \ dnsquery.${CMD_SRC_EXT} \ - dnskeygen.${CMD_SRC_EXT} \ - dnssigner.${CMD_SRC_EXT} + dnskeygen.${CMD_SRC_EXT} CMD_OUT = dig.${CMD_OUT_EXT} \ host.${CMD_OUT_EXT} \ dnsquery.${CMD_OUT_EXT} \ - dnskeygen.${CMD_OUT_EXT} \ - dnssigner.${CMD_OUT_EXT} + dnskeygen.${CMD_OUT_EXT} # # named manual entries @@ -257,6 +255,13 @@ NAMED_XFER_SRC = named-xfer.${SYS_OPS_SRC_EXT} NAMED_XFER_OUT = named-xfer.${SYS_OPS_OUT_EXT} # +# named-bootconf manual entry +# +NAMED_BOOTCONF_BASE = named-bootconf +NAMED_BOOTCONF_SRC = named-bootconf.${SYS_OPS_SRC_EXT} +NAMED_BOOTCONF_OUT = named-bootconf.${SYS_OPS_OUT_EXT} + +# # nslookup manual entry # NSLOOKUP_BASE = nslookup @@ -264,26 +269,48 @@ NSLOOKUP_SRC = nslookup.${SYS_OPS_SRC_EXT} NSLOOKUP_OUT = nslookup.${SYS_OPS_OUT_EXT} # +# nsupdate manual entry +# +NSUPDATE_BASE = nsupdate +NSUPDATE_SRC = nsupdate.${SYS_OPS_SRC_EXT} +NSUPDATE_OUT = nsupdate.${SYS_OPS_OUT_EXT} + +# # Network library routines manual entries # -LIB_NETWORK_BASE = gethostbyname resolver getnetent +LIB_NETWORK_BASE = gethostbyname inet_cidr resolver hesiod getnetent \ + tsig getaddrinfo inet_cidr getipnodebyname LIB_NETWORK_SRC_EXT = 3 LIB_NETWORK_SRC = gethostbyname.${LIB_NETWORK_SRC_EXT} \ + inet_cidr.${LIB_NETWORK_SRC_EXT} \ resolver.${LIB_NETWORK_SRC_EXT} \ - getnetent.${LIB_NETWORK_SRC_EXT} + hesiod.${LIB_NETWORK_SRC_EXT} \ + getnetent.${LIB_NETWORK_SRC_EXT} \ + tsig.${LIB_NETWORK_SRC_EXT} \ + getaddrinfo.${LIB_NETWORK_SRC_EXT} \ + getnameinfo.${LIB_NETWORK_SRC_EXT} \ + getipnodebyname.${LIB_NETWORK_SRC_EXT} LIB_NETWORK_OUT = gethostbyname.${LIB_NETWORK_OUT_EXT} \ + inet_cidr.${LIB_NETWORK_OUT_EXT} \ resolver.${LIB_NETWORK_OUT_EXT} \ - getnetent.${LIB_NETWORK_OUT_EXT} + hesiod.${LIB_NETWORK_OUT_EXT} \ + getnetent.${LIB_NETWORK_OUT_EXT} \ + tsig.${LIB_NETWORK_OUT_EXT} \ + getaddrinfo.${LIB_NETWORK_OUT_EXT} \ + getnameinfo.${LIB_NETWORK_OUT_EXT} \ + getipnodebyname.${LIB_NETWORK_OUT_EXT} # # File format manual entries # -FORMAT_BASE = resolver irs.conf +FORMAT_BASE = resolver irs.conf named.conf FORMAT_SRC_EXT = 5 FORMAT_SRC = resolver.${FORMAT_SRC_EXT} \ - irs.conf.${FORMAT_SRC_EXT} + irs.conf.${FORMAT_SRC_EXT} \ + named.conf.${FORMAT_SRC_EXT} FORMAT_OUT = resolver.${FORMAT_OUT_EXT} \ - irs.conf.${FORMAT_OUT_EXT} + irs.conf.${FORMAT_OUT_EXT} \ + named.conf.${FORMAT_OUT_EXT} # # Feature Description manual entries @@ -320,7 +347,8 @@ DESC_OUT = hostname.${DESC_OUT_EXT} mailaddr.${DESC_OUT_EXT} @${MK_MANFILE} <$*.${DESC_SRC_EXT} >$*.${DESC_OUT_EXT} OUTFILES = ${CMD_OUT} ${NAMED_OUT} ${NAMED_XFER_OUT} ${NSLOOKUP_OUT} \ - ${LIB_NETWORK_OUT} ${FORMAT_OUT} ${DESC_OUT} + ${NSUPDATE_OUT} ${LIB_NETWORK_OUT} ${FORMAT_OUT} ${DESC_OUT} \ + ${NAMED_BOOTCONF_OUT} all: ${OUTFILES} @@ -345,11 +373,21 @@ install: ${OUTFILES} \ $${f}.${SYS_OPS_OUT_EXT} \ ${DESTDIR}${DESTMAN}/${MANDIR}${SYS_OPS_EXT_DIR}/${XFER_INDOT}$${f}.${CATEXT}; \ done + @set -x; N=${SYS_OPS_EXT}; for f in ${NAMED_BOOTCONF_BASE}; do \ + ${INSTALL} -c -m 444 ${MAN_OWNER} ${MAN_GROUP} \ + $${f}.${SYS_OPS_OUT_EXT} \ + ${DESTDIR}${DESTMAN}/${MANDIR}${SYS_OPS_EXT_DIR}/${XFER_INDOT}$${f}.${CATEXT}; \ + done @set -x; N=${SYS_OPS_EXT}; for f in ${NSLOOKUP_BASE}; do \ ${INSTALL} -c -m 444 ${MAN_OWNER} ${MAN_GROUP} \ $${f}.${SYS_OPS_OUT_EXT} \ ${DESTDIR}${DESTMAN}/${MANDIR}${SYS_OPS_EXT_DIR}/$${f}.${CATEXT}; \ done + @set -x; N=${SYS_OPS_EXT}; for f in ${NSUPDATE_BASE}; do \ + ${INSTALL} -c -m 444 ${MAN_OWNER} ${MAN_GROUP} \ + $${f}.${SYS_OPS_OUT_EXT} \ + ${DESTDIR}${DESTMAN}/${MANDIR}${SYS_OPS_EXT_DIR}/$${f}.${CATEXT}; \ + done @set -x; N=${LIB_NETWORK_EXT}; for f in ${LIB_NETWORK_BASE}; do \ ${INSTALL} -c -m 444 ${MAN_OWNER} ${MAN_GROUP} \ $${f}.${LIB_NETWORK_OUT_EXT} \ diff --git a/contrib/bind/doc/man/dig.1 b/contrib/bind/doc/man/dig.1 index 72de71f..47284c2 100644 --- a/contrib/bind/doc/man/dig.1 +++ b/contrib/bind/doc/man/dig.1 @@ -1,4 +1,4 @@ -.\" $Id: dig.1,v 8.3 1998/03/21 01:01:23 halley Exp $ +.\" $Id: dig.1,v 8.4 1999/10/15 21:29:58 vixie Exp $ .\" .\" ++Copyright++ 1993 .\" - @@ -297,6 +297,9 @@ Specify class of query. May specify either an integer value to be included in the class field or use the abbreviated mnemonic as discussed above (i.e., in = C_IN). +.It Fl k Ar keydir:keyname +Sign the query with the TSIG key named keyname +that is in the directory keydir. .It Fl envsav This flag specifies that the .Ic dig diff --git a/contrib/bind/doc/man/dnskeygen.1 b/contrib/bind/doc/man/dnskeygen.1 index bdc2df9..4b3c406 100644 --- a/contrib/bind/doc/man/dnskeygen.1 +++ b/contrib/bind/doc/man/dnskeygen.1 @@ -1,4 +1,4 @@ -.\" Copyright (c) 1996 by Internet Software Consortium +.\" 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 @@ -13,163 +13,120 @@ .\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS .\" SOFTWARE. .\" -.\" $Id: dnskeygen.1,v 8.2 1997/03/14 02:29:41 vixie Exp $ +.\" $Id: dnskeygen.1,v 8.5 1999/02/23 05:20:18 vixie Exp $ .\" -.Dd October 25, 1996 +.Dd December 2, 1998 .Dt DNSKEYGEN @CMD_EXT_U@ .Os BSD 4 .Sh NAME .Nm dnskeygen -.Nd generate and display public and private RSA keys for DNS +.Nd generate public, private, and shared secret keys for DNS Security .Sh SYNOPSIS .Nm dnskeygen -.Bo Fl g Ns Op Ar size -.Op Fl f -.Bc -.Bo Fl z -| -.Fl e -| -.Fl u -.Bc -.Op Fl i -.Op Fl m -.Op Fl p Ns Ar # -.Op Fl s Ns Ar # -.Op Fl x -.Ar name +.Oo Fl +.Op Cm DHR +.Ar size +.Oc +.Op Fl F +.Fl Op Cm zhu +.Op Cm Fl a +.Op Cm Fl c +.Op Cm Fl p Ar num +.Op Cm Fl s Ar num +.Fl n Ar name .Sh DESCRIPTION .Ic Dnskeygen -(DNS Key Generator) is a tool to generate and maintain RSA keys -for DNS (Domain Name System). +(DNS Key Generator) is a tool to generate and maintain keys for DNS Security +within the DNS (Domain Name System). +.Nm Dnskeygen +can generate public and private keys to authenticate zone data, and shared +secret keys to be used for Request/Transaction signatures. .Bl -tag -width Fl -.It Fl g Ns Op Ar size -.Ic Dnskeygen -will generate a new key when -the -.Dq Fl g -flag is specified. If the -.Dq Fl g -flag is not specified, then it -will attempt to display an existing key that is stored in the current -directory. If no -.Ar size -is specified after the -.Dq Fl g -flag, a key of 512 bits -will be generated; otherwise, -.Ar size -is the size of the modulus in the newly-generated key. -.It Fl f -flag can only be specified with the -.Dq Fl g -flag; this changes the -exponent used on the key. If -.Dq Fl f -is specified, the exponent is 65537, -which is suitable for encryption keys. If -.Dq Fl f -is not specified, -the exponent is 3, which is suitable for signatures and -verification of public data such as DNS records. Signing and -verifying with exponent of 65537 takes significantly more CPU time than -with exponent of 3. -.It Fl z Fl e Fl u -These flags define the type of key being generated: Zone (DNS -validation) key, End Entity (host or service) key or User (e.g. email) key, -respectively. -Each key is only allowed to be one of these. When -keys are displayed, the type of key can be changed. -.It Fl i -Indicates that the key can be used for IPSEC (Internet Protocol Security -services). -.It Fl m -Indicates that the key can be used for secure email. -.It Fl p Ns Ar # -Indicates that the key can be used for protocol number -.Ar # . -A value of -.Ar 0 -denies the use of the key for -.Em any -protocol (other than those specified by other option flags like -.Fl m ) . -A value of -.Ar 255 -allows it to be used with -.Em all -protocols. -These protocol numbers will be assigned in the latest Assigned Numbers -RFC from the Internet Assigned Numbers Authority (IANA). -.It Fl s Ns Ar # -Strength value; this value is only used when key is signing. -Interpretation of this field is to be specified later. Default value is 7. -.It Fl x -Experimental key. This indicates that software should not assume -that it should use secure protocols when talking to this zone, host, or user. -Instead, the key is being published experimentally, to debug the software -to be used to run the secure protocols, for example. -Data signed by Experimental keys will not be treated as trusted by DNS servers. -.It Ar name -The DNS name the key is for. This can be any valid DNS name. +.It Fl D +Dnskeygen will generate a +.Ic DSA/DSS +key. +.Dq size +must be one of [512, 576, 640, 704, 768, 832, 896, 960, 1024]. +.It Fl H +Dnskeygen will generate an +.Ic HMAC-MD5 +key. +.Dq size +must be between 128 and 504. +.It Fl R +Dnskeygen will generate an +.Ic RSA +key. +.Dq size +must be between 512 and 4096. +.It Fl F +.Ic (RSA only) +Use a large exponent for key generation. +.It Fl z Fl h Fl u +These flags define the type of key being generated: Zone (DNS validation) key, +Host (host or service) key or User (e.g. email) key, respectively. +Each key is only allowed to be one of these. +.It Fl a +Indicates that the key +.Ic CANNOT +be used for authentication. +.It Fl c +Indicates that the key +.Ic CANNOT +be used for encryption. +.It Fl p Ar num +Sets the key's protocol field to +.Ar num +; the default is +.Ic 3 +(DNSSEC) if +.Dq Fl z +or +.Dq Fl h +is specified and +.Ic 2 +(EMAIL) otherwise. Other accepted values are +.Ic 1 +(TLS), +.Ic 4 +(IPSEC), and +.Ic 255 +(ANY). +.It Fl s Ar num +Sets the key's strength field to +.Ar num; +the default is +.Sy 0. +.It Fl n Ar name +Sets the key's name to +.Ar name. .El .Ss DETAILS .Ic Dnskeygen -uses two files for each key: -.Pa <name>.priv +stores each key in two files: +.Pa K<name>+<alg>+<footprint>.private and -.Pa <name>.public . -File -.Pa <name>.public -contains the public key in the pubkey format: +.Pa K<name>+<alg>+<footprint>.key +The file +.Pa K<name>+<alg>+<footprint>.private +contains the private key in a portable format. The file +.Pa K<name>+<alg>+<footprint>.key +contains the public key in the DNS zone file format: .Pp -.D1 Ar <flags> <algorithm> <protocol> <exponent|modulus> +.D1 Ar <name> IN KEY <flags> <algorithm> <protocol> <exponent|modulus> .Pp -.Ic Dnskeygen -.Ar name -displays the public key in both DNS RR format and pubkey format. -.Ic Dnskeygen -can display the key with different flags on subsequent runs. -The contents of the public key file will not be changed. -.Pa <name>.priv -stores the private key, in either a password-protected -format file or in a open file. The advantage of -a password-protected file is that it is harder to use the key if the file is -stolen. The disadvantage is that the password has to be given each time -the key is read. If the key is to be stored in a safe off-line place, -and only used for signing zones, then local policy may allow storing the -key in an unencrypted format. .Sh ENVIRONMENT No environmental variables are used. .Sh SEE ALSO -RSAREF documentation, .Em RFC 2065 -on secure DNS. +on secure DNS and the +.Em TSIG +Internet Draft. .Sh AUTHOR Olafur Gudmundsson (ogud@tis.com). .Sh ACKNOWLEDGMENTS -The underlying cryptographic math is done by the RSAREF or BSAFE libraries. +The underlying cryptographic math is done by the DNSSAFE and/or Foundation +Toolkit libraries. .Sh BUGS -.Ic Dnskeygen -renames old keys in such a way that only one -.Dq previous -key for a given name is kept; older keys are overwritten. (For example, -the third time a key is generated for a given name, the second key is kept -as the -.Dq previous -key, while the first key is lost. If a key is generated -.Em again -for this name--i.e., if the fourth key is generated--then the third key -will become the -.Dq previous -key and the second key will be lost.) -.Ic Dnskeygen -will not overwrite existing keys. -Only one key for each name can be stored in the current directory. If you -want to keep your old keys, rename the files before running -.Ic dnskeygen . -Otherwise you must delete them before running -.Ic dnskeygen . -.Pp -Portability of Private key file must be better tested between -different implementations of RSA. +None are known at this time diff --git a/contrib/bind/doc/man/dnsquery.1 b/contrib/bind/doc/man/dnsquery.1 index 048d29e..2662ab4 100644 --- a/contrib/bind/doc/man/dnsquery.1 +++ b/contrib/bind/doc/man/dnsquery.1 @@ -1,6 +1,6 @@ -.\" $Id: dnsquery.1,v 8.2 1997/03/14 02:29:41 vixie Exp $ +.\" $Id: dnsquery.1,v 8.3 1999/01/08 18:54:21 vixie Exp $ .\" -.\"Copyright (c) 1995, 1996 by Internet Software Consortium +.\"Copyright (c) 1995,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 diff --git a/contrib/bind/doc/man/getaddrinfo.3 b/contrib/bind/doc/man/getaddrinfo.3 new file mode 100644 index 0000000..a906c5d --- /dev/null +++ b/contrib/bind/doc/man/getaddrinfo.3 @@ -0,0 +1,361 @@ +.\" Copyright (c) 1983, 1987, 1991, 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. +.\" +.\" From: @(#)gethostbyname.3 8.4 (Berkeley) 5/25/95 +.\" $Id: getaddrinfo.3,v 8.1 1999/01/11 21:30:51 vixie Exp $ +.\" +.Dd May 25, 1995 +.Dt GETADDRINFO @LIB_NETWORK_EXT@ +.Os KAME +.Sh NAME +.Nm getaddrinfo +.Nm freeaddrinfo , +.Nm gai_strerror +.Nd nodename-to-address translation in protocol-independent manner +.Sh SYNOPSIS +.Fd #include <sys/socket.h> +.Fd #include <netdb.h> +.Ft int +.Fn getaddrinfo "const char *nodename" "const char *servname" \ +"const struct addrinfo *hints" "struct addrinfo **res" +.Ft void +.Fn freeaddrinfo "struct addrinfo *ai" +.Ft "char *" +.Fn gai_strerror "int ecode" +.Sh DESCRIPTION +The +.Fn getaddrinfo +function is defined for protocol-independent nodename-to-address translation. +It performs functionality of +.Xr gethostbyname @LIB_NETWORK_EXT@ +and +.Xr getservbyname @LIB_NETWORK_EXT@ , +in more sophisticated manner. +.Pp +The addrinfo structure is defined as a result of including the +.Li <netdb.h> +header: +.Bd -literal -offset +struct addrinfo { * + int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */ + 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 nodename */ + struct sockaddr *ai_addr; /* binary address */ + struct addrinfo *ai_next; /* next structure in linked list */ +}; +.Ed +.Pp +The +.Fa nodename +and +.Fa servname +arguments are pointers to null-terminated strings or +.Dv NULL . +One or both of these two arguments must be a +.Pf non Dv -NULL +pointer. +In the normal client scenario, both the +.Fa nodename +and +.Fa servname +are specified. +In the normal server scenario, only the +.Fa servname +is specified. +A +.Pf non Dv -NULL +.Fa nodename +string can be either a node name or a numeric host address string +.Po +i.e., a dotted-decimal IPv4 address or an IPv6 hex address +.Pc . +A +.Pf non Dv -NULL +.Fa servname +string can be either a service name or a decimal port number. +.Pp +The caller can optionally pass an +.Li addrinfo +structure, pointed to by the third argument, +to provide hints concerning the type of socket that the caller supports. +In this +.Fa hints +structure all members other than +.Fa ai_flags , +.Fa ai_family , +.Fa ai_socktype , +and +.Fa ai_protocol +must be zero or a +.Dv NULL +pointer. +A value of +.Dv PF_UNSPEC +for +.Fa ai_family +means the caller will accept any protocol family. +A value of 0 for +.Fa ai_socktype +means the caller will accept any socket type. +A value of 0 for +.Fa ai_protocol +means the caller will accept any protocol. +For example, if the caller handles only TCP and not UDP, then the +.Fa ai_socktype +member of the hints structure should be set to +.Dv SOCK_STREAM +when +.Fn getaddrinfo +is called. +If the caller handles only IPv4 and not IPv6, then the +.Fa ai_family +member of the +.Fa hints +structure should be set to +.Dv PF_INET +when +.Fn getaddrinfo +is called. +If the third argument to +.Fn getaddrinfo +is a +.Dv NULL +pointer, this is the same as if the caller had filled in an +.Li addrinfo +structure initialized to zero with +.Fa ai_family +set to PF_UNSPEC. +.Pp +Upon successful return a pointer to a linked list of one or more +.Li addrinfo +structures is returned through the final argument. +The caller can process each +.Li addrinfo +structure in this list by following the +.Fa ai_next +pointer, until a +.Dv NULL +pointer is encountered. +In each returned +.Li addrinfo +structure the three members +.Fa ai_family , +.Fa ai_socktype , +and +.Fa ai_protocol +are the corresponding arguments for a call to the +.Fn socket +function. +In each +.Li addrinfo +structure the +.Fa ai_addr +member points to a filled-in socket address structure whose length is +specified by the +.Fa ai_addrlen +member. +.Pp +If the +.Dv AI_PASSIVE +bit is set in the +.Fa ai_flags +member of the +.Fa hints +structure, then the caller plans to use the returned socket address +structure in a call to +.Fn bind . +In this case, if the +.Fa nodename +argument is a +.Dv NULL +pointer, then the IP address portion of the socket +address structure will be set to +.Dv INADDR_ANY +for an IPv4 address or +.Dv IN6ADDR_ANY_INIT +for an IPv6 address. +.Pp +If the +.Dv AI_PASSIVE +bit is not set in the +.Fa ai_flags +member of the +.Fa hints +structure, then the returned socket address structure will be ready for a +call to +.Fn connect +.Pq for a connection-oriented protocol +or either +.Fn connect , +.Fn sendto , or +.Fn sendmsg +.Pq for a connectionless protocol . +In this case, if the +.Fa nodename +argument is a +.Dv NULL +pointer, then the IP address portion of the +socket address structure will be set to the loopback address. +.Pp +If the +.Dv AI_CANONNAME +bit is set in the +.Fa ai_flags +member of the +.Fa hints +structure, then upon successful return the +.Fa ai_canonname +member of the first +.Li addrinfo +structure in the linked list will point to a null-terminated string +containing the canonical name of the specified +.Fa nodename . +.Pp +If the +.Dv AI_NUMERICHOST +bit is set in the +.Fa ai_flags +member of the +.Fa hints +structure, then a +.Pf non Dv -NULL +.Fa nodename +string must be a numeric host address string. +Otherwise an error of +.Dv EAI_NONAME +is returned. +This flag prevents any type of name resolution service (e.g., the DNS) +from being called. +.Pp +All of the information returned by +.Fn getaddrinfo +is dynamically allocated: +the +.Li addrinfo +structures, and the socket address structures and canonical node name +strings pointed to by the addrinfo structures. +To return this information to the system the function +Fn freeaddrinfo +is called. +The +.Fa addrinfo +structure pointed to by the +.Fa ai argument +is freed, along with any dynamic storage pointed to by the structure. +This operation is repeated until a +.Dv NULL +.Fa ai_next +pointer is encountered. +.Pp +To aid applications in printing error messages based on the +.Dv EAI_xxx +codes returned by +.Fn getaddrinfo , +.Fn gai_strerror +is defined. +The argument is one of the +.Dv EAI_xxx +values defined earlier and the return value points to a string describing +the error. +If the argument is not one of the +.Dv EAI_xxx +values, the function still returns a pointer to a string whose contents +indicate an unknown error. +.Sh FILES +.Bl -tag -width /etc/resolv.conf -compact +.It Pa /etc/hosts +.It Pa /etc/host.conf +.It Pa /etc/resolv.conf +.El +.Sh DIAGNOSTICS +Error return status from +.Fn getaddrinfo +is zero on success and non-zero on errors. +Non-zero error codes are defined in +.Li <netdb.h> , +and as follows: +.Pp +.Bl -tag -width EAI_ADDRFAMILY -compact +.It Dv EAI_ADDRFAMILY +address family for nodename not supported +.It Dv EAI_AGAIN +temporary failure in name resolution +.It Dv EAI_BADFLAGS +invalid value for ai_flags +.It Dv EAI_FAIL +non-recoverable failure in name resolution +.It Dv EAI_FAMILY +ai_family not supported +.It Dv EAI_MEMORY +memory allocation failure +.It Dv EAI_NODATA +no address associated with nodename +.It Dv EAI_NONAME +nodename nor servname provided, or not known +.It Dv EAI_SERVICE +servname not supported for ai_socktype +.It Dv EAI_SOCKTYPE +ai_socktype not supported +.It Dv EAI_SYSTEM +system error returned in errno +.El +.Pp +If called with proper argument, +.Fn gai_strerror +returns a pointer to a string describing the given error code. +If the argument is not one of the +.Dv EAI_xxx +values, the function still returns a pointer to a string whose contents +indicate an unknown error. +.Sh SEE ALSO +.Xr getnameinfo @LIB_NETWORK_EXT@ , +.Xr gethostbyname @LIB_NETWORK_EXT@ , +.Xr getservbyname @LIB_NETWORK_EXT@ , +.Xr hosts @FORMAT_EXT@ , +.Xr services @FORMAT_EXT@ , +.Xr hostname @DESC_EXT@ , +.Xr named @SYS_OPS_EXT@ +.Pp +R. Gilligan, S. Thomson, J. Bound, and W. Stevens, +``Basic Socket Interface Extensions for IPv6,'' RFC2133, April 1997. +.Sh HISTORY +The implementation first appeared in WIDE Hydrangea IPv6 protocol stack kit. +.Sh STANDARDS +The +.Fn getaddrinfo +function is defined IEEE POSIX 1003.1g draft specification, +and documented in ``Basic Socket Interface Extensions for IPv6'' +.Pq RFC2133 . +.Sh BUGS +The text was shamelessly copied from RFC2133. diff --git a/contrib/bind/doc/man/getipnodebyname.3 b/contrib/bind/doc/man/getipnodebyname.3 new file mode 100644 index 0000000..3396c3a --- /dev/null +++ b/contrib/bind/doc/man/getipnodebyname.3 @@ -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. +.\" +.\" Copyright (c) 1983, 1987 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms are permitted provided +.\" that: (1) source distributions retain this entire copyright notice and +.\" comment, and (2) distributions including binaries display the following +.\" acknowledgement: ``This product includes software developed by the +.\" University of California, Berkeley and its contributors'' in the +.\" documentation or other materials provided with the distribution and in +.\" all advertising materials mentioning features or use of this software. +.\" Neither the name of the University nor the names of its contributors may +.\" be used to endorse or promote products derived from this software without +.\" specific prior written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.Dd September 17, 1999 +.Dt GETIPNODEBYNAME @LIB_NETWORK_EXT_U@ +.Os BSD 4 +.Sh NAME +.Nm getipnodebyname , +.Nm getipnodebyaddr +.Nd get network host entry +.br +.Nm freehostent +.Nd free network host entry +.Sh SYNOPSIS +.Fd #include <netdb.h> +.Pp +.Ft struct hostent * +.Fn getipnodebyname "const char *name" "int af" "int flags" "int *error"; +.Ft struct hostent * +.Fn getipnodebyaddr "const void *addr" "size_t len" "int af" "int *error"; +.Ft void +.Fn freehostent "struct hostent *he"; +.Sh DESCRIPTION +.Fn Getipnodebyname , +and +.Fn getipnodebyaddr +each return a pointer to a +.Ft hostent +structure (see below) describing an internet host +referenced by name or by address, as the function names indicate. +This structure contains either the information obtained from the name server, +.Xr @INDOT@named @SYS_OPS_EXT@ , +or broken-out fields from a line in +.Pa /etc/hosts . +If the local name server is not running, these routines do a lookup in +.Pa /etc/hosts . +.Bd -literal -offset indent +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 compatibility */ +.Ed +.Pp +The members of this structure are: +.Bl -tag -width "h_addr_list" +.It h_name +Official name of the host. +.It h_aliases +A zero-terminated array of alternate names for the host. +.It h_addrtype +The type of address being returned. +.It h_length +The length, in bytes, of the address. +.It h_addr_list +A zero-terminated array of network addresses for the host. +Host addresses are returned in network byte order. +.It h_addr +The first address in +.Li h_addr_list ; +this is for backward compatibility. +.El +.Pp +This structure should be freed after use by calling +.Fn freehostent . +.Pp +When using the nameserver, +.Fn getiphostbyaddr +will search for the named host in each parent domain given in the +.Dq Li search +directive of +.Xr resolv.conf @FORMAT_EXT@ +unless the name contains a dot +.Pq Dq \&. . +If the name contains no dot, and if the environment variable +.Ev HOSTALIASES +contains the name of an alias file, the alias file will first be searched +for an alias matching the input name. +See +.Xr hostname @DESC_EXT@ +for the domain search procedure and the alias file format. +.Pp +.Fn Getiphostbyaddr +can be told to look for IPv4 addresses, IPv6 addresses or both IPv4 and IPv6. +If IPv4 addresses only are to be looked up then +.Fa af +should be set to +.Dv AF_INET , +otherwise it should be set to +.Dv AF_INET6 . +.Pp +There are three flags that can be set +.Bl -tag -width "AI_ADDRCONFIG" +.It Dv AI_V4MAPPED +Return IPv4 addresses if no IPv6 addresses are found. +This flag is ignored unless +.Fa af +is +.Dv AF_INET6 . +.It Dv AI_ALL +Return IPv4 addresses as well IPv6 addresses if +.Dv AI_V4MAPPED +is set. +This flag is ignored unless +.Fa af +is +.Dv AF_INET6 . +.It Dv AI_ADDRCONFIG +Only return addresses of a given type if the system has an active interface +with that type. +.El +.Pp +Also +.Dv AI_DEFAULT +is defined to be +.Dv (AI_V4MAPPED|AI_ADDRCONFIG) . +.Pp +.Fn Getipnodebyaddr +will lookup IPv4 mapped and compatible addresses in the IPv4 name +space and IPv6 name space +.Pp +.Fn Freehostent +frees the hostent structure allocated be +.Fn getipnodebyname +and +.Fn getipnodebyaddr . +The structures returned by +.Fn gethostbyname , +.Fn gethostbyname2 , +.Fn gethostbyaddr +and +.Fn gethostent +should not be passed to +.Fn freehostent +as they are pointers to static areas. +.Sh ENVIRONMENT +.Bl -tag -width "HOSTALIASES " -compress +.It Ev HOSTALIASES +Name of file containing +.Pq Ar host alias , full hostname +pairs. +.El +.Sh FILES +.Bl -tag -width "HOSTALIASES " -compress +.It Pa /etc/hosts +See +.Xr hosts @FORMAT_EXT@ . +.It Ev HOSTALIASES +Name of file containing +.Pq Ar host alias , full hostname +pairs. +.El +.Sh DIAGNOSTICS +.Pp +Error return status from +.Fn getipnodebyname +and +.Fn getipnodebyaddr +is indicated by return of a null pointer. +In this case +.Ft error +may then be checked to see whether this is a temporary failure +or an invalid or unknown host. +.Ft errno +can have the following values: +.Bl -tag -width "HOST_NOT_FOUND " -offset indent +.It Dv NETDB_INTERNAL +This indicates an internal error in the library, unrelated to the network +or name service. +.Ft errno +will be valid in this case; see +.Xr perror @SYSCALL_EXT@ . +.It Dv HOST_NOT_FOUND +No such host is known. +.It Dv TRY_AGAIN +This is usually a temporary error +and means that the local server did not receive +a response from an authoritative server. +A retry at some later time may succeed. +.It Dv NO_RECOVERY +Some unexpected server failure was encountered. +This is a non-recoverable error, as one might expect. +.It Dv NO_ADDRESS +The requested name is valid but does not have an IP address; +this is not a temporary error. +This means that the name is known to the name server but there is no address +associated with this name. +Another type of request to the name server using this domain name +will result in an answer; +for example, a mail-forwarder may be registered for this domain. +.El +.Sh SEE ALSO +.Xr hosts @FORMAT_EXT@ , +.Xr hostname @DESC_EXT@ , +.Xr @INDOT@named @SYS_OPS_EXT@ , +.Xr resolver @LIB_NETWORK_EXT@ , +.Xr resolver @FORMAT_EXT@ , +.Xr gethostbyname @LIB_NETWORK_EXT@ , +.Xr RFC2553 . diff --git a/contrib/bind/doc/man/getnameinfo.3 b/contrib/bind/doc/man/getnameinfo.3 new file mode 100644 index 0000000..02548c0 --- /dev/null +++ b/contrib/bind/doc/man/getnameinfo.3 @@ -0,0 +1,103 @@ +.\" $Id: getnameinfo.3,v 8.1 1999/01/11 21:30:51 vixie Exp $ +.\" +.\"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. +.\" +.Dd January 11, 1999 +.Dt GETRNAMEINFO @LIB_NETWORK_EXT@ +.Sh NAME +.Nm getnameinfo +.Nd address-to-name translation in protocol-independent manner +.Sh SYNOPSIS +.Fd #include <sys/socket.h> +.Fd #include <netdb.h> +.Ft int +.Fn getnameinfo "const struct sockaddr *sa" "socklen_t salen" \ +"char *host" "size_t hostlen" "char *serv" "size_t servlen" "int flags" +.Sh DESCRIPTION +The +.Fn getnameinfo +function is defined for protocol-independent address-to-nodename translation. +It performs functionality of +.Xr gethostbyaddr @LIB_NETWORK_EXT@ +and +.Xr getservbyport @LIB_NETWORK_EXT@ +in more sophisticated manner. +.Pp +The +.Fa sa +arguement is a pointer to a generic socket address structure of size +.Fa salen . +The arguements +.Fa host +and +.Fa serv +are pointers to buffers to hold the return values. +Their sizes are specified by +.Fa hostlen +and +.Fa servlen +repectively. +Either +.Fa host +or +.Fa serv +may be +.Dv NULL +if the hostname or service name is not required. +.Pp +The +.Fa flags +arguement modifies the behaviour of +.Fn getnameinfo +as follows: +.Pp +If +.Dv NI_NOFQDN +is set only the unqualified hostname is returned for local fully +qualified names. +.Pp +If +.Dv NI_NUMERICHOST +is set then the numeric form of the hostname is returned. +.Pp +If +.Dv NI_NAMEREQD +is set, then a error is returned if the hostname cannot be looked up. +.Pp +If +.Dv NI_NUMERICSERV +is set then the service is returned in numeric form. +.Pp +If +.Dv NI_DGRAM +is set then the service is UDP based rather than TCP based. +.Sh SEE ALSO +.Xr getaddrinfo @LIB_NETWORK_EXT@ , +.Xr gethostbyaddr @LIB_NETWORK_EXT@ , +.Xr getservbyport @LIB_NETWORK_EXT@ , +.Xr hosts @FORMAT_EXT@ , +.Xr services @FORMAT_EXT@ , +.Xr hostname @DESC_EXT@ , +.Xr named @SYS_OPS_EXT@ +.Pp +R. Gilligan, S. Thomson, J. Bound, and W. Stevens, +``Basic Socket Interface Extensions for IPv6,'' RFC2133, April 1997. +.Sh STANDARDS +The +.Fn getaddrinfo +function is defined IEEE POSIX 1003.1g draft specification, +and documented in ``Basic Socket Interface Extensions for IPv6'' +.Pq RFC2133 . diff --git a/contrib/bind/doc/man/getnetent.3 b/contrib/bind/doc/man/getnetent.3 index 3b941e2..4f600e0 100644 --- a/contrib/bind/doc/man/getnetent.3 +++ b/contrib/bind/doc/man/getnetent.3 @@ -1,6 +1,6 @@ -.\" $Id: getnetent.3,v 8.3 1997/03/14 02:29:43 vixie Exp $ +.\" $Id: getnetent.3,v 8.4 1999/01/08 18:54:23 vixie Exp $ .\" -.\"Copyright (c) 1995, 1996 by Internet Software Consortium +.\"Copyright (c) 1995,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 diff --git a/contrib/bind/doc/man/hesiod.3 b/contrib/bind/doc/man/hesiod.3 new file mode 100644 index 0000000..284b8f4 --- /dev/null +++ b/contrib/bind/doc/man/hesiod.3 @@ -0,0 +1,129 @@ +.\" $Id: hesiod.3,v 8.1 1999/04/12 02:47:00 vixie Exp $ +.\" +.\" Copyright 1988, 1996 by the Massachusetts Institute of Technology. +.\" +.\" Permission to use, copy, modify, and distribute this +.\" software and its documentation for any purpose and without +.\" fee is hereby granted, provided that the above copyright +.\" notice appear in all copies and that both that copyright +.\" notice and this permission notice appear in supporting +.\" documentation, and that the name of M.I.T. not be used in +.\" advertising or publicity pertaining to distribution of the +.\" software without specific, written prior permission. +.\" M.I.T. makes no representations about the suitability of +.\" this software for any purpose. It is provided "as is" +.\" without express or implied warranty. +.\" +.TH HESIOD 3 "30 November 1996" +.SH NAME +hesiod, hesiod_init, hesiod_resolve, hesiod_free_list, hesiod_to_bind, hesiod_end \- Hesiod name server interface library +.SH SYNOPSIS +.nf +.B #include <hesiod.h> +.PP +.B int hesiod_init(void **\fIcontext\fP) +.B char **hesiod_resolve(void *\fIcontext\fP, const char *\fIname\fP, +.B const char *\fItype\fP) +.B void hesiod_free_list(void *\fIcontext\fP, char **\fIlist\fP); +.B char *hesiod_to_bind(void *\fIcontext\fP, const char *\fIname\fP, +.B const char *\fItype\fP) +.B void hesiod_end(void *\fIcontext\fP) +.fi +.SH DESCRIPTION +This family of functions allows you to perform lookups of Hesiod +information, which is stored as text records in the Domain Name +Service. To perform lookups, you must first initialize a +.IR context , +an opaque object which stores information used internally by the +library between calls. +.I hesiod_init +initializes a context, storing a pointer to the context in the +location pointed to by the +.I context +argument. +.I hesiod_end +frees the resources used by a context. +.PP +.I hesiod_resolve +is the primary interface to the library. If successful, it returns a +list of one or more strings giving the records matching +.I name +and +.IR type . +The last element of the list is followed by a NULL pointer. It is the +caller's responsibility to call +.I hesiod_free_list +to free the resources used by the returned list. +.PP +.I hesiod_to_bind +converts +.I name +and +.I type +into the DNS name used by +.IR hesiod_resolve . +It is the caller's responsibility to free the returned string using +.IR free . +.SH RETURN VALUES +If successful, +.I hesiod_init +returns 0; otherwise it returns \-1 and sets +.I errno +to indicate the error. On failure, +.I hesiod_resolve +and +.I hesiod_to_bind +return NULL and set the global variable +.I errno +to indicate the error. +.SH ENVIRONMENT +If the environment variable +.B HES_DOMAIN +is set, it will override the domain in the Hesiod configuration file. +If the environment variable +.B HESIOD_CONFIG +is set, it specifies the location of the Hesiod configuration file. +.SH SEE ALSO +`Hesiod - Project Athena Technical Plan -- Name Service', named(8), +hesiod.conf(5) +.SH ERRORS +Hesiod calls may fail because of: +.IP ENOMEM +Insufficient memory was available to carry out the requested +operation. +.IP ENOEXEC +.I hesiod_init +failed because the Hesiod configuration file was invalid. +.IP ECONNREFUSED +.I hesiod_resolve +failed because no name server could be contacted to answer the query. +.IP EMSGSIZE +.I hesiod_resolve +failed because the query or response was too big to fit into the +packet buffers. +.IP ENOENT +.I hesiod_resolve +failed because the name server had no text records matching +.I name +and +.IR type , +or +.I hesiod_to_bind +failed because the +.I name +argument had a domain extension which could not be resolved with type +``rhs-extension'' in the local Hesiod domain. +.SH AUTHOR +Steve Dyer, IBM/Project Athena +.br +Greg Hudson, MIT Team Athena +.br +Copyright 1987, 1988, 1995, 1996 by the Massachusetts Institute of Technology. +.SH BUGS +The strings corresponding to the +.I errno +values set by the Hesiod functions are not particularly indicative of +what went wrong, especially for +.I ENOEXEC +and +.IR ENOENT . diff --git a/contrib/bind/doc/man/inet_cidr.3 b/contrib/bind/doc/man/inet_cidr.3 new file mode 100644 index 0000000..9aeb102 --- /dev/null +++ b/contrib/bind/doc/man/inet_cidr.3 @@ -0,0 +1,94 @@ +.\" $Id: inet_cidr.3,v 8.2 1999/01/08 18:54:24 vixie Exp $ +.\" +.\"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. +.\" +.Dd October 19, 1998 +.Dt INET_CIDR @LIB_NETWORK_EXT_U@ +.Os BSD 4 +.Sh NAME +.Nm inet_cidr_ntop , +.Nm inet_cidr_pton +.Nd network translation routines +.Sh SYNOPSIS +.Fd #include <sys/types.h> +.Fd #include <sys/socket.h> +.Fd #include <netinet/in.h> +.Fd #include <arpa/inet.h> +.Fn inet_cidr_ntop "int af" "const void *src" "int bits" "char *dst" "size_t size" +.Fn inet_cidr_pton "int af" "const char *src" "void *dst" "int *bits" +.Sh DESCRIPTION +These routines are used for converting addresses to and from network and +presentation forms with CIDR (Classless Inter-Domain Routing) representation, +embedded net mask. +.Pp +.Bd -literal + 130.155.16.1/20 +.Ed +.\" ::ffff:130.155.16.1/116 +.Pp +.Fn inet_cidr_ntop +converts an address from network to presentation format. +.Pp +.Ft af +describes the type of address that is being passed in +.Ft src. +.\"Currently defined types are AF_INET and AF_INET6. +Currently only AF_INET is supported. +.Pp +.Ft src +is an address in network byte order, its length is determined from +.Ft af. +.Pp +.Ft bits +specifies the number of bits in the netmask unless it is -1 in which case +the CIDR representation is omitted. +.Pp +.Ft dst +is a caller supplied buffer of at least +.Ft size +bytes. +.Pp +.Fn inet_cidr_ntop +returns +.Ft dst +on success or NULL. +Check errno for reason. +.Pp +.Fn inet_cidr_pton +converts and address from presentation format, with optional CIDR +reperesentation, to network format. +The resulting address is zero filled if there were insufficint bits in +.Ft src. +.Pp +.Ft af +describes the type of address that is being passed in via +.Ft src +and determines the size of +.Ft dst. +.Pp +.Ft src +is an address in presentation format. +.Pp +.Ft bits +returns the number of bits in the netmask or -1 if a CIDR representation was +not supplied. +.Pp +.Fn inet_cidr_pton +returns 0 on succces or -1 on error. +Check errno for reason. +ENOENT indicates an invalid netmask. +.Sh SEE ALSO +.Xr intro 2 diff --git a/contrib/bind/doc/man/irs.conf.5 b/contrib/bind/doc/man/irs.conf.5 index 50216e3..9ee5882 100644 --- a/contrib/bind/doc/man/irs.conf.5 +++ b/contrib/bind/doc/man/irs.conf.5 @@ -1,4 +1,4 @@ -.\" Copyright (c) 1996 by Internet Software Consortium +.\" 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 @@ -44,7 +44,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $Id: irs.conf.5,v 8.2 1997/11/17 06:46:27 vixie Exp $ +.\" $Id: irs.conf.5,v 8.4 1999/01/18 07:46:45 vixie Exp $ .\" .Dd November 16, 1997 .Dt IRS.CONF 5 @@ -96,6 +96,7 @@ Access method Description local Use a local file, usually in /etc dns Use the domain name service (includes hesiod) nis Use the Sun-compatible Network Information Service +irp Use the IRP daemon on the localhost. .Ed .Pp Available options: @@ -138,7 +139,10 @@ protocols local hosts dns continue hosts local -networks local +# Networks comes first from the local file, and failing +# that the, irp daemon +networks local continue +networks irp netgroup local .Ed diff --git a/contrib/bind/doc/man/named-bootconf.8 b/contrib/bind/doc/man/named-bootconf.8 new file mode 100644 index 0000000..2a0d39d --- /dev/null +++ b/contrib/bind/doc/man/named-bootconf.8 @@ -0,0 +1,70 @@ +.\" $NetBSD: named-bootconf.8,v 1.1 1998/11/19 21:11:45 tron Exp $ +.\" +.\" Copyright (c) 1998 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This documentation is derived from software contributed to The NetBSD +.\" Foundation by Matthias Scheler. +.\" +.\" 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 NetBSD +.\" Foundation, Inc. and its contributors. +.\" 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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) 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 19, 1998 +.Dt NAMED-BOOTCONF 8 +.Os NetBSD +.Sh NAME +.Nm named-bootconf +.Nd convert name server configuration files +.Sh SYNOPSIS +.Nm +.Sh DESCRIPTION +.Nm +converts named configuration files from BIND 4 format to BIND 8 format. +.Sh EXAMPLES +named-bootconf < named.boot > named.conf +.Sh BUGS +Comments from the source file will not always appear at the appropriate place +in the target file. +.Sh SEE ALSO +.Xr named 8 , +.Xr named.conf 5 diff --git a/contrib/bind/doc/man/named-xfer.8 b/contrib/bind/doc/man/named-xfer.8 index 766d583..e7b2cf3 100644 --- a/contrib/bind/doc/man/named-xfer.8 +++ b/contrib/bind/doc/man/named-xfer.8 @@ -49,6 +49,24 @@ .\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS .\" SOFTWARE. .\" - +.\" Portions Copyright (c) 1999 by Check Point Software Technologies, 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, and that +.\" the name of Check Point Software Technologies Incorporated 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 CHECK POINT SOFTWARE TECHNOLOGIES +.\" INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +.\" INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +.\" IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED +.\" 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-- .\" .\" from named.8 6.6 (Berkeley) 2/14/89 @@ -66,10 +84,14 @@ .Fl s Ar serial_no .Op Fl d Ar debuglevel .Op Fl l Ar debug_log_file +.Op Fl i Ar ixfr_file .Op Fl t Ar trace_file .Op Fl p Ar port# .Op Fl S -.Ar nameserver ... +.Ar nameserver +.Op Ar [ Sy axfr +| +.Op Sy ixfr ] .Sh DESCRIPTION .Ic Named-xfer is an ancillary program executed by @@ -107,6 +129,11 @@ or Note that this only applies if .Dq Fl d is also specified. +.It Fl i Ar ixfr_file +Specifies the name of the +.Ar ixfr_file +into which the zone changes from Incremental Zone Transfer (IXFR) +should be dumped when it is received from the primary server. .It Fl t Ar trace_file Specifies a .Ar trace_file @@ -138,10 +165,21 @@ syntax no host name are allowed here. At least one address must be specified. Any additional addresses will be tried, in order, if the first one fails to transfer to us successfully. +The +.Sy axfr +or +.Sy ixfr +after name server address designates the type of zone transfer to perform. +Use +.Sy axfr +for a full zone transfer or +.Sy ixfr +for an incremental zone transfer. .Sh SEE ALSO .Xr hostname @DESC_EXT@ , .Xr @INDOT@named @SYS_OPS_EXT@ , .Xr resolver @LIB_NETWORK_EXT@ , .Xr resolver @FORMAT_EXT@ , -RFC 882, RFC 883, RFC 973, RFC 974, RFC 1033, RFC 1034, RFC 1035, RFC 1123, +RFC 882, RFC 883, RFC 973, RFC 974, RFC 1033, RFC 1034, RFC 1035, +RFC 1123, RFC 1995 .Dq Name Server Operations Guide for Sy BIND . diff --git a/contrib/bind/doc/man/named.8 b/contrib/bind/doc/man/named.8 index b07dc7a..c0e73df 100644 --- a/contrib/bind/doc/man/named.8 +++ b/contrib/bind/doc/man/named.8 @@ -68,7 +68,7 @@ .Pc .Ar config_file .Oc -.Op Fl f q r +.Op Fl f q r v .Op Fl u Ar user_name .Op Fl g Ar group_name .Op Fl t Ar directory @@ -189,6 +189,8 @@ This option can be overridden by and is deprecated in favor of the clause of the configuration file's .Dq Li options statement. +.It Fl v +Report the version and exit. .It Fl u Ar user_name Specifies the user the server should run as after it initializes. The value specified may be either a username or a numeric user id. If the @@ -232,6 +234,7 @@ records for objects in the zone of the forms: .Bd -literal -offset indent $INCLUDE <filename> <opt_domain> $ORIGIN <domain> +$TTL <ttl> <domain> <opt_ttl> <opt_class> <type> <resource_record_data> .Ed .Pp @@ -261,10 +264,14 @@ Neither the field nor .Li $ORIGIN statements in the included file modify the current origin for this file. +.It Ar ttl +A integer number that sets the default time-to-live for future records without +an explicit ttl. .It Ar opt_ttl An optional integer number for the time-to-live field. -It defaults to zero, meaning the minimum value specified in the SOA -record for the zone. +If not set the ttl is taken from the last $TTL statement. +If no $TTL statement has occured then the SOA minimum value is used and a +warning is generated. .It Ar opt_class The object address type; currently only one type is supported, .Dv IN , @@ -286,7 +293,8 @@ the canonical name for an alias (domain) .It Dv SOA marks the start of a zone of authority (domain of originating host, domain address of maintainer, a serial number and the following -parameters in seconds: refresh, retry, expire and minimum TTL (see RFC 883)). +parameters in seconds: refresh, retry, expire and minimum TTL (see RFC 883 +and RFC 2308)). .It Dv NULL a null resource record (no format or data) .It Dv RP @@ -342,9 +350,7 @@ the new data. If a master server cannot be contacted when a refresh is due, the retry time specifies the interval at which refreshes should be attempted. If a master server cannot be contacted within the interval given by the expire time, all data from the zone is discarded by secondary servers. The -minimum value is the time-to-live -.Pq Dq TTL -used by records in the file with no explicit time-to-live value. +minimum value is the cache time-to-live for negative answers (RFC 2308). .Sh NOTES The boot file directives .Dq Li domain @@ -389,9 +395,7 @@ Dumps the profiling data in .Pa /var/tmp if the server is compiled with profiling (server forks, chdirs and exits). .It Dv SIGTERM -Dumps the primary and secondary database files. -Used to save modified data on shutdown if the -server is compiled with dynamic updating enabled. +Saves any modified dynamic zones to the file system, and shuts down the server. .It Dv SIGUSR1 Turns on debugging; each .Dv SIGUSR1 @@ -433,4 +437,5 @@ nameserver statistics data .Xr resolver @FORMAT_EXT@ , .Xr signal @SYSCALL_EXT@ , RFC 882, RFC 883, RFC 973, RFC 974, RFC 1033, RFC 1034, RFC 1035, RFC 1123, +RFC 2308 .Dq Name Server Operations Guide for Sy BIND diff --git a/contrib/bind/doc/man/named.conf.5 b/contrib/bind/doc/man/named.conf.5 new file mode 100644 index 0000000..44f1ec9 --- /dev/null +++ b/contrib/bind/doc/man/named.conf.5 @@ -0,0 +1,2355 @@ +.\" 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. + +.Dd January 7, 1999 +.Dt NAMED.CONF 5 +.Os BSD 4 + +.Sh NAME +.Nm named.conf +.Nd configuration file for +.Xr named 8 + +.Sh OVERVIEW + +BIND 8 is much more configurable than previous release of BIND. There +are entirely new areas of configuration, such as access control lists +and categorized logging. Many options that previously applied to all +zones can now be used selectively. These features, plus a +consideration of future configuration needs led to the creation of a +new configuration file format. + +.Ss General Syntax + +A BIND 8 configuration consists of two general features, statements +and comments. All statements end with a semicolon. Many statements +can contain substatements, which are each also terminated with a +semicolon. + +.Pp +The following statements are supported: +.Bl -tag -width 1 +.It Ic logging +specifies what the server logs, and where the log messages are sent + +.It Ic options +controls global server configuration options and sets defaults for other +statements + +.It Ic zone +defines a zone + +.It Ic acl +defines a named IP address matching list, for access control and other uses + +.It Ic key +specifies key information for use in authentication and authorization + +.It Ic trusted-keys +defines DNSSEC keys that are preconfigured into the server and implicitly +trusted + +.It Ic server +sets certain configuration options for individual remote servers + +.It Ic controls +declares control channels to be used by the +.Nm ndc +utility + +.It Ic include +includes another file + +.El + +The +.Ic logging +and +.Ic options +statements may only occur once per configuration, while the rest may +appear numerous times. Further detail on each statement is provided +in individual sections below. + +Comments may appear anywhere that whitespace may appear in a BIND +configuration file. To appeal to programmers of all kinds, they can +be written in C, C++, or shell/perl constructs. + +C-style comments start with the two characters +.Li /* +(slash, star) and end with +.Li */ +(star, slash). +Because they are completely delimited with these characters, +they can be used to comment only a portion of a line or to span +multiple lines. + +C-style comments cannot be nested. For example, the following is +not valid because the entire comment ends with the first +.Li */ : + +.Bd -literal -offset indent +/* This is the start of a comment. + This is still part of the comment. +/* This is an incorrect attempt at nesting a comment. */ + This is no longer in any comment. */ +.Ed + +C++-style comments start with the two characters +.Li // +(slash, slash) and continue to the end of the physical line. +They cannot be continued across multiple physical lines; to have +one logical comment span multiple lines, each line must use the +.Li // +pair. For example: + +.Bd -literal -offset indent +// This is the start of a comment. The next line +// is a new comment, even though it is logically +// part of the previous comment. +.Ed + +Shell-style (or perl-style, if you prefer) comments start with the +character +.Li # +(hash or pound or number or octothorpe or whatever) and continue to +the end of the physical line, like C++ comments. For example: + +.Bd -literal -offset indent +# This is the start of a comment. The next line +# is a new comment, even though it is logically +# part of the previous comment. +.Ed + +.Em WARNING: +you cannot use the +.Li ; +(semicolon) character to start a comment such as you would in a zone +file. The semicolon indicates the end of a configuration statement, +so whatever follows it will be interpreted as the start of the next +statement. + +.Ss Converting from BIND 4.9.x + +.Pp +BIND 4.9.x configuration files can be converted to the new format +by using +.Pa src/bin/named/named-bootconf , +a shell script that is part of the BIND 8.2.x source kit. + +.Sh DOCUMENTATION DEFINITIONS + +Described below are elements used throughout the BIND configuration +file documentation. Elements which are only associated with one +statement are described only in the section describing that statement. + +.Bl -tag -width 1 +.It Va acl_name +The name of an +.Va address_match_list +as defined by the +.Ic acl +statement. + +.It Va address_match_list +A list of one or more +.Va ip_addr , +.Va ip_prefix , +.Va key_id , +or +.Va acl_name +elements, as described in the +.Sx ADDRESS MATCH LISTS +section. + +.It Va dotted-decimal +One or more integers valued 0 through 255 separated only by dots +(``.''), such as +.Li 123 , +.Li 45.67 +or +.Li 89.123.45.67 . + +.It Va domain_name +A quoted string which will be used as a DNS name, for example +.Qq Li my.test.domain . + +.It Va path_name +A quoted string which will be used as a pathname, such as +.Qq Li zones/master/my.test.domain . + +.It Va ip_addr +An IP address in with exactly four elements in +.Va dotted-decimal +notation. + +.It Va ip_port +An IP port +.Va number . +.Va number is limited to +.Li 0 +through +.Li 65535 , +with values below 1024 typically restricted to +root-owned processes. In some cases an asterisk (``*'') character +can be used as a placeholder to select a random high-numbered port. + +.It Va ip_prefix +An IP network specified in +.Va dotted-decimal +form, followed by ``/'' +and then the number of bits in the netmask. E.g. +.Li 127/8 +is +the network +.Li 127.0.0.0 +with netmask +.Li 255.0.0.0 . +.Li 1.2.3.0/28 +is network +.Li 1.2.3.0 +with netmask +.Li 255.255.255.240. + +.It Va key_name +A string representing the name of a shared key, to be used for transaction +security. + +.It Va number +A non-negative integer with an entire range limited by the range of a +C language signed integer (2,147,483,647 on a machine with 32 bit +integers). Its acceptable value might further be limited by the +context in which it is used. + +.It Va size_spec +A +.Va number , +the word +.Li unlimited , +or the word +.Li default . + +.Pp +The maximum value of +.Va size_spec +is that of unsigned long integers on the machine. +.Li unlimited +requests unlimited use, or the maximum available amount. +.Li default +uses the limit that was in force when the server was started. + +.Pp +A +.Va number +can optionally be followed by a scaling factor: +.Li K +or +.Li k +for kilobytes, +.Li M +or +.Li m +for megabytes, and +.Li G +or +.Li g +for gigabytes, which scale by 1024, 1024*1024, and 1024*1024*1024 +respectively. + +.Pp +Integer storage overflow is currently silently ignored during +conversion of scaled values, resulting in values less than intended, +possibly even negative. Using +.Li unlimited +is the best way to safely set a really large number. + +.It Va yes_or_no +Either +.Li yes +or +.Li no . +The words +.Li true +and +.Li false +are also accepted, as are the numbers +.Li 1 and +.Li 0 . + +.El + +.Sh ADDRESS MATCH LISTS +.Ss Syntax + +.Bd -literal +\fIaddress_match_list\fR = 1\&*\fIaddress_match_element\fR + +\fIaddress_match_element\fR = [ \&"!\&" ] ( \fIaddress_match_list\fR / + \fIip_address\fR / \fIip_prefix\fR / + \fIacl_name\fR / \&"key \&" \fIkey_id\fR ) \&";\&" +.Ed + +.Ss Definition and Usage + +Address match lists are primarily used to determine access control for +various server operations. They are also used to define priorities +for querying other nameservers and to set the addresses on which +.Nm named +will listen for queries. +The elements which constitute an address match list can be any +of the following: + +.Bl -bullet +.It +an +.Va ip-address +(in +.Va dotted-decimal +notation, +.It +an +.Va ip-prefix +(in the '/'-notation), +.It +A +.Va key_id , +as defined by the +.Ic key +statement, +.It +the name of an address match list previously defined with +the +.Ic acl +statement, or +.It +another +.Va address_match_list . +.El + +.Pp +Elements can be negated with a leading exclamation mark (``!''), and +the match list names +.Li any , +.Li none , +.Li localhost +and +.Li localnets +are predefined. More information on those names can be found in the +description of the +.Ic acl +statement. + +.Pp +The addition of the +.Ic key +clause made the name of this syntactic element something of a +misnomer, since security keys can be used to validate access without +regard to a host or network address. Nonetheless, the term ``address +match list'' is still used throughout the documentation. + +.Pp +When a given IP address or prefix is compared to an address match +list, the list is traversed in order until an element matches. The +interpretation of a match depends on whether the list is being used +for access control, defining +.Ic listen-on +ports, or as a topology, and whether the element was +negated. + +.Pp +When used as an access control list, a non-negated match allows access +and a negated match denies access. If there is no match at all in the +list, access is denied. The clauses +.Ic allow-query , +.Ic allow-transfer , +.Ic allow-update , +.Ic allow-recursion , +and +.Ic blackhole +all use address match lists like this. Similarly, the +.Ic listen-on +option will cause the server to not accept queries on any of the +machine's addresses which do not match the list. + +.Pp +When used with the +.Ic topology +option, a non-negated match returns a distance based on its position on +the list (the closer the match is to the start of the list, the +shorter the distance is between it and the server). A negated match +will be assigned the maximum distance from the server. If there is no +match, the address will get a distance which is further than any +non-negated list element, and closer than any negated element. + +.Pp +Because of the first-match aspect of the algorithm, an element that +defines a subset of another element in the list should come before the +broader element, regardless of whether either is negated. For +example, in +.Dl 1.2.3/24; !1.2.3.13 +the 1.2.3.13 element is completely useless, because the algorithm will +match any lookup for 1.2.3.13 to the 1.2.3/24 element. Using +.Dl !1.2.3.13; 1.2.3/24 +fixes that problem by having 1.2.3.13 blocked by the negation but all +other 1.2.3.* hosts fall through. + +.Sh THE LOGGING STATEMENT +.Ss Syntax + +.Bd -literal +logging { + [ channel \fIchannel_name\fR { + ( file \fIpath_name\fR + [ versions ( \fInumber\fR | unlimited ) ] + [ size \fIsize_spec\fR ] + | syslog ( kern | user | mail | daemon | auth | syslog | lpr | + news | uucp | cron | authpriv | ftp | + local0 | local1 | local2 | local3 | + local4 | local5 | local6 | local7 ) + | null ); + + [ severity ( critical | error | warning | notice | + info | debug [ \fIlevel\fR ] | dynamic ); ] + [ print-category \fIyes_or_no\fR; ] + [ print-severity \fIyes_or_no\fR; ] + [ print-time \fIyes_or_no\fR; ] + }; ] + + [ category \fIcategory_name\fR { + \fIchannel_name\fR; [ \fIchannel_name\fR; ... ] + }; ] + ... +}; +.Ed + +.Ss Definition and Usage + +The +.Ic logging +statement configures a wide variety of logging options for the nameserver. +Its +.Ic channel +phrase associates output methods, format options and +severity levels with a name that can then be used with the +.Ic category +phrase to select how various classes of messages are logged. + +.Pp +Only one +.Ic logging +statement is used to define as many channels and categories as are wanted. +If there are multiple logging statements in a configuration, the first +defined determines the logging, and warnings are issued for the +others. If there is no logging statement, the logging configuration +will be: + +.Bd -literal + logging { + category default { default_syslog; default_debug; }; + category panic { default_syslog; default_stderr; }; + category packet { default_debug; }; + category eventlib { default_debug; }; + }; +.Ed + +The logging configuration is established as soon as the +.Ic logging +statement is parsed. If you want to redirect +messages about processing of the entire configuration file, the +.Ic logging +statement must appear first. Even if you do not +redirect configuration file parsing messages, we recommend +always putting the +.Ic logging +statement first so that this rule need not be consciously recalled if +you ever do need want the parser's messages relocated. + +.Ss The channel phrase + +All log output goes to one or more ``channels''; you can make as many +of them as you want. + +.Pp +Every channel definition must include a clause that says whether +messages selected for the channel go to a file, to a particular syslog +facility, or are discarded. It can optionally also limit the message +severity level that will be accepted by the channel (default is +.Li info ) , +and whether to include a time stamp generated by +.Nm named , +the category name, or severity level. The default is not to include +any of those three. + +.Pp +The word +.Li null +as the destination option for the +channel will cause all messages sent to it to be discarded; other +options for the channel are meaningless. + +.Pp +The +.Ic file +clause can include limitations both on how +large the file is allowed to become, and how many versions of the file +will be saved each time the file is opened. + +.Pp +The +.Ic size +option for files is simply a hard ceiling on +log growth. If the file ever exceeds the size, then +.Nm named +will just not write anything more to it until the file is reopened; +exceeding the size does not automatically trigger a reopen. The +default behavior is to not limit the size of the file. + +.Pp +If you use the +.Ic version +logfile option, then +.Nm named +will retain that many backup versions of the file +by renaming them when opening. For example, if you choose to keep 3 +old versions of the file lamers.log then just before it is opened +lamers.log.1 is renamed to lames.log.2, lamers.log.0 is renamed to +lamers.log.1, and lamers.log is renamed to lamers.log.0. No rolled +versions are kept by default; any existing log file is simply appended. +The +.Li unlimited +keyword is synonymous with +.Li 99 +in current BIND releases. Example usage of size and versions options: + +.Bd -literal + channel an_example_level { + file "lamers.log" versions 3 size 20m; + print-time yes; + print-category yes; + }; +.Ed + +.Pp +The argument for the +.Ic syslog +clause is a syslog facility as described in the +.Xr syslog 3 +manual page. How +.Nm syslogd +will handle messages sent to this facility is described in the +.Xr syslog.conf 5 +manual page. If you have a system which uses a very old version of +syslog that only uses two arguments to the +.Fn openlog() +function, then this clause is silently ignored. + +.Pp +The +.Ic severity +clause works like syslog's ``priorities'', except that they can also be +used if you are writing straight to a file rather than using +syslog. Messages which are not at least of the severity level given +will not be selected for the channel; messages of higher severity +levels will be accepted. + +.Pp +If you are using syslog, then the +.Pa syslog.conf +priorities will also determine what eventually passes through. +For example, defining a channel facility and severity as +.Li daemon +and +.Li debug +but only logging +.Li daemon.warning +via +.Pa syslog.conf +will cause messages of severity +.Li info +and +.Li notice +to be dropped. If the situation were reversed, with +.Nm named +writing messages of only +.Li warning +or higher, then +.Nm syslogd +would print all messages it received from the channel. + +.Pp +The server can supply extensive debugging information when it is in +debugging mode. If the server's global debug level is greater than +zero, then debugging mode will be active. The global debug level is +set either by starting the +.Nm named +server with the +.Fl d +flag followed by a positive integer, or by sending the running server the +.Dv SIGUSR1 +signal (for example, by using +.Ic ndc trace ) . +The global debug level can be set to +zero, and debugging mode turned off, by sending the server the +.Dv SIGUSR2 +signal (as with +.Ic ndc notrace ) . +All debugging messages in the server have a +debug level, and higher debug levels give more more detailed output. +Channels that specify a specific debug severity, e.g. + +.Bd -literal + channel specific_debug_level { + file \&"foo\&"; + severity debug 3; + }; +.Ed + +will get debugging output of level 3 or less any time the +server is in debugging mode, regardless of the global debugging level. +Channels with +.Li dynamic +severity use the server's global level to determine what messages to +print. + +.Pp +If +.Ic print-time +has been turned on, then the date and time will be logged. +.Ic print-time +may be specified for a syslog channel, but is usually pointless since +syslog also prints the date and time. +If +.Ic print-category +is requested, then the category of the message will be logged as well. +Finally, if +.Ic print-severity +is on, then the severity level of the message will be logged. The +.Ic print- +options may be used +in any combination, and will always be printed in the following order: +time, category, severity. Here is an example where all three +.Ic print- +options are on: + +.Bd -literal + 28-Apr-1997 15:05:32.863 default: notice: Ready to answer queries. +.Ed + +.Pp +There are four predefined channels that are used for +.Nm named 's +default logging as follows. How they are used +used is described in the next section, +.Sx The category phrase. + +.Bd -literal + channel default_syslog { + syslog daemon; # send to syslog's daemon facility + severity info; # only send priority info and higher + }; + + channel default_debug { + file \&"named.run\&"; # write to named.run in the working directory + # Note: stderr is used instead of \&"named.run\&" + # if the server is started with the -f option. + severity dynamic; # log at the server's current debug level + }; + + channel default_stderr { # writes to stderr + file \&"<stderr>\&"; # this is illustrative only; there's currently + # no way of specifying an internal file + # descriptor in the configuration language. + severity info; # only send priority info and higher + }; + + channel null { + null; # toss anything sent to this channel + }; +.Ed + +Once a channel is defined, it cannot be redefined. Thus you cannot +alter the built-in channels directly, but you can modify the default +logging by pointing categories at channels you have defined. + +.Ss The category phrase + +There are many categories, so you can send the logs you want to see +wherever you want, without seeing logs you don't want. If you don't +specify a list of channels for a category, then log messages in that +category will be sent to the +.Li default +category instead. +If you don't specify a default category, the following ``default +default'' is used: + +.Bd -literal + category default { default_syslog; default_debug; }; +.Ed + +As an example, let's say you want to log security events to a file, +but you also want keep the default logging behavior. You'd specify +the following: + +.Bd -literal + channel my_security_channel { + file \&"my_security_file\&"; + severity info; + }; + category security { my_security_channel; + default_syslog; default_debug; }; +.Ed + +To discard all messages in a category, specify the +.Li null +channel: + +.Bd -literal + category lame-servers { null; }; + category cname { null; }; +.Ed + +The following categories are available: + +.Bl -tag -width 1 +.It Ic default +The catch-all. Many things still aren't classified into categories, +and they all end up here. Also, if you don't specify any channels for +a category, the default category is used instead. If you do not +define the default category, the following definition is used: +.Dl category default { default_syslog; default_debug; }; + +.It Ic config +High-level configuration file processing. + +.It Ic parser +Low-level configuration file processing. + +.It Ic queries +A short log message is generated for every query the server receives. + +.It Ic lame-servers +Messages like ``Lame server on ...'' + +.It Ic statistics +Statistics. + +.It Ic panic +If the server has to shut itself down due to an internal problem, it +will log the problem in this category as well as in the problem's native +category. If you do not define the panic category, the following definition +is used: +.Dl category panic { default_syslog; default_stderr; }; + +.It Ic update +Dynamic updates. + +.It Ic ncache +Negative caching. + +.It Ic xfer-in +Zone transfers the server is receiving. + +.It Ic xfer-out +Zone transfers the server is sending. + +.It Ic db +All database operations. + +.It Ic eventlib +Debugging info from the event system. Only one channel may be specified for +this category, and it must be a file channel. If you do not define the +eventlib category, the following definition is used: +.Dl category eventlib { default_debug; }; + +.It Ic packet +Dumps of packets received and sent. Only one channel may be specified for +this category, and it must be a file channel. If you do not define the +packet category, the following definition is used: +.Dl category packet { default_debug; }; + +.It Ic notify +The NOTIFY protocol. + +.It Ic cname +Messages like ``... points to a CNAME''. + +.It Ic security +Approved/unapproved requests. + +.It Ic os +Operating system problems. + +.It Ic insist +Internal consistency check failures. + +.It Ic maintenance +Periodic maintenance events. + +.It Ic load +Zone loading messages. + +.It Ic response-checks +Messages arising from response checking, such as +``Malformed response ...'', ``wrong ans. name ...'', +``unrelated additional info ...'', ``invalid RR type ...'', +and ``bad referral ...''. + +.El + +.Sh THE OPTIONS STATEMENT +.Ss Syntax + +.Bd -literal +options { + [ version \fIversion_string\fR; ] + [ directory \fIpath_name\fR; ] + [ named-xfer \fIpath_name\fR; ] + [ dump-file \fIpath_name\fR; ] + [ memstatistics-file \fIpath_name\fR; ] + [ pid-file \fIpath_name\fR; ] + [ statistics-file \fIpath_name\fR; ] + [ auth-nxdomain \fIyes_or_no\fR; ] + [ deallocate-on-exit \fIyes_or_no\fR; ] + [ dialup \fIyes_or_no\fR; ] + [ fake-iquery \fIyes_or_no\fR; ] + [ fetch-glue \fIyes_or_no\fR; ] + [ has-old-clients \fIyes_or_no\fR; ] + [ host-statistics \fIyes_or_no\fR; ] + [ multiple-cnames \fIyes_or_no\fR; ] + [ notify \fIyes_or_no\fR; ] + [ recursion \fIyes_or_no\fR; ] + [ rfc2308-type1 \fIyes_or_no\fR; ] + [ use-id-pool \fIyes_or_no\fR; ] + [ treat-cr-as-space \fIyes_or_no\fR; ] + [ also-notify \fIyes_or_no\fR; ] + [ forward ( only | first ); ] + [ forwarders { [ \fIin_addr\fR ; [ \fIin_addr\fR ; ... ] ] }; ] + [ check-names ( master | slave | response ) ( warn | fail | ignore); ] + [ allow-query { \fIaddress_match_list\fR }; ] + [ allow-recursion { \fIaddress_match_list\fR }; ] + [ allow-transfer { \fIaddress_match_list\fR }; ] + [ blackhole { \fIaddress_match_list\fR }; ] + [ listen-on [ port \fIip_port\fR ] { \fIaddress_match_list\fR }; ] + [ query-source [ address ( \fIip_addr\fR | * ) ] + [ port ( \fIip_port\fR | * ) ] ; ] + [ lame-ttl \fInumber\fR; ] + [ max-transfer-time-in \fInumber\fR; ] + [ max-ncache-ttl \fInumber\fR; ] + [ min-roots \fInumber\fR; ] + [ serial-queries \fInumber\fR; ] + [ transfer-format ( one-answer | many-answers ); ] + [ transfers-in \fInumber\fR; ] + [ transfers-out \fInumber\fR; ] + [ transfers-per-ns \fInumber\fR; ] + [ transfer-source \fIip_addr\fR; ] + [ maintain-ixfr-base \fIyes_or_no\fR; ] + [ max-ixfr-log-size \fInumber\fR; ] + [ coresize \fIsize_spec\fR ; ] + [ datasize \fIsize_spec\fR ; ] + [ files \fIsize_spec\fR ; ] + [ stacksize \fIsize_spec\fR ; ] + [ cleaning-interval \fInumber\fR; ] + [ heartbeat-interval \fInumber\fR; ] + [ interface-interval \fInumber\fR; ] + [ statistics-interval \fInumber\fR; ] + [ topology { \fIaddress_match_list\fR }; ] + [ sortlist { \fIaddress_match_list|fR }; ] + [ rrset-order { \fIorder_spec\fR ; [ \fIorder_spec\fR ; ... [ [ }; +}; +.Ed + +.Ss Definition and Usage + +The options statement sets up global options to be used by +BIND. This statement may appear at only once in a +configuration file; if more than one occurrence is found, the +first occurrence determines the actual options used, +and a warning will be generated. If there is no options statement, +an options block with each option set to its default will be used. + +.Ss Pathnames + +.Bl -tag -width 1 + +.It Ic version +The version the server should report via the ndc command or via a query of +name +.Pa version.bind +in class chaos. The default is the real version number of ths server, +but some server operators prefer the string ( +.Ic surely you must be joking +). + +.It Ic directory +The working directory of the server. Any non-absolute +pathnames in the configuration file will be taken as relative to this +directory. The default location for most server output files +(e.g. +.Pa named.run ) +is this directory. If a directory is not +specified, the working directory defaults to +.Pa . , +the directory from which the +server was started. The directory specified should be an absolute path. + +.It Ic named-xfer +The pathname to the named-xfer program that the server uses for +inbound zone transfers. If not specified, the default is +system dependent (e.g. +.Pa /usr/sbin/named-xfer +). + +.It Ic dump-file +The pathname of the file the server dumps the database to when it +receives +.Dv SIGINT +signal (as sent by +.Ic ndc dumpdb +). If not specified, the default is +.Pa named_dump.db . + +.It Ic memstatistics-file +The pathname of the file the server writes memory usage statistics to +on exit, if +.Ic deallocate-on-exit +is +.Li yes . +If not specified, the default is +.Pa named.memstats . + +.It Ic pid-file +The pathname of the file the server writes its process ID in. If not +specified, the default is operating system dependent, but is usually +.Pa /var/run/named.pid +or +.Pa /etc/named.pid . +The pid-file is used by programs like +.Nm ndc +that want to send signals to the running nameserver. + +.It Ic statistics-file +The pathname of the file the server appends statistics to when it +receives +.Dv SIGILL +signal (from +.Ic ndc stats ) . +If not specified, the default is +.Pa named.stats . +.El + +.Ss Boolean Options + +.Bl -tag -width 1 +.It Ic auth-nxdomain +If +.Li yes , +then the +.Li AA +bit is always set on +.Dv NXDOMAIN +responses, even if the server is not actually authoritative. +The default is +.Li yes . +Do not turn off +.Ic auth-nxdomain +unless you are sure you know what you are +doing, as some older software won't like it. + +.It Ic deallocate-on-exit +If +.Li yes , +then when the server exits it will painstakingly deallocate every +object it allocated, and then write a memory usage report to the +.Ic memstatistics-file . +The default is +.Li no , +because it is faster to let the operating system clean up. +.Ic deallocate-on-exit +is handy for detecting memory leaks. + +.It Ic dialup +If +.Li yes , +then the server treats all zones as if they are doing zone transfers +across a dial on demand dialup link, which can be brought up by +traffic originating from this server. This has different effects +according to zone type and concentrates the zone maintenance so that +it all happens in a short interval, once every +.Ic heartbeat-interval +and hopefully during the one call. +It also suppresses some of the normal zone maintenance traffic. +The default is +.Li no . +The +.Ic dialup +option may also be specified in the +.Ic zone +statement, in which +case it overrides the +.Ic options dialup +statement. + +.Pp +If the zone is a +.Ic master +then the server will send out +.Dv NOTIFY +request to all the slaves. +This will trigger the zone up to date checking in the slave (providing +it supports +.Dv NOTIFY ) +allowing the slave +to verify the zone while the call us up. + +.Pp +If the zone is a +.Ic slave +or +.Ic stub +then the server will suppress the zone regular zone up to date queries +and only perform the when the +.Ic heartbeat-interval +expires. + +.It Ic fake-iquery +If +.Li yes , +the server will simulate the obsolete DNS query type +.Dv IQUERY . +The default is +.Li no . + +.It Ic fetch-glue +If +.Li yes +(the default), the server will fetch ``glue'' resource +records it doesn't have when constructing the additional data section of +a response. +.Ic fetch-glue no +can be used in conjunction with +.Ic recursion no +to prevent the server's cache from growing or +becoming corrupted (at the cost of requiring more work from the client). + +.It Ic has-old-clients +Setting the option to +.Li yes , +is equivalent to setting the following three options: +.Ic auth-nxdomain yes ;, +.Ic maintain-ixfr-base yes ;, +and +.Ic rfc2308-type1 no ; +. The use of +.Ic has-old-clients +with +.Ic auth-nxdomain , +.Ic maintain-ixfr-base , +and +.Ic rfc2308-type1 +is order dependant. + +.It Ic host-statistics +If +.Li yes , +then statistics are kept for every host that the the nameserver +interacts with. The default is +.Li no . +.Em Note: +turning on +.Ic host-statistics +can consume huge amounts of memory. + +.It Ic maintain-ixfr-base +If +.Li yes , +statistics are kept for every host that the nameserver interacts with. The default is +.Li no . +.Em Note: +turning on +.Li host-statistics +can consume huge amounts of memory. + +.It Ic multiple-cnames +If +.Li yes , +then multiple CNAME resource records will be +allowed for a domain name. The default is +.Li no . +Allowing multiple CNAME records is against standards and is not recommended. +Multiple CNAME support is available because previous versions of BIND +allowed multiple CNAME records, and these records have been used for load +balancing by a number of sites. + +.It Ic notify +If +.Li yes +(the default), DNS NOTIFY messages are sent when a +zone the server is authoritative for changes. The use of NOTIFY +speeds convergence between the master and its slaves. Slave servers +that receive a NOTIFY message and understand it will contact the +master server for the zone and see if they need to do a zone transfer, and +if they do, they will initiate it immediately. The +.Ic notify +option may also be specified in the +.Ic zone +statement, in which case it overrides the +.Ic options notify +statement. + +.It Ic recursion +If +.Li yes , +and a DNS query requests recursion, then the +server will attempt to do all the work required to answer the query. +If recursion is not on, the server will return a referral to the +client if it doesn't know the answer. The default is +.Li yes . +See also +.Ic fetch-glue +above. + +.It Ic rfc2308-type1 +If +.Li yes, +the server will send NS records along with the SOA record for negative +answers. You need to set this to no if you have an old BIND server using +you as a forwarder that does not understand negative answers which contain +both SOA and NS records or you have an old version of sendmail. The correct +fix is to upgrade the broken server or sendmail. The default is +.Li no . + +.It Ic use-id-pool +If +.Li yes, +the server will keep track of its own outstanding query ID's to avoid duplication +and increase randomness. This will result in 128KB more memory being consumed +by the server. The default is +.Li no . + +.It Ic treat-cr-as-space +If +.Li yes, +the server will treat CR characters the same way it treats a space +or tab. This may be necessary when loading zone files on a UNIX system +that were generated on an NT or DOS machine. The default is +.Li no . + + +.El + +.Ss Also-Notify + +.Ic also-notify + +Defines a global list of IP addresses that also get sent NOTIFY messages +whenever a fresh copy of the zone is loaded. This helps to ensure that copies of +the zones will quickly converge on ``stealth'' servers. If an +.Ic also-notify +list is given in a +.Ic zone +statement, it will override the +.Ic options also-notify +statement. When a +.Ic zone notify +statement is set to +.Ic no , +the IP addresses in +the global +.Ic also-notify +list will not get sent NOTIFY messages for that zone. +The default is the empty list (no global notification list). + +.Ss Forwarding + +.Pp +The forwarding facility can be used to create a large site-wide +cache on a few servers, reducing traffic over links to external +nameservers. It can also be used to allow queries by servers that do +not have direct access to the Internet, but wish to look up exterior +names anyway. Forwarding occurs only on those queries for which the +server is not authoritative and does not have the answer in its cache. + +.Bl -tag -width 1 +.It Ic forward +This option is only meaningful if the +.Ic forwarders +list is +not empty. A value of +.Li first , +the default, causes the +server to query the forwarders first, and if that doesn't answer the +question the server will then look for the answer itself. If +.Li only +is specified, the server will only query the forwarders. + +.It Ic forwarders +Specifies the IP addresses to be used for forwarding. The default is the +empty list (no forwarding). +.El + +.Pp +Forwarding can also be configured on a per-zone basis, allowing for +the global forwarding options to be overridden in a variety of ways. +You can set particular zones to use different forwarders, or have +different +.Ic forward only/first +behavior, or to not forward +at all. See +.Sx THE ZONE STATEMENT +section for more information. + +.Pp +Future versions of BIND 8 will provide a more powerful forwarding +system. The syntax described above will continue to be supported. + +.Ss Name Checking + +The server can check domain names based upon their expected client contexts. +For example, a domain name used as a hostname can be checked for compliance +with the RFCs defining valid hostnames. + +.Pp +Three checking methods are available: + +.Bl -tag -width 1 +.It Ic ignore +No checking is done. + +.It Ic warn +Names are checked against their expected client contexts. Invalid names are +logged, but processing continues normally. + +.It Ic fail +Names are checked against their expected client contexts. Invalid names are +logged, and the offending data is rejected. +.El + +.Pp +The server can check names three areas: master zone files, slave +zone files, and in responses to queries the server has initiated. If +.Ic check-names response fail +has been specified, and +answering the client's question would require sending an invalid name +to the client, the server will send a +.Dv REFUSED +response code to the client. + +.Pp +The defaults are: + +.Bd -literal + check-names master fail; + check-names slave warn; + check-names response ignore; +.Ed + +.Pp +.Ic check-names +may also be specified in the +.Ic zone +statement, in which case it overrides the +.Ic options check-names +statement. When used in a +.Ic zone +statement, the area is not specified (because it can be deduced from +the zone type). + +.Ss Access Control + +.Pp +Access to the server can be restricted based on the IP address of the +requesting system or via shared secret keys. See +.Sx ADDRESS MATCH LISTS +for details on how to specify access criteria. + +.Bl -tag -width 1 +.It Ic allow-query +Specifies which hosts are allowed to ask ordinary questions. +.Ic allow-query +may also be specified in the +.Ic zone +statement, in which case it overrides the +.Ic options allow-query +statement. If not specified, the default is + +.Bl -tag -width 1 +.It Ic allow-recursion +Specifies which hosts are allowed to ask recursive questions. +.Ic allow-recursion +may also be specified in the +.Ic zone +statement, in which case it overrides the +.Ic options allow-recursion +statement. If not specified, the default is to allow recursive queries +from all hosts. + +.It Ic allow-transfer +Specifies which hosts are allowed to receive zone transfers from the +server. +.Ic allow-transfer +may also be specified in the +.Ic zone +statement, in which case it overrides the +.Ic options allow-transfer +statement. If not specified, the default +is to allow transfers from all hosts. + +.It Ic blackhole +Specifies a list of addresses that the server will not accept queries from +or use to resolve a query. Queries from these addresses will not be +responded to. +.El + +.Ss Interfaces + +.Pp +The interfaces and ports that the server will answer queries from may +be specified using the +.Ic listen-on +option. +.Ic listen-on +takes an optional port, and an address match list. +The server will listen on all interfaces allowed by the address match +list. If a port is not specified, port 53 will be used. + +.Pp +Multiple +.Ic listen-on +statements are allowed. For example, + +.Bd -literal + listen-on { 5.6.7.8; }; + listen-on port 1234 { !1.2.3.4; 1.2/16; }; +.Ed + +will enable the nameserver on port 53 for the IP address 5.6.7.8, and +on port 1234 of an address on the machine in net 1.2 that is not +1.2.3.4. + +.Pp +If no +.Ic listen-on +is specified, the server will listen on port +53 on all interfaces. + +.Ss Query Address + +.Pp +If the server doesn't know the answer to a question, it will query +other nameservers. +.Ic query-source +specifies the address and port used for such queries. If +.Ic address +is +.Li * +or is omitted, a wildcard IP address +( +.Dv INADDR_ANY ) +will be used. If +.Va port +is +.Li * +or is omitted, a random unprivileged port will be used. +The default is +.Dl query-source address * port *; + +.Pp +Note: +.Ic query-source +currently applies only to UDP queries; +TCP queries always use a wildcard IP address and a random unprivileged +port. + +.Ss Zone Transfers + +.Bl -tag -width 1 +.It Ic max-transfer-time-in +Inbound zone transfers ( +.Nm named-xfer +processes) running +longer than this many minutes will be terminated. +The default is 120 minutes (2 hours). + +.It Ic transfer-format +The server supports two zone transfer methods. +.Li one-answer +uses one DNS message per resource record +transferred. +.Li many-answers +packs as many resource records +as possible into a message. +.Li many-answers +is more efficient, but is only known to be understood by BIND 8.1 and +patched versions of BIND 4.9.5. The default is +.Li one-answer . +.Ic transfer-format +may be overridden on a per-server basis by using the +.Ic server +statement. + +.It Ic transfers-in +The maximum number of inbound zone transfers that can be running +concurrently. The default value is 10. Increasing +.Ic transfers-in +may speed up the convergence of slave zones, +but it also may increase the load on the local system. + +.It Ic transfers-out +This option will be used in the future to limit the number of +concurrent outbound zone transfers. It is checked for syntax, but is +otherwise ignored. + +.It Ic transfers-per-ns +The maximum number of inbound zone transfers ( +.Nm named-xfer +processes) that can be concurrently transferring from a given remote +nameserver. The default value is 2. Increasing +.Ic transfers-per-ns +may speed up the convergence of slave zones, but it also may increase +the load on the remote nameserver. +.Ic transfers-per-ns +may be overridden on a per-server basis by using the +.Ic transfers +phrase of the +.Ic server +statement. + +.It Ic transfer-source +.Nm transfer-source +determines which local address will be bound to the TCP connection used to fetch all zones +transferred inbound by the server. If not set, it defaults to a system controlled value which will usually be the address of the interface ``closest to`` the remote end. This +address must appear in the remote end's +.Nm allow-transfer +option for the zones being transferred, if one is specified. This statement sets the +.Nm transfer-source +for all zones, but can be overriden on a per-zone basis by includinga +.Nm transfer-source +statement within the zone block in the configuration file. +.El + +.Ss Resource Limits + +.Pp +The server's usage of many system resources can be limited. Some +operating systems don't support some of the limits. On such systems, +a warning will be issued if the unsupported limit is used. Some +operating systems don't support limiting resources, and on these systems +a +.D1 cannot set resource limits on this system +message will +be logged. + +.Pp +Scaled values are allowed when specifying resource limits. For +example, +.Li 1G +can be used instead of +.Li 1073741824 +to specify a limit of one gigabyte. +.Li unlimited +requests unlimited use, or the maximum +available amount. +.Li default +uses the limit that was in +force when the server was started. +See the definition of +.Va size_spec +in the +.Sx DOCUMENTATION DEFINITIONS +section for more details. + +.Bl -tag -width 1 +.It Ic coresize +The maximum size of a core dump. The default value is +.Li default . + +.It Ic datasize +The maximum amount of data memory the server may use. The default +value is +.Li default . + +.It Ic files +The maximum number of files the server may have open concurrently. +The default value is +.Li unlimited . +Note that on some operating systems the server cannot set an unlimited +value and cannot determine the maximum number of open files the kernel +can support. On such systems, choosing +.Li unlimited +will cause the server to use +the larger of the +.Va rlim_max +from +.Fn getrlimit RLIMIT_NOFILE +and the value returned by +.Fn sysconf _SC_OPEN_MAX . +If the +actual kernel limit is larger than this value, use +.Ic limit files +to specify the limit explicitly. + +.It Ic max-ixfr-log-size +The +.Li max-ixfr-log-size +will be used in a future release of the server to limit the size of the transaction +log kept for Incremental Zone Transfer. + +.It Ic stacksize +The maximum amount of stack memory the server may use. The default value is +.Li default . +.El + +.Ss Periodic Task Intervals + +.Bl -tag -width 1 +.It Ic cleaning-interval +The server will remove expired resource records from the cache every + +.Ic cleaning-interval +minutes. The default is 60 minutes. If set +to 0, no periodic cleaning will occur. + +.It Ic heartbeat-interval +The server will perform zone maintenance tasks for all zones marked +.Ic dialup yes +whenever this interval expires. +The default is 60 minutes. Reasonable values are up to 1 day (1440 minutes). +If set to 0, no zone maintenance for these zones will occur. + +.It Ic interface-interval +The server will scan the network interface list every +.Ic interface-interval +minutes. The default is 60 minutes. +If set to 0, interface scanning will only occur when the configuration +file is loaded. After the scan, listeners will be started on any new +interfaces (provided they are allowed by the +.Ic listen-on +configuration). Listeners on interfaces that have gone away will be +cleaned up. + +.It Ic statistics-interval +Nameserver statistics will be logged every +.Ic statistics-interval +minutes. The default is 60. If set to 0, no statistics will be logged. +.El + +.Ss Topology + +.Pp +All other things being equal, when the server chooses a nameserver +to query from a list of nameservers, it prefers the one that is +topologically closest to itself. The +.Ic topology +statement takes an address match list and interprets it in a special way. +Each top-level list element is assigned a distance. +Non-negated elements get a distance based on +their position in the list, where the closer the match is to the start +of the list, the shorter the distance is between it and the server. A +negated match will be assigned the maximum distance from the server. +If there is no match, the address will get a distance which is further +than any non-negated list element, and closer than any negated +element. For example, + +.Bd -literal + topology { + 10/8; + !1.2.3/24; + { 1.2/16; 3/8; }; + }; +.Ed + +will prefer servers on network 10 the most, followed by hosts on +network 1.2.0.0 (netmask 255.255.0.0) and network 3, with the exception +of hosts on network 1.2.3 (netmask 255.255.255.0), which is preferred least +of all. + +.Pp +The default topology is +.Dl topology { localhost; localnets; }; + +.Ss Resource Record sorting + +.Pp +When returning multiple RRs, the nameserver will normally return them in +.Ic Round Robin , +i.e. after each request, the first RR is put to the end of the list. +As the order of RRs is not defined, this should not cause any problems. + +The client resolver code should re-arrange the RRs as appropriate, i.e. using +any addresses on the local net in preference to other addresses. However, not all +resolvers can do this, or are not correctly configured. + +When a client is using a local server, the sorting can be performed in the server, +based on the client's address. This only requires configuring the nameservers, +not all the clients. + +The +.Ic sortlist +statement takes an address match list and interprets it even more +specially than the +.Ictopology +statement does. + +Each top level statement in the sortlist must itself be an explicit address match +list with one or two elements. The first element (which may be an IP address, +an IP prefix, an ACL name or nested address match list) of each top level list is +checked against the source address of the query until a match is found. + +Once the source address of the query has been matched, if the top level +statement contains only one element, the actual primitive element that +matched the source address is used to select the address in the response to +move to the beginning of the response. If the statement is a list of two elements, +the second element is treated like the address match list in a topology +statement. Each top level element is assigned a distance and the address in the +response with the minimum distance is moved to the beginning of the response. + +In the following example, any queries received from any of the addresses of the +host itself will get responses preferring addresses on any of the locally +connected networks. Next most preferred are addresses on the 192.168.1/24 +network, and after that either the 192.168.2/24 or 192.168.3/24 network with no +preference shown between these two networks. Queries received from a host on +the 192.168.1/24 network will prefer other addresses on that network to the +192.168.2/24 and 192.168.3/24 networks. Queries received from a host on the +192.168.4/24 or the 192.168.5/24 network will only prefer other addresses on +their directly connected networks. + +.Bd -literal +sortlist { + { localhost; // IF the local host + { localnets; // THEN first fit on the + 192.168.1/24; // following nets + { 192,168.2/24; 192.168.3/24; }; }; }; + { 192.168.1/24; // IF on class C 192.168.1 + { 192.168.1/24; // THEN use .1, or .2 or .3 + { 192.168.2/24; 192.168.3/24; }; }; }; + { 192.168.2/24; // IF on class C 192.168.2 + { 192.168.2/24; // THEN use .2, or .1 or .3 + { 192.168.1/24; 192.168.3/24; }; }; }; + { 192.168.3/24; // IF on class C 192.168.3 + { 192.168.3/24; // THEN use .3, or .1 or .2 + { 192.168.1/24; 192.168.2/24; }; }; }; + { { 192.168.4/24; 192.168.5/24; }; // if .4 or .5, prefer that net + }; +}; +.Ed + +The following example will give reasonable behaviour for the local host and +hosts on directly connected networks. It is similar to the behavior of the +address sort in BIND 4.9.x. Responses sent to queries from the local host will +favor any of the directly connected networks. Responses sent to queries from +any other hosts on a directly connected network will prefer addresses on that +same network. Responses to other queries will not be sorted. + +.Bd -literal +sortlist { + { localhost; localnets; }; + { localnets; }; +}; +.Ed + +.Ss RRset Ordering + +.Pp +When multiple records are returned in an answer it may be useful to configure +the order the records are placed into the response. For example the records for +a zone might be configured to always be returned in the order they are defined +in the zone file. Or perhaps a random shuffle of the records as they are +returned is wanted. The rrset-order statement permits configuration of the +ordering made of the records in a multiple record response. The default, if no +ordering is defined, is a cyclic ordering (round robin). + +An +.Ic order_spec +is defined as follows: + +.Bd -literal + [ \fIclass class_name\fR ][ \fItype type_name\fR ][ \fIname\fR "FQDN" ] \fIorder\fR ordering +.Ed + +If no class is specified, the default is +.Ic ANY . +If no +.Li Ictype +is specified, the default is +.Ic ANY . +If no name is specified, the default is "*". + +The legal values for +.Ic ordering +are: + +.Bd -literal +.Ic fixed + Records are returned in the order they are defined in the zone file. +.Ic random + Records are returned in some random order. +.Ic cyclic + Records are returned in a round-robin order. + +For example: + + rrset-order { + class IN type A name "rc.vix.com" order random; + order cyclic; + }; +.Ed + +will cause any responses for type A records in class IN that have "rc.vix.com" as +a suffix, to always be returned in random order. All other records are returned +in cyclic order. + +If multiple +.Ic rrset-order +statements appear, they are not combined--the last one applies. + +If no +.Ic rrset-order +statement is specified, a default one of: + +.Bd -literal + rrset-order { class ANY type ANY name "*" order cyclic ; }; +.Ed + +is used. + +.Ss Tuning + +.Bl -tag -width 1 +.It Ic lame-ttl +Sets the number of seconds to cache a lame server indication. 0 disables +caching. Default is 600 (10 minutes). Maximum value is 1800 (30 minutes) +.It Ic max-ncache-ttl +To reduce network traffic and increase performance the server store negative +answers. +.Ic max-ncache-ttl +is used to set a maximum retention time +for these answers in the server is seconds. The default +.Ic max-ncache-ttl +is 10800 seconds (3 hours). +.Ic max-ncache-ttl +cannot exceed the maximum retention time for ordinary (positive) +answers (7 days) and will be silently truncated to 7 days if set to a +value which is greater that 7 days. +.It Ic min-roots +The minimum number of root servers that is required for a request for the root +servers to be accepted. Default is 2. +.El + +.Sh THE ZONE STATEMENT +.Ss Syntax + +.Bd -literal +zone \fIdomain_name\fR [ ( in | hs | hesiod | chaos ) ] { + type master; + file \fIpath_name\fR; + [ check-names ( warn | fail | ignore ); ] + [ allow-update { \fIaddress_match_list\fR }; ] + [ allow-query { \fIaddress_match_list\fR }; ] + [ allow-transfer { \fIaddress_match_list\fR }; ] + [ dialup \fIyes_or_no\fR; ] + [ notify \fIyes_or_no\fR; ] + [ also-notify { \fIip_addr\fR; [ \fIip_addr\fR; ... ] }; + [ pubkey \fInumber\fR \fInumber\fR \fInumber\fR \fIstring\fR; ] +}; + +zone \fIdomain_name\fR [ ( in | hs | hesiod | chaos ) ] { + type ( slave | stub ); + [ file \fIpath_name\fR; ] + masters [ port \fIip_port\fR ] { \fIip_addr\fR; [ \fIip_addr\fR; ... ] }; + [ check-names ( warn | fail | ignore ); ] + [ allow-update { \fIaddress_match_list\fR }; ] + [ allow-query { \fIaddress_match_list\fR }; ] + [ allow-transfer { \fIaddress_match_list\fR }; ] + [ transfer-source \fIip_addr\fR; ] + [ max-transfer-time-in \fInumber\fR; ] + [ notify \fIyes_or_no\fR; ] + [ also-notify { \fIip_addr\fR; [ \fIip_addr\fR; ... ] }; + [ pubkey \fInumber\fR \fInumber\fR \fInumber\fR \fIstring\fR; ] +}; + +zone \fIdomain_name\fR [ ( in | hs | hesiod | chaos ) ] { + type forward; + [ forward ( only | first ); ] + [ forwarders { [ \fIip_addr\fR ; [ \fIip_addr\fR ; ... ] ] }; ] + [ check-names ( warn | fail | ignore ); ] +}; + +zone \&".\&" [ ( in | hs | hesiod | chaos ) ] { + type hint; + file \fIpath_name\fR; + [ check-names ( warn | fail | ignore ); ] +}; +.Ed + +.Ss Definition and Usage + +The +.Ic zone +statement is used to define how information about particular DNS zones +is managed by the server. There are five different zone types. + +.Bl -tag -width 1 +.It Ic master +The server has a master copy of the data for the zone and will be able +to provide authoritative answers for it. + +.It Ic slave +A +.Ic slave +zone is a replica of a master zone. The +.Ic masters +list specifies one or more IP addresses that the slave contacts to +update its copy of the zone. If a +.Ic port +is specified then checks to see if the zone is current and zone transfers +will be done to the port given. If +.Ic file +is specified, then the replica will be written to the named file. +Use of the +.Ic file +clause is highly recommended, since it often speeds server startup +and eliminates a needless waste of bandwidth. + +.It Ic stub +A +.Ic stub +zone is like a slave zone, except that it replicates +only the NS records of a master zone instead of the entire zone. + +.It Ic forward +A +.Ic forward +zone is used to direct all queries in it to other servers, as described in +.Sx THE OPTIONS STATEMENT +section. The specification of options in such a zone will override +any global options declared in the +.Ic options +statement. + +.Pp +If either no +.Ic forwarders +clause is present in the zone or an empty list for +.Ic forwarders +is given, then no forwarding will be done for the zone, cancelling the +effects of any +.Ic forwarders +in the +.Ic options +statement. +Thus if you want to use this type of zone to change only the behavior of +the global +.Ic forward +option, and not the servers used, then you also need to respecify the +global forwarders. + +.It Ic hint +The initial set of root nameservers is specified using a +.Ic hint +zone. When the server starts up, it uses the root hints +to find a root nameserver and get the most recent list of root nameservers. +.El + +.Pp +Note: previous releases of BIND used the term +.Ic primary +for a master zone, +.Ic secondary +for a slave zone, and +.Ic cache +for a hint zone. + +.Ss Classes + +The zone's name may optionally be followed by a class. If a class is not +specified, class +.Ic in +(for "internet"), is assumed. This is correct for the vast majority +of cases. + +.Pp +The +.Ic hesiod +class is for an information service from MIT's Project Athena. It is +used to share information about various systems databases, such as +users, groups, printers and so on. More information can be found at +ftp://athena-dist.mit.edu/pub/ATHENA/usenix/athena_changes.PS. +The keyword +.Ic hs +is a synonym for +.Ic hesiod . + +.Pp +Another MIT development was CHAOSnet, a LAN protocol created in the +mid-1970s. It is still sometimes seen on LISP stations and other +hardware in the AI community, and zone data for it can be specified +with the +.Ic chaos +class. + +.Ss Options + +.Bl -tag -width 1 +.It Ic check-names +See the subsection on +.Sx Name Checking +in +.Sx THE OPTIONS STATEMENT . + +.It Ic allow-query +See the description of +.Ic allow-query +in the +.Sx Access Control +subsection of +.Sx THE OPTIONS STATEMENT . + +.It Ic allow-update +Specifies which hosts are allowed to submit Dynamic DNS updates to the +server. The default is to deny updates from all hosts. + +.It Ic allow-transfer +See the description of +.Ic allow-transfer +in the +.Sx Access Control +subsection of +.Sx THE OPTIONS STATEMENT . + +.It Ic transfer-source +.Ic transfer-source +determines which local address will be bound to the TCP connection +used to fetch this zone. If not set, it defaults to a system +controlled value which will usually be the address of the interface +``closest to'' the remote end. This address must appear in the remote end's +.Ic allow-transfer +option for this zone if one is specified. + +.It Ic max-transfer-time-in +See the description of +.Ic max-transfer-time-in +in the +.Sx Zone Transfers +subsection of +.Sx THE OPTIONS STATEMENT . + +.It Ic dialup +See the description of +.Ic dialup +in the +.Sx Boolean Options +subsection of +.Sx THE OPTIONS STATEMENT . + +.It Ic notify +See the description of +.Sx notify +in the +.Sx Boolean Options +subsection of the +.Sx THE OPTIONS STATEMENT . + +.It Ic also-notify +.Ic also-notify +is only meaningful if +.Ic notify +is active for this zone. +The set of machines that will receive a DNS NOTIFY message for this +zone is made up of all the listed nameservers for the zone (other than +the primary master) plus any IP addresses specified with +.Ic also-notify . +.Ic also-notify +is not meaningful for +.Ic stub +zones. The default is the empty list. + +.It Ic forward +.Ic forward +is only meaningful if the zone has a +.Ic forwarders +list. The +.Ic only +value causes the lookup to fail after trying the +.Ic forwarders +and getting no answer, while +.Ic first +would allow a normal lookup to be tried. + +.It Ic forwarders +The +.Ic forwarders +option in a zone is used to override the list of global forwarders. +If it is not specified in a zone of type +.Ic forward , +.Em no +forwarding is done for the zone; the global options are not used. + +.It Ic pubkey +The DNSSEC flags, protocol, and algorithm are specified, as well as a base-64 +encoded string representing the key. +.El + +.Sh THE ACL STATEMENT +.Ss Syntax + +.Bd -literal +acl \fIname\fR { + \fIaddress_match_list\fR +}; +.Ed + +.Ss Definition and Usage + +The +.Ic acl +statement creates a named address match list. +It gets its name from a primary use of address match lists: Access +Control Lists (ACLs). + +.Pp +Note that an address match list's name must be defined with +.Ic acl +before it can be used elsewhere; no forward +references are allowed. + +.Pp +The following ACLs are built-in: + +.Bl -tag -width 1 +.It Ic any +Allows all hosts. +.It Ic none +Denies all hosts. +.It Ic localhost +Allows the IP addresses of all interfaces on the system. +.It Ic localnets +Allows any host on a network for which the system has an interface. +.El + +.Sh THE KEY STATEMENT +.Ss Syntax + +.Bd -literal +key \fIkey_id\fR { + algorithm \fIalgorithm_id\fR; + secret \fIsecret_string\fR; +}; +.Ed + +.Ss Definition and Usage + +The +.Ic key +statement defines a key ID which can be used in a +.Ic server +statement to associate a method of authentication with a particular +name server that is more rigorous than simple IP address matching. +A key ID must be created with the +.Ic key +statement before it can be used in a +.Ic server +definition or an address match list. + +.Pp +The +.Va algorithm_id +is a string that specifies a +security/authentication algorithm. +.Va secret_string +is the secret to be used by the algorithm, +and is treated as a base-64 encoded string. +It should go without saying, but probably can't, +that if you have +.Va secret_string 's +in your +.Pa named.conf , +then it should not be readable by anyone but the superuser. + +.Sh THE TRUSTED-KEYS STATEMENT +.Ss Syntax + +.Bd -literal +trusted-keys { + [ \fIdomain_name\fR \fIflags\fR \fIprotocol\fR \fIalgorithm\fR \fIkey\fR; ] +}; +.Ed + +.Ss Definition and Usage + +The +.Ic trusted-keys +statement is for use with DNSSEC-style security, originally specified +in RFC 2065. DNSSEC is meant to +provide three distinct services: key distribution, data origin +authentication, and transaction and request authentication. A +complete description of DNSSEC and its use is beyond the scope of this +document, and readers interested in more information should start with +RFC 2065 and then continue with the Internet Drafts available at +http://www.ietf.org/ids.by.wg/dnssec.html. + +.Pp +Each trusted key is associated with a domain name. Its attributes are +the non-negative integral +.Va flags , +.Va protocol , +and +.Va algorithm , +as well as a base-64 encoded string representing the +.Va key . + +.Pp +Any number of trusted keys can be specified. + +.Sh THE SERVER STATEMENT +.Ss Syntax + +.Bd -literal +server \fIip_addr\fR { + [ bogus \fIyes_or_no\fR; ] + [ transfers \fInumber\fR; ] + [ transfer-format ( one-answer | many-answers ); ] + [ keys { \fIkey_id\fR [ \fIkey_id\fR ... ] }; ] +}; +.Ed + +.Ss Definition and Usage + +The server statement defines the characteristics to be +associated with a remote name server. + +.Pp +If you discover that a server is giving out bad data, marking it as +.Ic bogus +will prevent further queries to it. The default value of +.Ic bogus +is +.Li no . + +.Pp +The server supports two zone transfer methods. The first, +.Ic one-answer , +uses one DNS message per resource record transferred. +.Ic many-answers +packs as many resource records as possible into a message. +.Ic many-answers +is more efficient, but is only known to be understood by BIND 8.1 and +patched versions of BIND 4.9.5. You can specify which method to use +for a server with the +.Ic transfer-format +option. If +.Ic transfer-format +is not specified, the +.Ic transfer-format +specified by the +.Ic options +statement will be used. + +.Pp +The +.Ic transfers +will be used in a future release of the server to limit the number of +concurrent in-bound zone transfers from the specified server. It is +checked for syntax but is otherwise ignored. + +.Pp +The +.Ic keys +clause is used to identify a +.Va key_id +defined by the +.Ic key +statement, to be used for transaction security when talking to the +remote server. +The +.Ic key +statememnt must come before the +.Ic server +statement that references it. + +.Pp +The +.Ic keys +statement is intended for future use by the +server. It is checked for syntax but is otherwise ignored. + +.Sh THE CONTROLS STATEMENT +.Ss Syntax + +.Bd -literal +controls { + [ inet \fIip_addr\fR + port \fIip_port\fR + allow { \fIaddress_match_list\fR; }; ] + [ unix \fIpath_name\fR + perm \fInumber\fR + owner \fInumber\fR + group \fInumber\fR; ] +}; +.Ed + +.Ss Definition and Usage + +The +.Ic controls +statement declares control channels to be used by system +administrators to affect the operation of the local name server. +These control channels are used by the +.Nm ndc +utility to send commands +to and retrieve non-DNS results from a name server. + +.Pp +A +.Ic unix +control channel is a FIFO in the file system, and access to it is +controlled by normal file system permissions. It is created by +.Nm named +with the specified file mode bits (see +.Xr chmod 1 ) , +user and group owner. Note that, unlike +.Nm chmod , +the mode bits specified for +.Ic perm +will normally have a leading +.Li 0 +so the number is interpreted as octal. Also note that the user and +group ownership specified as +.Ic owner +and +.Ic group +must be given as numbers, not names. +It is recommended that the +permissions be restricted to administrative personnel only, or else any +user on the system might be able to manage the local name server. + +.Pp +An +.Ic inet +control channel is a TCP/IP socket accessible to the Internet, created +at the specified +.Va ip_port +on the specified +.Va ip_addr . +Modern +.Nm telnet +clients are capable of speaking directly to these +sockets, and the control protocol is ARPAnet-style text. +It is recommended that 127.0.0.1 be the only +.Va ip_addr +used, and this only if you trust all non-privileged users on the local +host to manage your name server. + +.Sh THE INCLUDE STATEMENT +.Ss Syntax + +.Bd -literal +include \fIpath_name\fR; +.Ed + +.Ss Definition and Usage + +The +.Ic include +statement inserts the specified file at the point that the +.Ic include +statement is encountered. It cannot be used within another statement, +though, so a line such as +.Dl acl internal_hosts { include "internal_hosts.acl"; }; +is not allowed. + +.Pp +Use +.Ic include +to break the configuration up into easily-managed chunks. +For example: + +.Bd -literal +include "/etc/security/keys.bind"; +include "/etc/acls.bind"; +.Ed + +could be used at the top of a BIND configuration file in order to +include any ACL or key information. + +.Pp +Be careful not to type +``#include'', like you would in a C program, because +``#'' is used to start a comment. + +.Sh EXAMPLES + +The simplest configuration file that is still realistically useful is +one which simply defines a hint zone that has a full path to the root +servers file. +.Bd -literal +zone \&".\&" in { + type hint; + file \&"/var/named/root.cache\&"; +}; +.Ed + +Here's a more typical real-world example. + +.Bd -literal +/* + * A simple BIND 8 configuration + */ + +logging { + category lame-servers { null; }; + category cname { null; }; +}; + +options { + directory \&"/var/named\&"; +}; + +controls { + inet * port 52 allow { any; }; // a bad idea + unix \&"/var/run/ndc\&" perm 0600 owner 0 group 0; // the default +}; + +zone \&"isc.org\&" in { + type master; + file \&"master/isc.org\&"; +}; + +zone \&"vix.com\&" in { + type slave; + file \&"slave/vix.com\&"; + masters { 10.0.0.53; }; +}; + +zone \&"0.0.127.in-addr.arpa\&" in { + type master; + file \&"master/127.0.0\&"; +}; + +zone \&".\&" in { + type hint; + file \&"root.cache\&"; +}; +.Ed + +.Sh FILES +.Bl -tag -width 1 -compact +.It Pa /etc/named.conf +The BIND 8 +.Nm named +configuration file. +.El + +.Sh SEE ALSO +.Xr named 8 , +.Xr ndc 8 diff --git a/contrib/bind/doc/man/ndc.8 b/contrib/bind/doc/man/ndc.8 index 247ef96..a4645e6 100644 --- a/contrib/bind/doc/man/ndc.8 +++ b/contrib/bind/doc/man/ndc.8 @@ -1,142 +1,133 @@ -.\" Copyright (c) 1994 -.\" 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) 1998,1999 by Internet Software Consortium .\" -.Dd November 27, 1994 +.\" 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 December 31, 1998 .Dt @INDOT_U@NDC @SYS_OPS_EXT_U@ .Os BSD 4 .Sh NAME -.Nm @INDOT@ndc -.Nd name daemon control interface +.Nm ndc +.Nd name daemon control program .Sh SYNOPSIS -.Nm @INDOT@ndc -.Ar directive -.Op Ar ... +.Nm ndc +.Op Fl c Ar channel +.Op Fl l Ar localsock +.Op Fl p Ar pidfile +.Op Fl d +.Op Fl q +.Op Fl s +.Op Fl t +.Op Ar command .Sh DESCRIPTION -This command allows the name server administrator to send various signals -to the name server, or to restart it. Zero or more directives may be given, -from the following list: -.Bl -tag -width "querylog" -.It Ic status -Displays the current status of -.Xr @INDOT@named @SYS_OPS_EXT@ -as shown by -.Xr ps @CMD_EXT@ . -.It Ic dumpdb -Causes -.Ic @INDOT@named -to dump its database and cache to -.Pa /var/tmp/named_dump.db -(uses the -.Dv INT -signal.) -.It Ic reload -Causes -.Ic @INDOT@named -to check the serial numbers of all primary and secondary zones -and to reload those that have changed (uses the -.Dv HUP -signal.) -.It Ic stats -Causes -.Ic @INDOT@named -to dump its statistics to -.Pa /var/tmp/named.stats -(uses the -.Dv IOT -or -.Dv ABRT -signal.) -.It Ic trace -Causes -.Ic @INDOT@named -to increment its -.Dq tracing level -by one. Whenever the tracing level -is nonzero, trace information will be written to -.Pa /var/tmp/named.run . -Higher tracing levels result in more detailed information. -(Uses the -.Dv USR1 -signal.) -.It Ic notrace -Causes -.Ic @INDOT@named -to set its -.Dq tracing level -to zero, closing -.Pa /var/tmp/named.run , -if it is open (uses the -.Dv USR2 -signal.) -.It Ic querylog -Causes -.Ic @INDOT@named -to toggle the -.Dq query logging -feature, which while on will result in a -.Xr syslog @SYSCALL_EXT@ -of each incoming query (uses the -.Dv WINCH -signal.) Note that query logging -consumes quite a lot of log file space. This directive may also be given as -.Ic qrylog . -.It Ic start -Causes -.Ic @INDOT@named -to be started, as long as it isn't already running. -.It Ic stop -Causes -.Ic @INDOT@named -to be stopped, if it is running. -.It Ic restart -Causes -.Ic @INDOT@named -to be killed and restarted. +This command allows the system administrator to control the operation +of a name server. If no +.Ar command +is given, +.Ic ndc +will prompt for commands until it reads EOF. +.Pp +Options are: +.Bl -tag -width Fl +.It Fl c Ar channel +Specifies the rendezvous point for the control channel. The default is +.Pa /var/run/ndc +(a UNIX domain socket which is also the server's default control channel). +If the desired control channel is a TCP/IP socket, then the format of the +.Ar channel +argument is +.Sy ipaddr/port +(for example, +.Sy 127.0.0.1/54 +would be TCP port 54 on the local host.) +.It Fl l Ar localsock +This option will +.Xr bind 2 +the client side of the control channel to a specific address. Servers can +be configured to reject connections which do not come from specific addresses. +The format is the same as for +.Ar channel +(see above). +.It Fl p Ar pidfile +For backward compatibility with older name servers, +.Ic ndc +is able to use UNIX signals for control communications. This capability is +optional in modern name servers and will disappear altogether at some future +time. Note that the available +.Ar command +set is narrower when the signal interface is used. A likely +.Ar pidfile +argument would be something like +.Pa /var/run/named.pid . +.It Fl d +Turns on debugging output, which is of interest mainly to developers. +.It Fl q +Suppresses prompts and result text. +.It Fl s +Suppresses nonfatal error announcements. +.It Fl t +Turns on protocol and system tracing, useful in installation debugging. .El -.Sh BUGS -Arguments to +.Sh COMMANDS +Several commands are built into +.Ic ndc , +but the full set of commands supported by the name server is dynamic and +should be discovered using the +.Ar help +command (see below). Builtin commands are: +.Bl -tag -width Fl +.It Ar /help +Provides help for builtin commands. +.It Ar /exit +Exit from +.Ic ndc +command interpreter. +.It Ar /trace +Toggle tracing (see +.Fl -t +description above). +.It Ar /debug +Toggle debugging (see +.Fl d +description above). +.It Ar /quiet +Toggle quietude (see +.Fl q +description above). +.It Ar /silent +Toggle silence (see +.Fl s +description above). +.El +.Sh NOTES +If running in +.Ar pidfile +mode, any arguments to +.Ar start +and +.Ar restart +commands are passed to the new .Ic @INDOT@named -are not preserved by -.Ic restart , -or known by -.Ic start . -.Pp -Some mechanism for controlling the parameters and environment should exist. -.Pp -Implemented as a -.Xr sh @CMD_EXT@ -script. +on its command line. If running in +.Ar channel +mode, there is no +.Ar start +command and the +.Ar restart +command just tells the name server to +.Xr execvp 2 +itself. .Sh AUTHOR Paul Vixie (Internet Software Consortium) .Sh SEE ALSO .Xr @INDOT@named @SYS_OPS_EXT@ , -.Xr @INDOT@named.reload @SYS_OPS_EXT@ , -.Xr @INDOT@named.restart @SYS_OPS_EXT@ . diff --git a/contrib/bind/doc/man/nsupdate.8 b/contrib/bind/doc/man/nsupdate.8 new file mode 100644 index 0000000..feaa64c --- /dev/null +++ b/contrib/bind/doc/man/nsupdate.8 @@ -0,0 +1,214 @@ +.\" $Id: nsupdate.8,v 8.4 1999/10/17 06:26:18 cyarnell Exp $ +.\" +.\"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. +.Dd March 5, 1999 +.Dt NSUPDATE @SYS_OPS_EXT_U@ +.Os BSD 4 +.Sh NAME +.Nm nsupdate +.Nd update Internet name servers interactively +.Sh SYNOPSIS +.Nm nsupdate +.Op Fl Ar k keydir:keyname +.Op Fl Ar d +.Op Fl Ar v +.Op Ar filename +.Sh DESCRIPTION +.Ic Nsupdate +is a program to update Internet domain name servers +supporting dynamic update. +.Ic Nsupdate +uses the DNS resolver library to pass messages +to a DNS server requesting the additional or deletion of +DNS resource records (RRs). +.Ic Nsupdate +reads input from +.Ar filename +or standard input. +.Sh ARGUMENTS +.Bl -tag -width Fl +.It Fl k +Sign updates with TSIG. +.It Fl d +Debug mode. +.It Fl v +Virtual circuit - use TCP to communication with server. +Default is UDP. +.Sh INPUT FORMAT +.Ic Nsupdate +reads input records, one per line, +each line contributing a resource record to an +update request. +All domain names used in a single update request +must belong to the same DNS zone. +A blank line causes the accumulated +records to be formated into a single update request +and transmitted to the zone's authoritative name servers. +Additional records may follow, +which are formed into additional, +completely independent update requests. +For the last request to be transmitted, a blank line +must end the input. +.Pp +Records take one of two general forms. +.Em Prerequisite +records specify conditions that must be satisfied before +the request will be processed. +.Em Update +records specify changes to be made to the DNS database. +A update request consists of zero or more prerequisites +and one or more updates. +Each update request is processed atomically - +all prerequisites must be satisfied, then all updates +will be performed. +.Pp +.Ic Nsupdate +understands the following input record formats: +.Pp + +.Bl -ohang + +.It Ic prereq nxdomain Va domain-name +Requires that no RR of any type exists with name +.Va domain-name . + +.It Ic prereq yxdomain Va domain-name +Requires that at least one RR named +.Va domain-name +must exist. + +.It Xo +.Ic prereq nxrrset Va domain-name Op class +.Va type +.Xc +Requires that no RR exists of the specified +.Va type +and +.Va domain-name . + +.It Xo +.Ic prereq yxrrset +.Va domain-name Op class +.Va type Op data... +.Xc +Requires that a RR exists of the specified +.Va type +and +.Va domain-name . +If +.Va data +is specified, it must match exactly. + +.It Xo +.Ic update delete +.Va domain-name Op class +.Va Op type Op data... +.Xc +Deletes RRs named +.Va domain-name . +If +.Va type +(and possibly +.Va data ) +is specified, +only matching records will be deleted. + +.It Xo +.Ic update add +.Va domain-name ttl Op class +.Va type data... +.Xc +Adds a new RR with specified +.Va ttl , type , +and +.Va data . + +.El + +.Sh EXAMPLES +The following example illustrates the interactive use of +.Ic nsupdate +to change an IP address by deleting any existing A records +for a domain name and then inserting a new one. +Since no prerequisites are specified, +the new record will be added even if +there were no existing records to delete. +Note the +trailing blank line, required to process the request. +.Bd -literal -offset indent +$ nsupdate +> update delete test.example.com A +> update add test.example.com 3600 A 10.1.1.1 +> + +.Ed +.Pp +In this example, a CNAME alias is added to the database +only if there are no existing A or CNAME records for +the domain name. +.Bd -literal -offset indent +$ nsupdate +> prereq nxrrset www.example.com A +> prereq nxrrset www.example.com CNAME +> update add www.example.com 3600 CNAME test.example.com +> + +.Ed +.Pp +In this example, the nsupdate will be signed with the key "mykey", which +is in the directory "/var/named/keys". +.Bd -literal -offset indent +$ nsupdate -k /var/named/keys:mykey +> update add ftp.example.com 60 A 192.168.5.1 +> + +.Ed + +.Sh DIAGNOSTICS +.Bl -ohang + +.It Qq send error +Typically indicates that the authoritative nameservers could not be reached + +.It Qq failed update packet +Typically indicates that the nameserver has rejected the update, +either because the nameserver doesn't support dynamic update, +or due to an authentication failure + +.It Qq res_mkupdate: packet size = Va size +(and no other messages) +The update was successfully received and authenticated by the nameserver. +The prerequisites, however, may have prevented the update from actually +being performed. The only way to determine if the update was performed +is to use debug mode +.Fl ( d ) +and examine the status field in the nameserver's reply. + +.Sh FILES +.It Pa /etc/resolv.conf +initial domain name and name server addresses +.Sh SEE ALSO +.Xr @INDOT@named @SYS_OPS_EXT@ , +.Xr resolver @LIB_NETWORK_EXT@ , +.Xr resolver @FORMAT_EXT@ ; +RFC-1034, +.Dq Domain Names - Concepts and Facilities ; +RFC-1035, +.Dq Domain Names - Implementation and Specification ; +RFC-2136, +Dynamic Updates in the Domain Name System. +.Sh AUTHOR +Brent Baccala diff --git a/contrib/bind/doc/man/resolver.3 b/contrib/bind/doc/man/resolver.3 index fe0c3f7..6ddfe11 100644 --- a/contrib/bind/doc/man/resolver.3 +++ b/contrib/bind/doc/man/resolver.3 @@ -16,44 +16,134 @@ .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" .\" @(#)resolver.3 6.5 (Berkeley) 6/23/90 -.\" $Id: resolver.3,v 8.5 1997/03/14 02:29:48 vixie Exp $ +.\" $Id: resolver.3,v 8.11 1999/09/13 23:33:24 vixie Exp $ .\" -.Dd December 11, 1995 +.Dd October 19, 1998 .Dt RESOLVER @LIB_NETWORK_EXT_U@ .Os BSD 4 .Sh NAME +.Nm res_ninit , +.Nm res_nisourserver , +.Nm fp_resstat , +.Nm res_npquery , +.Nm res_hostalias , +.Nm res_nquery , +.Nm res_nsearch , +.Nm res_nquerydomain , +.Nm res_nmkquery , +.Nm res_nsend , +.Nm res_nupdate , +.Nm res_nmkupdate , +.Nm res_nclose , +.Nm res_nsendsigned , +.Nm res_nsendupdate , +.Nm res_findzonecut , +.Nm dn_comp , +.Nm dn_expand , +.Nm hstrerror , +.Nm res_init , +.Nm res_isourserver , +.Nm p_nquery , +.Mm p_query , +.Mm hostalias , .Nm res_query , .Nm res_search , +.Nm res_querydomain , .Nm res_mkquery , .Nm res_send , -.Nm res_init , -.Nm dn_comp , -.Nm dn_expand +.Nm res_update , +.Nm res_close , +.Nm herror .Nd resolver routines .Sh SYNOPSIS .Fd #include <sys/types.h> .Fd #include <netinet/in.h> .Fd #include <arpa/nameser.h> .Fd #include <resolv.h> +.Fn res_ninit "res_state statp" +.Fn res_nisourserver "const res_state statp" "const struct sockaddr_in *addr" +.Fn fp_resstat "const res_state statp" "FILE *fp" +.Fn res_npquery "const res_state statp" "const u_char *msg" "int msglen" "FILE *fp" +.Fn res_hostalias "const res_state statp" "const char *name" "char *buf" "size_t buflen" +.Fn res_nquery "res_state statp" "const char *dname" "int class" "int type" "u_char *answer" "int anslen" +.Fn res_nsearch "res_state statp" "const char *dname" "int class" "int type" "u_char * answer" "int anslen" +.Fn res_nquerydomain "res_state statp" "const char *name" "const char *domain" "int class" "int type" "u_char *answer" "int anslen" +.Fn res_nmkquery "res_state statp, int op, const char *dname" "int class" "int type" "const u_char *data" "int datalen" "const u_char *newrr" "u_char *buf" "int buflen" +.Fn res_nsend "res_state statp" "const u_char *msg" "int msglen" "u_char *answer" "int anslen" +.Fn res_nupdate "res_state statp" "ns_updrec *rrecp_in" +.Fn res_nmkupdate "res_state statp" "ns_updrec *rrecp_in" "u_char *buf" "int buflen" +.Fn res_nclose "res_state statp" +.Fn res_nsendsigned "res_state statp" "const u_char *msg" "int msglen" "ns_tsig_key *key" "u_char *answer" "int anslen" +.Fn res_findzonecut "res_state statp" "const char *dname" "ns_class class" "int options" "char *zname" "size_t zsize" "struct in_addr *addrs" "int naddrs" +.Fn res_nsendupdate "res_state statp" "ns_updrec *rrecp_in" "ns_tsig_key *key" "char *zname" "struct in_addr addr" +.Fn dn_comp "const char *exp_dn" "u_char *comp_dn" "int length" "u_char **dnptrs, **lastdnptr" +.Fn dn_expand "const u_char *msg, *eomorig, *comp_dn" "char *exp_dn" "int length" +.Fn hstrerror "int err" +.Sh DEPRECATED +.nr nS 1 +.Fd #include <sys/types.h> +.Fd #include <netinet/in.h> +.Fd #include <arpa/nameser.h> +.Fd #include <resolv.h> +.Fn res_init "void" +.Fn res_isourserver "const struct sockaddr_in *addr" +.Fn p_nquery "const u_char *msg" "int msglen" "FILE *fp" +.Fn p_query "const u_char *msg" "FILE *fp" +.Fn hostalias "const char *name" .Fn res_query "const char *dname" "int class, type" "u_char *answer" "int anslen" .Fn res_search "const char *dname" "int class, type" "u_char *answer" "int anslen" -.Fn res_mkquery "int op" "const char *dname" "int class, type" "const char *data" "int datalen" "struct rrec *newrr" "u_char *buf" "int buflen" +.Fn res_querydomain "const char *name" "const char *domain" "int class" "int type" "u_char *answer" "int anslen" +.Fn res_mkquery "int op" "const char *dname, int class, type" "const char *data" "int datalen" "struct rrec *newrr" "u_char *buf" "int buflen" .Fn res_send "const u_char *msg" "int msglen" "u_char *answer" "int anslen" -.Fn res_init -.Fn dn_comp "const char *exp_dn" "u_char *comp_dn" "int length" "u_char **dnptrs, **lastdnptr" -.Fn dn_expand "const u_char *msg, *eomorig, *comp_dn" "char *exp_dn" "int length" +.Fn res_update "ns_updrec *rrecp_in" +.Fn res_close "void" .Fn herror "const char *s" -.Fn hstrerror "int err" .Sh DESCRIPTION These routines are used for making, sending and interpreting query and reply messages with Internet domain name servers. .Pp -Global configuration and state information that is used by the -resolver routines is kept in the structure -.Ft _res . -Most of the values have reasonable defaults and can be ignored. +State information is kept in +.Fa statp +and is used to control the behavior of these functions. +.Fa statp +should be set to all zeros prior to the first call to any of these functions. +.Pp +The functions +.Fn res_init , +.Fn res_isourserver , +.Fn p_nquery , +.Fn p_query , +.Fn hostalias , +.Fn res_query , +.Fn res_search , +.Fn res_querydomain , +.Fn res_mkquery , +.Fn res_send , +.Fn res_update , +.Fn res_close +and +.Fn herror +are deprecated and are supplied for compatability with old source +code. +They use global configuration and state information that is +kept in the structure +.Ft _res +rather than that referenced through +.Ft statp . +.Pp +Most of the values in +.Ft statp +and +.Ft _res +are initialized on the first call to +.Fn res_ninit +/ +.Fn res_init +to reasonable defaults and can be ignored. Options stored in +.Ft statp->options +/ .Ft _res.options are defined in .Pa resolv.h @@ -65,14 +155,14 @@ of the options enabled. .It Dv RES_INIT True if the initial name server address and default domain name are initialized (i.e., +.Fn res_ninit +/ .Fn res_init has been called). .It Dv RES_DEBUG Print debugging messages. .It Dv RES_AAONLY Accept authoritative answers only. -With this option, -.Fn res_send should continue until it finds an authoritative answer or finds an error. Currently this is not implemented. .It Dv RES_USEVC @@ -84,22 +174,28 @@ to keep the TCP connection open between queries. This is useful only in programs that regularly do many queries. UDP should be the normal mode used. .It Dv RES_IGNTC -Unused currently (ignore truncation errors, i.e., don't retry with TCP). +Ignore truncation errors, i.e., don't retry with TCP. .It Dv RES_RECURSE Set the recursion-desired bit in queries. This is the default. (\c +.Fn res_nsend +/ .Fn res_send does not do iterative queries and expects the name server to handle recursion.) .It Dv RES_DEFNAMES If set, +.Fn res_nsearch +/ .Fn res_search will append the default domain name to single-component names (those that do not contain a dot). This option is enabled by default. .It Dv RES_DNSRCH If this option is set, +.Fn res_nsearch +/ .Fn res_search will search for host names in the current domain and in parent domains; see .Xr hostname @DESC_EXT@ . @@ -110,10 +206,31 @@ This option is enabled by default. This option turns off the user level aliasing feature controlled by the .Ev HOSTALIASES -environment variable. Network daemons should set this option. +environment variable. +Network daemons should set this option. +.It Dv RES_USE_INET6 +This option causes +.Xr gethostbyname @LIB_NETWORK_EXT@ +to look for AAAA records before looking for A records if none are found. +.It Dv RES_ROTATE +This options causes the +.Fn res_nsend +/ +.Fn res_send +to rotate the list of nameservers in +.Fa statp->nsaddr_list +/ +.Fa _res.nsaddr_list . +.It Dv RES_KEEPTSIG +This option causes +.Fn res_nsendsigned +to leave the message unchanged after TSIG verification; otherwise the TSIG +record would be removed and the header updated. .El .Pp The +.Fn res_ninit +/ .Fn res_init routine reads the configuration file (if any; see @@ -135,6 +252,8 @@ Another environment variable .Pq Dq Ev RES_OPTIONS can be set to override certain internal resolver options which are otherwise set by changing fields in the +.Ft statp +/ .Ft _res structure or are inherited from the configuration file's .Ic options @@ -146,9 +265,11 @@ Initialization normally occurs on the first call to one of the other resolver routines. .Pp The +.Fn res_nquery +/ .Fn res_query -function provides an interface to the server query mechanism. -It constructs a query, sends it to the local server, +functions provides interfaces to the server query mechanism. +They constructs a query, sends it to the local server, awaits a response, and makes preliminary checks on the reply. The query requests information of the specified .Fa type @@ -161,10 +282,18 @@ The reply message is left in the buffer with length .Fa anslen supplied by the caller. +.Fn res_nquery +/ +.Fn res_query +return -1 on error or the length of the answer. .Pp The +.Fn res_nsearch +/ .Fn res_search -routine makes a query and awaits a response like +routines make a query and awaits a response like +.Fn res_nquery +/ .Fn res_query , but in addition, it implements the default and search rules controlled by the @@ -172,13 +301,19 @@ controlled by the and .Dv RES_DNSRCH options. -It returns the first successful reply. +It returns the length of the first successful reply which is stored in +.Ft answer +or -1 on error. .Pp The remaining routines are lower-level routines used by +.Fn res_nquery +/ .Fn res_query . The +.Fn res_nmkquery +/ .Fn res_mkquery -function +functions constructs a standard query message and places it in .Fa buf . It returns the size of the query, or \-1 if the query is @@ -196,17 +331,159 @@ The domain name for the query is given by is currently unused but is intended for making update messages. .Pp The +.Fn res_nsend +/ .Fn res_send -routine +/ +.Fn res_nsendsigned +routines sends a pre-formatted query and returns an answer. It will call +.Fn res_ninit +/ .Fn res_init if .Dv RES_INIT is not set, send the query to the local name server, and -handle timeouts and retries. +handle timeouts and retries. Additionally, +.Fn res_nsendsigned +will use TSIG signatures to add authentication to the query and verify the +response. In this case, only one nameserver will be contacted. The length of the reply message is returned, or \-1 if there were errors. .Pp +.Fn res_nquery +/ +.Fn res_query , +.Fn res_nsearch +/ +.Fn res_search +and +.Fn res_nsend +/ +.Fn res_send +return a length that may be bigger than +.Fa anslen . +In that case the query should be retried with a bigger buffer. +NOTE the answer to the second query may be larger still so supplying +a buffer that bigger that the answer returned by the previous +query is recommended. +.Pp +.Fa answer +MUST be big enough to receive a maximum UDP response from the server or +parts of the answer will be silently discarded. +The default maximum UDP response size is 512 bytes. +.Pp +The functions +.Fn res_nisourserver +/ +.Fn res_isourserver +return true when +.Fa inp +is one of the servers in +.Fa statp->nsaddr_list +/ +.Fa _res.nsaddr_list . +.Pp +The functions +.Fn res_npquery +/ +.Fn p_nquery +/ +.Fn p_query +print out the query and any answer in +.Fa msg +on +.Fa fp . +.Fn p_query +is equivalent to +.Fn p_nquery +with +.Fa msglen +set to 512. +.Pp +The function +.Fn fp_resstat +prints out the active flag bits in +.Fa statp->options +preceeded by the text ";; res options:" on +.Fa file . +.Pp +The functions +.Fn res_hostalias +/ +.Fn hostalias +lookup up name in the file referred to by the +.Ev HOSTALIASES files return a fully qualified hostname if found or NULL if +not found or an error occurred. +.Fn res_hostalias +uses +.Fa buf +to store the result in, +.Fn hostalias +uses a static buffer. +.Pp +The functions +.Fn res_nupdate +/ +.Fn res_update +take a list of ns_updrec +.Fa rrecp_in . +Identifies the containing zone for each record and groups the records +according to containing zone maintaining in zone order then sends and +update request to the servers for these zones. +The number of zones updated is returned or -1 on error. +.Pp +The function +.Fn res_findzonecut +discovers the closest enclosing zone cut for a specified domain name, +and finds the IP addresses of the zone's master servers. +.Pp +The function +.Fn res_nsendupdate +is used to perform TSIG authenticated dynamic update operations. +.Fn res_nsendupdate +sends a dynamic update to the specified IP address, authenticating the update +if the key is not NULL. +.Pp +The functions +.Fn res_nmkupdate +/ +.Fn res_mkupdate +take a linked list of ns_updrec +.Fa rrecp_in +and construct a UPDATE message in +.Fa buf . +.Fn res_nmkupdate +/ +.Fn res_mkupdate +return the length of the constructed message on no error or one of the +following error values. +.Bl -inset -width "-5" +.It -1 +An error occurred parsing +.Fa rrecp_in . +.It -2 +The buffer +.Fa buf +was too small. +.It -3 +The first record was not a zone section or there was a section order problem. +The section order is S_ZONE, S_PREREQ and S_UPDATE. +.It -4 +A number overflow occurred. +.It -5 +Unknown operation or no records. +.El +.Pp +The functions +.Fn res_nclose +/ +.Fn res_close +close any open files referenced through +.Fa statp +/ +.Fa _res . +.Pp The .Fn dn_comp function @@ -256,7 +533,11 @@ which is of size .Fa length . The size of compressed name is returned or \-1 if there was an error. .Pp -The external variable +The variables +.Ft statp->res_h_errno +/ +.Ft _res.res_h_errno +and external variable .Ft h_errno is set whenever an error occurs during resolver operation. The following definitions are given in @@ -265,8 +546,8 @@ definitions are given in #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 not found, or SERVFAIL */ -#define NO_RECOVERY 3 /* Nonrecoverable: FORMERR, REFUSED, NOTIMP */ +#define TRY_AGAIN 2 /* Non-Authoritative not found, or SERVFAIL */ +#define NO_RECOVERY 3 /* Non-Recoverable: FORMERR, REFUSED, NOTIMP */ #define NO_DATA 4 /* Valid name, no data for requested type */ .Ed .Pp diff --git a/contrib/bind/doc/man/resolver.5 b/contrib/bind/doc/man/resolver.5 index 044bf60..2129893 100644 --- a/contrib/bind/doc/man/resolver.5 +++ b/contrib/bind/doc/man/resolver.5 @@ -14,7 +14,7 @@ .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" .\" @(#)resolver.5 5.9 (Berkeley) 12/14/89 -.\" $Id: resolver.5,v 8.4 1997/03/14 02:29:49 vixie Exp $ +.\" $Id: resolver.5,v 8.6 1999/05/21 00:01:02 vixie Exp $ .\" .Dd November 11, 1993 .Dt RESOLVER @FORMAT_EXT_U@ @@ -46,14 +46,16 @@ The only name server to be queried will be on the local machine, the domain name is determined from the host name, and the domain search path is constructed from the domain name. .Pp -The different configuration options are: +The different configuration directives are: .Bl -tag -width "nameser" .It Li nameserver Internet address (in dot notation) of a name server that the .Nm resolver should query. Up to .Dv MAXNS -(currently 3) name servers may be listed, one per keyword. +(see +.Pa <resolv.h> ) +name servers may be listed, one per keyword. If there are multiple servers, the .Nm resolver library queries them in the order listed. @@ -138,6 +140,44 @@ meaning that if there are dots in a name, the name will be tried first as an absolute name before any .Em search list elements are appended to it. +.It Li timeout: Ns Ar n +sets the amount of time the resolver will wait for a response from a remote +name server before retrying the query via a different name server. Measured in +seconds, the default is +.Dv RES_TIMEOUT +(see +.Pa <resolv.h> ). +.It Li attempts: Ns Ar n +sets the number of times the resolver will send a query to its name servers +before giving up and returning an error to the calling application. The +default is +.Dv RES_DFLRETRY +(see +.Pa <resolv.h> ). +.It Li rotate +sets +.Dv RES_ROTATE +in +.Ft _res.options , +which causes round robin selection of nameservers from among those listed. +This has the effect of spreading the query load among all listed servers, +rather than having all clients try the first listed server first every time. +.It Li no-check-names +sets +.Dv RES_NOCHECKNAME +in +.Ft _res.options , +which disables the modern BIND checking of incoming host names and mail names +for invalid characters such as underscore (_), non-ASCII, or control characters. +.It Li inet6 +sets +.Dv RES_USE_INET6 +in +.Ft _res.options . +This has the effect of trying a AAAA query before an A query inside the +.Ft gethostbyname +function, and of mapping IPv4 responses in IPv6 ``tunnelled form'' if no +AAAA records are found but an A record set exists. .El .El .Pp @@ -174,6 +214,7 @@ The keyword and value must appear on a single line, and the keyword must start the line. The value follows the keyword, separated by white space. .Sh FILES .Pa /etc/resolv.conf +.Pa <resolv.h> .Sh SEE ALSO .Xr gethostbyname @LIB_NETWORK_EXT@ , .Xr hostname @DESC_EXT@ , diff --git a/contrib/bind/doc/man/tsig.3 b/contrib/bind/doc/man/tsig.3 new file mode 100644 index 0000000..fa852ee --- /dev/null +++ b/contrib/bind/doc/man/tsig.3 @@ -0,0 +1,240 @@ +.\" $Id: tsig.3,v 8.2 1999/01/08 18:54:28 vixie 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 January 1, 1996 +.Os BSD 4 +.Dt TSIG @SYSCALL_EXT@ +.Sh NAME +.Nm ns_sign , +.Nm ns_sign_tcp , +.Nm ns_sign_tcp_init , +.Nm ns_verify , +.Nm ns_verify_tcp , +.Nm ns_verify_tcp_init , +.Nm ns_find_tsig +.Nd TSIG system +.Sh SYNOPSIS +.Ft int +.Fo ns_sign +.Fa "u_char *msg" +.Fa "int *msglen" +.Fa "int msgsize" +.Fa "int error" +.Fa "void *k" +.Fa "const u_char *querysig" +.Fa "int querysiglen" +.Fa "u_char *sig" +.Fa "int *siglen" +.Fa "time_t in_timesigned" +.Fc +.Ft int +.Fn ns_sign_tcp "u_char *msg" "int *msglen" "int msgsize" "int error" \ + "ns_tcp_tsig_state *state" "int done" +.Ft int +.Fn ns_sign_tcp_init "void *k" "const u_char *querysig" "int querysiglen" \ + "ns_tcp_tsig_state *state" +.Ft int +.Fo ns_verify +.Fa "u_char *msg" +.Fa "int *msglen" +.Fa "void *k" +.Fa "const u_char *querysig" +.Fa "int querysiglen" +.Fa "u_char *sig" +.Fa "int *siglen" +.Fa "time_t in_timesigned" +.Fa "int nostrip" +.Fc +.Ft int +.Fn ns_verify_tcp "u_char *msg" "int *msglen" "ns_tcp_tsig_state *state" \ + "int required" +.Ft int +.Fn ns_verify_tcp_init "void *k" "const u_char *querysig" "int querysiglen" \ + "ns_tcp_tsig_state *state" +.Ft u_char * +.Fn ns_find_tsig "u_char *msg" "u_char *eom" +.Sh DESCRIPTION +The TSIG routines are used to implement transaction/request security of +DNS messages. +.Pp +.Fn ns_sign +and +.Fn ns_verify +are the basic routines. +.Fn ns_sign_tcp +and +.Fn ns_verify_tcp +are used to sign/verify TCP messages that may be split into multiple packets, +such as zone transfers, and +.Fn ns_sign_tcp_init, +.Fn ns_verify_tcp_init +initialize the state structure necessary for TCP operations. +.Fn ns_find_tsig +locates the TSIG record in a message, if one is present. +.Pp +.Fn ns_sign +.Bl -tag -width "in_timesigned" -compact -offset indent +.It Dv msg +the incoming DNS message, which will be modified +.It Dv msglen +the length of the DNS message, on input and output +.It Dv msgsize +the size of the buffer containing the DNS message on input +.It Dv error +the value to be placed in the TSIG error field +.It Dv key +the (DST_KEY *) to sign the data +.It Dv querysig +for a response, the signature contained in the query +.It Dv querysiglen +the length of the query signature +.It Dv sig +a buffer to be filled with the generated signature +.It Dv siglen +the length of the signature buffer on input, the signature length on output +.El +.Pp +.Fn ns_sign_tcp +.Bl -tag -width "in_timesigned" -compact -offset indent +.It Dv msg +the incoming DNS message, which will be modified +.It Dv msglen +the length of the DNS message, on input and output +.It Dv msgsize +the size of the buffer containing the DNS message on input +.It Dv error +the value to be placed in the TSIG error field +.It Dv state +the state of the operation +.It Dv done +non-zero value signifies that this is the last packet +.El +.Pp +.Fn ns_sign_tcp_init +.Bl -tag -width "in_timesigned" -compact -offset indent +.It Dv k +the (DST_KEY *) to sign the data +.It Dv querysig +for a response, the signature contained in the query +.It Dv querysiglen +the length of the query signature +.It Dv state +the state of the operation, which this initializes +.El +.Pp +.Fn ns_verify +.Bl -tag -width "in_timesigned" -compact -offset indent +.It Dv msg +the incoming DNS message, which will be modified +.It Dv msglen +the length of the DNS message, on input and output +.It Dv key +the (DST_KEY *) to sign the data +.It Dv querysig +for a response, the signature contained in the query +.It Dv querysiglen +the length of the query signature +.It Dv sig +a buffer to be filled with the signature contained +.It Dv siglen +the length of the signature buffer on input, the signature length on output +.It Dv nostrip +non-zero value means that the TSIG is left intact +.El +.Pp +.Fn ns_verify_tcp +.Bl -tag -width "in_timesigned" -compact -offset indent +.It Dv msg +the incoming DNS message, which will be modified +.It Dv msglen +the length of the DNS message, on input and output +.It Dv state +the state of the operation +.It Dv required +non-zero value signifies that a TSIG record must be present at this step +.El +.Pp +.Fn ns_verify_tcp_init +.Bl -tag -width "in_timesigned" -compact -offset indent +.It Dv k +the (DST_KEY *) to verify the data +.It Dv querysig +for a response, the signature contained in the query +.It Dv querysiglen +the length of the query signature +.It Dv state +the state of the operation, which this initializes +.El +.Pp +.Fn ns_find_tsig +.Bl -tag -width "in_timesigned" -compact -offset indent +.It Dv msg +the incoming DNS message +.It Dv msglen +the length of the DNS message +.El +.Sh RETURN VALUES +.Fn ns_find_tsig +returns a pointer to the TSIG record if one is found, and NULL otherwise. +.Pp +All other routines return 0 on success, modifying arguments when necessary. +.Pp +.Fn ns_sign +and +.Fn ns_sign_tcp +return the following errors: +.Bl -tag -width "NS_TSIG_ERROR_NO_SPACE" -compact -offset indent +.It Dv (-1) +bad input data +.It Dv (-ns_r_badkey) +The key was invalid, or the signing failed +.It Dv NS_TSIG_ERROR_NO_SPACE +the message buffer is too small. +.El +.Pp +.Fn ns_verify +and +.Fn ns_verify_tcp +return the following errors: +.Bl -tag -width "NS_TSIG_ERROR_NO_SPACE" -compact -offset indent +.It Dv (-1) +bad input data +.It Dv NS_TSIG_ERROR_FORMERR +The message is malformed +.It Dv NS_TSIG_ERROR_NO_TSIG +The message does not contain a TSIG record +.It Dv NS_TSIG_ERROR_ID_MISMATCH +The TSIG original ID field does not match the message ID +.It Dv (-ns_r_badkey) +Verification failed due to an invalid key +.It Dv (-ns_r_badsig) +Verification failed due to an invalid signature +.It Dv (-ns_r_badtime) +Verification failed due to an invalid timestamp +.It Dv ns_r_badkey +Verification succeeded but the message had an error of BADKEY +.It Dv ns_r_badsig +Verification succeeded but the message had an error of BADSIG +.It Dv ns_r_badtime +Verification succeeded but the message had an error of BADTIME +.El +.Pp +.Sh SEE ALSO +.Xr resolver 3 . +.Sh AUTHORS +Brian Wellington, TISLabs at Network Associates +.\" .Sh BUGS diff --git a/contrib/bind/doc/notes/data b/contrib/bind/doc/notes/data new file mode 100644 index 0000000..e522392 --- /dev/null +++ b/contrib/bind/doc/notes/data @@ -0,0 +1,51 @@ +/* + * We need a registy of name server addresses. For each, we retain an RTT + * and a list of name server names which have used this address. + */ +tree_t *by_nsaddr; +struct by_nsaddr { + u_int32_t rtt; /* measured. */ + char **names; /* NULL terminated array; strdup'd. */ +}; + +/* + * "struct server" is a name server, which can have many addresses. There + * is no central registry of servers, since each creator can have a different + * idea of what the addresses are. + */ +struct server { + char *name; /* made with strdup. */ + struct sockaddr_in *addrs; /* counted array. */ + int n_addrs; /* array size. */ +}; + +/* + * "struct zone" is a zone cut. + */ +tree_t *by_class; /* zone[class]. */ +struct zone { + enum {master, slave, cache, boot} + type; + + /* Servers learned from boot cache, a parent zone, or !auth answer. */ + struct server *servers_notauth; + + /* Servers learned from authoritative answer or local zone. */ + struct server *servers_auth; + + /* Root node of zone. */ + struct node *root; +}; + +struct node { + char *label; /* made with strdup. */ + tree_t *subs; /* subdomains (node[label]). */ + /* really this is "data" since for the zone cut tree we have no sets.*/ + tree_t *rrsets; /* rr sets (rrset[type]). */ +}; + +struct rrset { + rrtype type; + u_int32_t ttl; + u_char data[1]; /* struct size constrains this. */ +}; diff --git a/contrib/bind/doc/notes/db_names.c b/contrib/bind/doc/notes/db_names.c new file mode 100644 index 0000000..0b4e62c --- /dev/null +++ b/contrib/bind/doc/notes/db_names.c @@ -0,0 +1,184 @@ +/* + * 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. + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <netinet/in.h> +#include <arpa/nameser.h> + +#include <ctype.h> +#include <errno.h> +#include <resolv.h> +#include <stdio.h> + +#include "named.h" +#include "tree.h" + +struct node { + struct node *parent; /* NULL for "."'s node. */ + tree *children; /* Nodes using us as parent. */ + /*void *userdata;*/ /* For future use. */ + char name[sizeof(void*)]; /* Open array. */ +}; + +static struct node rootNode; + +static int +nodeCompare(t1, t2) + const tree_t t1, t2; +{ + const char *n1 = ((struct node *)t1)->name + sizeof(u_char), + *n2 = ((struct node *)t2)->name + sizeof(u_char); + + return (strcasecmp(n1, n2)); +} + +/* void * + * db_findname(const char *name, int storeflag) + * find or store a presentation format domain name. + * returns: + * NULL if an error occurred (check errno) + * else, node's unique, opaque address. + */ +void * +db_findname(name, storeflag) + const char *name; + int storeflag; +{ + struct node *node, *tnode; + const char *tname; + size_t len; + int ch; + + /* The root domain has its own static node. */ + if (name[0] == '\0') + return (&rootNode); + + /* Locate the end of the first label. */ + for (tname = name; (ch = *tname) != '\0'; tname++) { + /* Is this the end of the first label? */ + if (ch == '.') + break; + /* Is it an escaped character? */ + if (ch == '\\') { + ch = *++tname; + if (ch == '\0') + break; + } + } + + /* Make sure the label's length will fit in our length byte. */ + len = tname - name; + if (len > 255) { + errno = ENAMETOOLONG; + return (NULL); + } + + /* If nothing but unescaped dots after this, elide them. */ + while (ch == '.') + ch = *tname++; + + /* + * Make a new node since the comparison function needs it + * and we may yet end up adding it to our parent's tree. + * + * Note that by recursing for tnode->parent, we might be + * creating our parents and grandparents and so on. + */ + tnode = (struct node *)malloc(sizeof(struct node) - sizeof(void *) + + sizeof(u_char) + len + sizeof(char)); + tnode->parent = db_findname(tname); + tnode->children = NULL; + *((u_char *)tnode->name) = (u_char)len; + memcpy(tnode->name + sizeof(u_char), name, len); + tnode->name[sizeof(u_char) + len] = '\0'; + + /* If our first label isn't in our parent's tree, put it there. */ + node = tree_srch(&tnode->parent->children, nodeCompare, (tree_t)tnode); + if (node == NULL) + if (storeflag) + if (tree_add(&tnode->parent->children, nodeCompare, + (tree_t)tnode, NULL)) + node = tnode, tnode = NULL; + else + errno = ENOMEM; + else + errno = ENOENT; + + /* Get rid of tnode if we didn't consume it. */ + if (tnode != NULL) + free(tnode); + + /* Return the (possibly new) node, or NULL, as appropriate. */ + return (node); +} + +/* int + * db_getname(void *node, char *name, size_t size) + * given a node's unique, opaque address, format its name. + * returns: + * -1 = error occurred, check errno + * 0 = success + */ +int +db_getname(vnode, name, size) + const void *vnode; + char *name; + size_t size; +{ + const struct node *node = vnode; + + while (node != NULL) { + size_t len = (size_t)node->name[0]; + + if (size < len + 1) + goto too_long; + memcpy(name, node->name + sizeof(u_char), len); + name += len; + *name++ = '.'; + size -= len + sizeof(char); + node = node->parent; + } + + if (size < sizeof(char)) { + too_long: + errno = ENAMETOOLONG; + return (-1); + } + *name = '\0'; + return (0); +} + +/* + * char * + * db_makename(void *node) + * given a node's unique, opaque address, format and return its name. + * returns: + * pointer to the name or NULL on errors (check errno). + * notes: + * returns pointer to a static buffer, be careful how you call it. + */ +char * +db_makename(vnode) + void *vnode; +{ + static char name[MAXDNAME*2]; + + if (db_getname(vnode, name, sizeof name) < 0) + return (NULL); + return (name); +} diff --git a/contrib/bind/doc/notes/irp.txt b/contrib/bind/doc/notes/irp.txt new file mode 100644 index 0000000..f2b59e2 --- /dev/null +++ b/contrib/bind/doc/notes/irp.txt @@ -0,0 +1,521 @@ +IRP Commands + +This document describes version 1 of IRP. + +IRP is a text-based command/response protocol like NNTP or SMTP. + +1.0 Response types: textual and status. + +1.1 Textual responses + +Textual responses are sent after a status response which indicates the text +will follow. The text is a series of CR-LF terminated lines. On the last line a +single period ``.'' will appear. If a normal text line starts with a period +then this will be doubled before sending. + +There is no maximum line length for responses. Commands have a maximum line +length of 1024 characters. + +The lines that make up the transmitted data are divided into fields. The fields +are spearated by the colon character ``:'', except in one case (for host data) +where the at-sign ``@'' is used instead. Some fields, such as alias names for +hosts, can have multiple values, and these values are separated by commas. + +Most transmission of data requires no special character changes. The field +separators and subfield separators don't normally appear in the data. However +in one case they can (network names). So to avoid trouble, all ``special'' +characters found in any data fields are encoded in URL-encoding form. That is +they are replaced with the 3-character sequence ``%xx'', where xx is the +hexidecimal value of the ascii-code for the chatacter. i,e, ``:'' becomes +``%58'', ``,'' becomes ``%44'' and ``%'' becomes ``%37''. + +For version 1 of IRP the set of special characters for purposes of encoding, +is: + + `,', '%', ':', '@' + +In a couple cases (password structure and group structure), there may be +encrypted passwords as part of the data. If the client is a privileged user +that the server can verify (e.g. through the use of SunOS doors(2)), then the +encrypted password will be sent back to the client. If the client is not +privileged the password will be replaced with the string ``*''. + + +1.2 Status responses. + +Status responses follow a numbering pattern similar to NNTP. + + 1xx - Informative message + 2xx - Command ok + 3xx - Command ok so far, send the rest of it. + 4xx - Command was correct, but couldn't be performed for + some reason. + 5xx - Command unimplemented, or incorrect, or a serious + program error occurred. + + The next digit in the code indicates the function response category. + + x0x - Connection, setup, and miscellaneous messages + x1x - Host lookup + x2x - Network lookup + x3x - User lookup + x4x - Group lookup + x5x - Service lookup + x6x - Protocol lookup + x7x - Netgroup lookup + x8x - Misc. Information Lookup + x9x - Debugging output + + The final digit in the code indicates whether textual data follows + + xx0 - No textual data follows. + xx1 - Textual data follows. + +2.0 Connection Establishment + + When the client connects to the server, the server will issue a welcome + banner. If the server will accetp commands, then the banner will start with + a status code indicating this, followed by a version number of the protocol + it accepts. Other words may come on the line afterwards to indicate to + humans the state of the server, + + If the server wont accept commands then it will issue a banner indicating + that and will then drop the connection. + +2.1 Responses + + 200 1 Ready to go. ; note: The server handles version 1 of the protocol + 200 2 Ready ; note: The server handles version 2 of the protocol + 400 Sorry. Down to due to nightly backups. + +3.0 Commands + +3.1 The HOST commands + +3.1.1 GETHOSTBYNAME hostname +3.1.2 GETHOSTBYNAME2 hostname address-family +3.1.2 GETHOSTBYADDR address address-family +3.1.3 GETHOSTENT + + Returns a textual response containing the information for the given host(s) + (a struct hostent) encoded in an ascii format. gethostbyaddr and + gethostbyname look up a specific host. GETHOSTENT returns the contents + of the /etc/hosts file. The GETHOSTENT command is optional may not be + supported by the server. The address-family paramater is the value + "AF_INET" or "AF_INET6" + +{ XXX GETHOSTENT is optional as the gethostent(3) call isn't always available } + +3.1.4 Responses + + 210 No such host + 211 Host found + + If the hostname given as the command argument doesn't exist, then the 210 + response will be returned. If the host is successfully looked up, then the + 211 response is sent and a textual message is sent after. The textual + message contains the host information encoded in an ascii form. The fields + of the host data are separated by at-signs. Fields that have multiple values + (like the aliases field) have their sub values separated by commas. + + hostname@aliases@address-type@address-length@address-list@ + + - hostname is the FQDN of the host. + + - aliases is a comma separated list of FQDNs for the host aliases. + + - address-type is either the strings "AF_INET" or "AF_INET6" + + - address-length is the length of each address in bytes (after conversion + back to binary form). + + - address-list is a comma separated list of dotted IPv4 if IPv6 addresses. + +{ XXX if we're going to include TTLs where should they go? Perhaps the +address-list field should be "addr/ttl,addr/ttl,..." } + + For example: + + C: GETHOSTBYNAME gw.downtown.vix.com + + S: 210 No such host. + + C: GETHOSTBYNAME gw.home.vix.com + + S: 211 OK + gw.home.vix.com@ftp.vix.com,www.vix.com@AF_INET@4@192.5.5.1,192.5.5.1@ + . + + C: GETHOSTBYNAME2 gw.home.vix.com AF_INET6 + gw.home.vix.com@@AF_INET6@ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255@ + . + + C: GETHOSTBYADDR 192.5.5.1 + + S: 211 OK + gw.home.vix.com@ftp.vix.com,www.vix.com@AF_INET@4@192.5.5.1,192.5.5.1@ + . + + C: GETHOSTENT + + S: 211 OK + gw.home.vix.com@ftp.vix.com,www.vix.com@AF_INET@4@192.5.5.1,192.5.5.1@ + data.pa.vix.com@@AF_INET@4@204.152.184.37@ + . + + +3.2 The USER commands. + +3.2.1 GETPWNAM username +3.2.2 GETPWUID uid +3.2.3 GETPWENT + + Returns a textual response with the user information (a struct passwd) + enocoded in an ascii format. The optional GETPWENT command transmits the + entire /etc/password file + +{ XXX It's optional only cause it doesn't seem right to spit the password out +to whoever wants it, even with encrypted passwords not being sent } + +3.2.4 Reponses + + 230 No such user + 231 User found + + If the username or uid given as the command argument doesn't exist, then + the 230 response will be returned. If the user is successfully looked up, + then the 231 response is sent and a textual message is sent after. The + textual message contains the user information encoded in an ascii form. The + fields of the user data are separated by colons. The format is very similar + to the /etc/password format (see passwd(5)) + + username:password:uid:gid:class:change:expire:gecos:home_dir:shell: + + - username is the user's login name + + - password User's encrypted password (or the string "*" if the client is + unprivileged) + + - uid User's numeric id. + + - gid User's numeric login group id. + + - class User's general classification (a string) + + - change Password change time (integer seconds from epoch) + + - expire Account expiration time (integer seconds from epoch) + + - gecos General information about the user. + + - home_dir User's home directory. + + - shell User's login shell. + + For example. Client being a non-privileged user: + + C: GETPWNAM brister + + S: 231 User found + brister:*:1364:100:James Brister:/udir/brister:/bin/csh: + . + + C: GETPWUID 6 + games:*:7:13:Games Pseudo-user:/usr/games:nologin + . + + S: GETPWENT + root:*:0:0:System Administrator:/root:/bin/csh + postmast:*:4:4:Postmaster:/:/nologin + daemon:*:1:1:System Daemon:/:nologin + sys:*:2:2:Operating System:/tmp:nologin + bin:*:3:7:BSDI Software:/usr/bsdi:nologin + operator:*:5:5:System Operator:/usr/opr:/bin/csh + uucp:*:6:6:UNIX-to-UNIX Copy:/var/spool/uucppublic:/usr/libexec/uucico + . + + If a priviled user looks up a username: + + C: GETPWNAM www + + S: 231 User found + www:WZajcgFCaAd8s:51:84::0:0:WWW-server:/var/www:/bin/sh + . + +3.3 The NETWORK commands + +3.3.1 GETNETBYNAME network +3.3.2 GETNETBYADDR dotted-ip-address address-family +3.3.4 GETNETENT + + Returns a textual response with the network information (an IRS struct + nwent, *not* a struct netent) enocoded in an ascii format. The optionally + supported GETNETENT command transmits the entire /etc/networks file + +{ XXX should it be optional? } + +3.2.4 Reponses + + 220 No such network + 221 Netork found + + If the network given as the command argument doesn't exist, then the 220 + response will be returned. If the network is successfully looked up, then + the 221 response is sent and a textual message is sent after. The textual + message contains the network information encoded in an ascii form. The fields + of the network data are separated by colons. + + network-name:aliases:address-type:address-length:network-address: + + - network-name is the name of the network + + - aliases is a comma separated list of aliases for the network + + - address-type is ``AF_INET'' or ``AF_INET6''. + + - address-length is the number of bits the following network address uses. + + - address is the network address in a dotted ascii format. AF_INET address + are padded with 0 bits to the full 32 bits before conversion to ascii for + transmission. AF_INET6 addresses are padded to the full 128 bits with 0 + bits before conversion. + + For example: + + C: GETNETBYNAME vixie-net + + S: 221 Network found + vixie-net::AF_INET:24:192.5.5.0: + . + + C: GETNETBYADDR 10.0.0.1 + + S: 221 Network found + private-net:home-net,upstairs-net:AF_INET:8:10.0.0.0: + . + + C: GETNETENT + + S: 221 OK + vixie-net::AF_INET:24:192.5.5.0: + private-net:home-net,upstairs-net:AF_INET:8:10.0.0.0: + lookback-net::AF_INET:8:127.0.0.0 + . + +3.4 The GROUP commands + +3.4.1 GETGRNAM group +3.4.2 GETGRGID gid +3.4.3 GETGRENT + + Returns a textual response with the group information (a struct group) + enocoded in an ascii format. The optionally supported GETGRENT command + transmits the entire /etc/group file. + +3.4.4 Reponses + + 240 No such group + 241 Group found + + If the group given as the command argument doesn't exist, then the 240 + response will be returned. If the group is successfully looked up, then + the 241 response is sent and a textual message is sent after. The textual + message contains the group information encoded in an ascii form. The fields + of the group data are separated by colons. + + group-name:group-password:group-gid:group-members: + + - group-name is the name of the group. + + - group-password is the group's password. This will be correct if the + client has appropriate privileges (see discussion above on the USER + commands). Otherwise it will be the string ``*'' + + - group-gid is the numeric id for the group + + - group-members is a comma separated list of usernames for all the members + of the group. + + For example: + + C: GETGRNAM wheel + + S: 241 Group found + wheel:*:0:root,brister,nathalie,tester: + + C: GETGRGID 20 + + S: 241 Group found + staff:*:20:root,brister: + + C: GETGRENT + + S: 241 OK + wheel:*:0:root,brister,nathalie,tester: + daemon:*:1:daemon: + kmem:*:2:root: + sys:*:3:root: + tty:*:4:root: + operator:*:5:root: + uucp:*:6:brister: + bin:*:7:: + news:*:8:brister: + utmp:*:12:: + games:*:13:: + mail:*:14:: + staff:*:20:root,brister: + . + +3.5 The SERVICE commands + +3.5.1 GETSERVBYNAME name protocol +3.5.2 GETSERVBYPORT port protocol +3.5.3 GETSERVENT + + Returns a textual response with the service information (a struct servent) + enocoded in an ascii format. The optionally supported GETSERVENT command + transmits the entire /etc/services file. + +3.5.4 Reponses + + 250 No such service + 251 Group found + + If the group given as the command argument doesn't exist, then the 250 + response will be returned. If the service is successfully looked up, then + the 251 response is sent and a textual message is sent after. The textual + message contains the service information encoded in an ascii form. The fields + of the service data are separated by colons. + + service-name:aliases:port-number:protocol: + + - The service name is the offical name of the services. + + - aliases is a comma separated list of aliases for the service. + + - port-number is the decimal number of the port used for the service. + + - protocol is the name of the protocol the service operates under. Usually + either ``TCP'' or ``UCP'' + + For example: + + C: GETSERVBYNAME nntp tcp + + S: 251 Service found + nntp:readnews,untp:119:tcp: + . + + C: GETSERVBYPORT 514 udp + syslog::514:ucp: + . + + C: GETSERVENT + 251 OK + tcpmux::1:tcp: + echo::7:tcp: + echo::7:udp: + discard:sink,null:9:tcp: + discard:sink,null:9:udp: + systat:users:11:tcp: + systat:users:11:udp: + daytime::13:tcp: + daytime::13:udp: + netstat::15:tcp: + qotd:quote:17:tcp: + qotd:quote:17:udp: + . + +3.6 The PROTOCOL commands + +3.6.1 GETPROTOBYNAME protocol-name +3.6.2 GETPROTOBYNUMBER protocol-number +3.6.3 GETPROTOENT + + Returns a textual response with the protocol information (a struct protoent) + enocoded in an ascii format. The optionally supported GETPROTOENT command + transmits the entire /etc/protocols file. + +3.6.4 Reponses + + 260 No such protocol + 261 Protocol found + + If the protocol given as the command argument doesn't exist, then the 260 + response will be returned. If the service is successfully looked up, then + the 261 response is sent and a textual message is sent after. The textual + message contains the protocol information encoded in an ascii form. The fields + of the protocol data are separated by colons. + + protocol-name:aliases:protocol-number: + + - protocol-name is the offical name of the protocol + + - aliases is a comma separated list of aliases for the protocol + + - protocol-nunber is the number of the protocol in decimal. + + + For example: + + C: GETPROTOBYNAME ip + + S: 261 Protocol found + ip:IP:0: + . + + C: GETPROTOBYNUMBER 17 + + S: 261 Protocol found + udp:UDP:17: + . + + C: GETPROTOENT + + S: 261 OK + ip:IP:0: + icmp:ICMP:1: + igmp:IGMP:2: + ggp:GGP:3: + tcp:TCP:6: + egp:EGP:8: + pup:PUP:12: + udp:UDP:17: + hmp:HMP:20: + xns-idp:XNS-IDP:22: + rdp:RDP:27: + iso-tp4:ISO-TP4:29: + iso-ip:ISO-IP:80: + encap:ENCAP:98: + . + +3.7 The NETGROUP commands + +3.7.1 GETNETGRENT netgrouup + + Returns a textual response with the netgroup information enocoded in an + ascii format. + +3.6.4 Reponses + + 270 No such netgroup + 271 Netgroups found + + For the given netgroup a list of the netgroup entries will be + returned. Each netgroup entry is three fields separated by colons. A field + may be empty to indicate wildcarding. + + :hostname:username:domainname: + + For example: + + C: GETNETGRENT devlopers + + S: 271 OK + :gw.home.vix.com:brister:vix.com: + :bb.rc.vix.com:vixie:: + . + + + + diff --git a/contrib/bind/include/Makefile b/contrib/bind/include/Makefile index d0a13a8..168c0d2 100644 --- a/contrib/bind/include/Makefile +++ b/contrib/bind/include/Makefile @@ -1,4 +1,4 @@ -# Copyright (c) 1996 by Internet Software Consortium +# 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 @@ -14,14 +14,15 @@ # SOFTWARE. SUBDIRS = arpa isc -HFILES = netdb.h resolv.h irs.h hesiod.h +HFILES = netdb.h resolv.h res_update.h irs.h irp.h hesiod.h DESTDIR= DESTINC= /usr/local/bind/include INSTALL= install +INSTALL_INC= MARGS= DESTDIR="${DESTDIR}" DESTINC="${DESTINC}" INSTALL="${INSTALL}" \ - MAKE="${MAKE}" + MAKE="${MAKE}" INSTALL_INC=${INSTALL_INC} all depend clean distclean install:: @for x in ${SUBDIRS}; do \ @@ -35,7 +36,7 @@ clean:: FRC install:: ${DESTDIR}${DESTINC} @set -x; for x in ${HFILES}; do \ - ${INSTALL} -c -m 444 $$x ${DESTDIR}${DESTINC}/$$x; \ + ${INSTALL} -c ${INSTALL_INC} -m 444 $$x ${DESTDIR}${DESTINC}/$$x; \ done ${DESTDIR}${DESTINC}: diff --git a/contrib/bind/include/arpa/Makefile b/contrib/bind/include/arpa/Makefile index 279c569..1aa6bd6 100644 --- a/contrib/bind/include/arpa/Makefile +++ b/contrib/bind/include/arpa/Makefile @@ -1,4 +1,4 @@ -# Copyright (c) 1996 by Internet Software Consortium +# 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 @@ -27,7 +27,7 @@ clean: FRC install: ${DESTDIR}${DESTINC}/arpa set -x; for x in ${HFILES}; do \ - ${INSTALL} -c -m 444 $$x ${DESTDIR}${DESTINC}/arpa/$$x; \ + ${INSTALL} -c ${INSTALL_INC} -m 444 $$x ${DESTDIR}${DESTINC}/arpa/$$x; \ done ${DESTDIR}${DESTINC}/arpa: diff --git a/contrib/bind/include/arpa/inet.h b/contrib/bind/include/arpa/inet.h index 6065980..58a6f9a 100644 --- a/contrib/bind/include/arpa/inet.h +++ b/contrib/bind/include/arpa/inet.h @@ -55,7 +55,7 @@ /* * @(#)inet.h 8.1 (Berkeley) 6/2/93 - * $Id: inet.h,v 8.5 1997/01/29 08:48:09 vixie Exp $ + * $Id: inet.h,v 8.8 1999/05/14 18:16:54 vixie Exp $ */ #ifndef _INET_H_ @@ -80,6 +80,8 @@ #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 @@ -96,7 +98,9 @@ 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_ntoa __P((struct in_addr)); +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)); diff --git a/contrib/bind/include/arpa/nameser.h b/contrib/bind/include/arpa/nameser.h index 8d0faf5..c61f8b7 100644 --- a/contrib/bind/include/arpa/nameser.h +++ b/contrib/bind/include/arpa/nameser.h @@ -32,7 +32,7 @@ */ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -49,7 +49,7 @@ */ /* - * $Id: nameser.h,v 8.16 1998/02/06 00:35:58 halley Exp $ + * $Id: nameser.h,v 8.36 1999/10/15 19:49:08 vixie Exp $ */ #ifndef _ARPA_NAMESER_H_ @@ -66,15 +66,14 @@ #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 libnameser.a - * is new enough to contain a certain feature. + * 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. */ -/* XXXRTH I made this bigger than __BIND in 4.9.5 T6B */ -#define __NAMESER 19961001 /* New interface version stamp. */ +#define __NAMESER 19991006 /* New interface version stamp. */ /* * Define constants based on RFC 883, RFC 1034, RFC 1035 @@ -142,18 +141,18 @@ extern struct _ns_flagdata _ns_flagdata[]; * This is a parsed record. It is caller allocated and has no dynamic data. */ typedef struct __ns_rr { - char name[NS_MAXDNAME]; /* XXX need to malloc */ + char name[NS_MAXDNAME]; u_int16_t type; - u_int16_t class; + u_int16_t rr_class; u_int32_t ttl; u_int16_t rdlength; - const u_char *rdata; + 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) ((rr).type + 0) -#define ns_rr_class(rr) ((rr).class + 0) +#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) @@ -206,7 +205,11 @@ typedef enum __ns_rcode { 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 + 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 */ @@ -217,31 +220,40 @@ typedef enum __ns_update_operation { } ns_update_operation; /* - * This RR-like structure is particular to UPDATE. + * This structure is used for TSIG authenticated messages */ -struct ns_updrec { - struct ns_updrec *r_prev; /* prev record */ - struct ns_updrec *r_next; /* next record */ - u_int8_t r_section; /* ZONE/PREREQUISITE/UPDATE */ - char * r_dname; /* owner of the RR */ - u_int16_t r_class; /* class number */ - u_int16_t r_type; /* type number */ - u_int32_t r_ttl; /* time to live */ - u_char * r_data; /* rdata fields as text string */ - u_int16_t r_size; /* size of r_data field */ - int r_opcode; /* type of operation */ - /* following fields for private use by the resolver/server routines */ - struct ns_updrec *r_grpnext; /* next record when grouped */ - struct databuf *r_dp; /* databuf to process */ - struct databuf *r_deldp; /* databuf's deleted/overwritten */ - u_int16_t r_zone; /* zone number on server */ +struct ns_tsig_key { + char name[NS_MAXDNAME], alg[NS_MAXDNAME]; + unsigned char *data; + int len; }; -typedef struct ns_updrec ns_updrec; +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. */ @@ -277,21 +289,40 @@ typedef enum __ns_type { ns_t_srv = 33, /* Server Selection. */ ns_t_atma = 34, /* ATM Address */ ns_t_naptr = 35, /* Naming Authority PoinTeR */ - /* Query type values which do not appear in resource records. */ + ns_t_kx = 36, /* Key Exchange */ + ns_t_cert = 37, /* Certification record */ + ns_t_a6 = 38, /* IPv6 address (deprecates AAAA) */ + ns_t_dname = 39, /* Non-terminal DNAME (for IPv6) */ + ns_t_sink = 40, /* Kitchen sink (experimentatl) */ + ns_t_opt = 41, /* EDNS0 option (meta-RR) */ + ns_t_tsig = 250, /* Transaction signature. */ ns_t_ixfr = 251, /* Incremental zone transfer. */ ns_t_axfr = 252, /* Transfer zone of authority. */ ns_t_mailb = 253, /* Transfer mailbox records. */ ns_t_maila = 254, /* Transfer mail agent records. */ ns_t_any = 255, /* Wildcard match. */ + ns_t_zxfr = 256, /* BIND-specific, nonstandard. */ ns_t_max = 65536 } ns_type; +/* Exclusively a QTYPE? (not also an RTYPE) */ +#define ns_t_qt_p(t) (ns_t_xfr_p(t) || (t) == ns_t_any || \ + (t) == ns_t_mailb || (t) == ns_t_maila) +/* Some kind of meta-RR? (not a QTYPE, but also not an RTYPE) */ +#define ns_t_mrr_p(t) ((t) == ns_t_tsig || (t) == ns_t_opt) +/* Exclusively an RTYPE? (not also a QTYPE or a meta-RR) */ +#define ns_t_rr_p(t) (!ns_t_qt_p(t) && !ns_t_mrr_p(t)) +#define ns_t_udp_p(t) ((t) != ns_t_axfr && (t) != ns_t_zxfr) +#define ns_t_xfr_p(t) ((t) == ns_t_axfr || (t) == ns_t_ixfr || \ + (t) == ns_t_zxfr) + /* * Values for class field */ typedef enum __ns_class { + ns_c_invalid = 0, /* Cookie. */ ns_c_in = 1, /* Internet. */ - /* Class 2 unallocated/unsupported. */ + 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 */ @@ -300,9 +331,24 @@ typedef enum __ns_class { ns_c_max = 65536 } ns_class; -/* - * Flags field of the KEY RR rdata - */ +/* 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 */ @@ -311,28 +357,45 @@ typedef enum __ns_class { /* 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_EXPERIMENTAL 0x2000 /* Security is *mandatory* if bit=0 */ -#define NS_KEY_RESERVED3 0x1000 /* reserved - must be zero */ +#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_USERACCOUNT 0x0400 /* key is assoc. with a user acct */ -#define NS_KEY_ENTITY 0x0200 /* key is assoc. with entity eg host */ -#define NS_KEY_ZONEKEY 0x0100 /* key is zone key */ -#define NS_KEY_IPSEC 0x0080 /* key is for IPSEC (host or user)*/ -#define NS_KEY_EMAIL 0x0040 /* key is for email (MIME security) */ +#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_RESERVED3 | \ +#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 @@ -340,6 +403,12 @@ typedef enum __ns_class { #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 */ @@ -356,20 +425,20 @@ typedef enum __ns_class { #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) { \ +#define NS_GET16(s, cp) do { \ register u_char *t_cp = (u_char *)(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) { \ +#define NS_GET32(l, cp) do { \ register u_char *t_cp = (u_char *)(cp); \ (l) = ((u_int32_t)t_cp[0] << 24) \ | ((u_int32_t)t_cp[1] << 16) \ @@ -377,17 +446,17 @@ typedef enum __ns_class { | ((u_int32_t)t_cp[3]) \ ; \ (cp) += NS_INT32SZ; \ -} +} while (0) -#define NS_PUT16(s, cp) { \ +#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) { \ +#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; \ @@ -395,27 +464,42 @@ typedef enum __ns_class { *t_cp++ = t_l >> 8; \ *t_cp = t_l; \ (cp) += NS_INT32SZ; \ -} +} while (0) /* - * ANSI C identifier hiding. + * ANSI C identifier hiding for bind's lib/nameser. */ #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_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 u_int ns_get16 __P((const u_char *)); @@ -423,6 +507,7 @@ 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)); @@ -432,6 +517,8 @@ int ns_sprintrrf __P((const u_char *, size_t, 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 *, @@ -443,6 +530,23 @@ int ns_name_uncompress __P((const u_char *, const u_char *, 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 *)); +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 diff --git a/contrib/bind/include/arpa/nameser_compat.h b/contrib/bind/include/arpa/nameser_compat.h index 82b4c4d..292669d 100644 --- a/contrib/bind/include/arpa/nameser_compat.h +++ b/contrib/bind/include/arpa/nameser_compat.h @@ -32,7 +32,7 @@ /* * from nameser.h 8.1 (Berkeley) 6/2/93 - * $Id: nameser_compat.h,v 8.9 1998/03/20 23:25:10 halley Exp $ + * $Id: nameser_compat.h,v 8.11 1999/01/02 08:00:58 vixie Exp $ */ #ifndef _ARPA_NAMESER_COMPAT_ @@ -164,6 +164,10 @@ typedef struct { #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 @@ -203,6 +207,7 @@ typedef struct { #define T_SRV ns_t_srv #define T_ATMA ns_t_atma #define T_NAPTR ns_t_naptr +#define T_TSIG ns_t_tsig #define T_IXFR ns_t_ixfr #define T_AXFR ns_t_axfr #define T_MAILB ns_t_mailb diff --git a/contrib/bind/include/hesiod.h b/contrib/bind/include/hesiod.h index b0a3e45..a110bd0 100644 --- a/contrib/bind/include/hesiod.h +++ b/contrib/bind/include/hesiod.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -20,7 +20,7 @@ */ /* - * $Id: hesiod.h,v 1.5 1996/12/04 09:39:00 vixie Exp $ + * $Id: hesiod.h,v 1.7 1999/01/08 19:22:45 vixie Exp $ */ #ifndef _HESIOD_H_INCLUDED @@ -33,5 +33,8 @@ char * hesiod_to_bind __P((void *context, const char *name, 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/contrib/bind/include/irp.h b/contrib/bind/include/irp.h new file mode 100644 index 0000000..2402383 --- /dev/null +++ b/contrib/bind/include/irp.h @@ -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 8.1 1999/01/18 07:46:46 vixie 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/contrib/bind/include/irs.h b/contrib/bind/include/irs.h index 0606e01..17d3f20 100644 --- a/contrib/bind/include/irs.h +++ b/contrib/bind/include/irs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ /* - * $Id: irs.h,v 8.1 1997/12/04 04:55:19 halley Exp $ + * $Id: irs.h,v 8.4 1999/01/18 07:46:46 vixie Exp $ */ #ifndef _IRS_H_INCLUDED @@ -24,8 +24,11 @@ #include <sys/types.h> -#include <netdb.h> +#include <arpa/nameser.h> + #include <grp.h> +#include <netdb.h> +#include <resolv.h> #include <pwd.h> /* @@ -41,6 +44,9 @@ struct irs_gr { 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 *))); }; /* @@ -54,6 +60,9 @@ struct irs_pw { 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 *))); }; /* @@ -68,6 +77,9 @@ struct irs_sv { 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 *))); }; /* @@ -81,6 +93,9 @@ struct irs_pr { 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 *))); }; /* @@ -96,6 +111,9 @@ struct irs_ho { 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 *))); }; /* @@ -109,6 +127,9 @@ struct irs_nw { 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 *))); }; /* @@ -148,6 +169,9 @@ 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 *))); }; /* @@ -171,13 +195,125 @@ struct nwent { #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)); +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)); + +/* + * 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 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((char **host, char **user, + 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/contrib/bind/include/isc/Makefile b/contrib/bind/include/isc/Makefile index 4e8fc8c..b0184fc 100644 --- a/contrib/bind/include/isc/Makefile +++ b/contrib/bind/include/isc/Makefile @@ -1,4 +1,4 @@ -# Copyright (c) 1996 by Internet Software Consortium +# 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 @@ -14,7 +14,7 @@ # SOFTWARE. HFILES = eventlib.h misc.h tree.h logging.h heap.h memcluster.h \ - assertions.h list.h + assertions.h list.h dst.h irpmarshall.h DESTDIR = DESTINC = /usr/local/bind/include @@ -28,7 +28,7 @@ clean: FRC install: ${DESTDIR}${DESTINC}/isc set -x; for x in ${HFILES}; do \ - ${INSTALL} -c -m 444 $$x ${DESTDIR}${DESTINC}/isc/$$x; \ + ${INSTALL} -c ${INSTALL_INC} -m 444 $$x ${DESTDIR}${DESTINC}/isc/$$x; \ done ${DESTDIR}${DESTINC}/isc: diff --git a/contrib/bind/include/isc/assertions.h b/contrib/bind/include/isc/assertions.h index 95a9556..44089d1 100644 --- a/contrib/bind/include/isc/assertions.h +++ b/contrib/bind/include/isc/assertions.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ /* - * $Id: assertions.h,v 8.1 1997/12/03 22:34:50 halley Exp $ + * $Id: assertions.h,v 8.2 1999/01/08 19:23:01 vixie Exp $ */ #ifndef ASSERTIONS_H diff --git a/contrib/bind/include/isc/ctl.h b/contrib/bind/include/isc/ctl.h new file mode 100644 index 0000000..3c6e565 --- /dev/null +++ b/contrib/bind/include/isc/ctl.h @@ -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 8.9 1999/08/08 20:16:45 vixie 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, 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, 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/contrib/bind/include/isc/dst.h b/contrib/bind/include/isc/dst.h new file mode 100644 index 0000000..9e68a10 --- /dev/null +++ b/contrib/bind/include/isc/dst.h @@ -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/contrib/bind/include/isc/eventlib.h b/contrib/bind/include/isc/eventlib.h index 98a0f46..6b9b077 100644 --- a/contrib/bind/include/isc/eventlib.h +++ b/contrib/bind/include/isc/eventlib.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 1996, 1997, 1998 by Internet Software Consortium + * 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 @@ -18,7 +18,7 @@ /* eventlib.h - exported interfaces for eventlib * vix 09sep95 [initial] * - * $Id: eventlib.h,v 1.19 1998/02/06 01:55:51 halley Exp $ + * $Id: eventlib.h,v 1.22 1999/08/18 22:09:04 vixie Exp $ */ #ifndef _EVENTLIB_H @@ -47,6 +47,9 @@ 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)); @@ -82,6 +85,7 @@ typedef struct { unsigned char mask[256/8]; } evByteMask; #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)); @@ -90,6 +94,7 @@ 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 diff --git a/contrib/bind/include/isc/heap.h b/contrib/bind/include/isc/heap.h index 5df73e8..45c867c 100644 --- a/contrib/bind/include/isc/heap.h +++ b/contrib/bind/include/isc/heap.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 by Internet Software Consortium. + * 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 diff --git a/contrib/bind/include/isc/irpmarshall.h b/contrib/bind/include/isc/irpmarshall.h new file mode 100644 index 0000000..d8afe32 --- /dev/null +++ b/contrib/bind/include/isc/irpmarshall.h @@ -0,0 +1,115 @@ +/* + * 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 8.1 1999/01/18 07:46:47 vixie 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(char **host, char **user, 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/contrib/bind/include/isc/list.h b/contrib/bind/include/isc/list.h index b78ba4f..febfbf8 100644 --- a/contrib/bind/include/isc/list.h +++ b/contrib/bind/include/isc/list.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 by Internet Software Consortium. + * 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 @@ -66,6 +66,7 @@ (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) diff --git a/contrib/bind/include/isc/logging.h b/contrib/bind/include/isc/logging.h index 5b11906..720e2a31 100644 --- a/contrib/bind/include/isc/logging.h +++ b/contrib/bind/include/isc/logging.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1997, 1998 by Internet Software Consortium. + * 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 diff --git a/contrib/bind/include/isc/memcluster.h b/contrib/bind/include/isc/memcluster.h index e5f0c75..b6f4191 100644 --- a/contrib/bind/include/isc/memcluster.h +++ b/contrib/bind/include/isc/memcluster.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 by Internet Software Consortium. + * 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 @@ -24,10 +24,15 @@ #ifdef MEMCLUSTER_DEBUG #define memget(s) __memget_debug(s, __FILE__, __LINE__) #define memput(p, s) __memput_debug(p, s, __FILE__, __LINE__) -#else +#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 +#endif /*MEMCLUSTER_RECORD*/ +#endif /*MEMCLUSTER_DEBUG*/ #define memstats __memstats int meminit(size_t, size_t); @@ -35,6 +40,8 @@ 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/contrib/bind/include/isc/misc.h b/contrib/bind/include/isc/misc.h index 09b593f..d13e1d3 100644 --- a/contrib/bind/include/isc/misc.h +++ b/contrib/bind/include/isc/misc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 1996 by Internet Software Consortium + * 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 @@ -16,7 +16,7 @@ */ /* - * $Id: misc.h,v 8.1 1996/11/12 03:19:13 vixie Exp $ + * $Id: misc.h,v 8.2 1999/01/08 19:23:10 vixie Exp $ */ #ifndef _ISC_MISC_H diff --git a/contrib/bind/include/netdb.h b/contrib/bind/include/netdb.h index 7527cc9..4ffefad 100644 --- a/contrib/bind/include/netdb.h +++ b/contrib/bind/include/netdb.h @@ -50,12 +50,43 @@ * 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 8.9 1996/11/19 08:39:29 vixie Exp $ + * $Id: netdb.h,v 8.15 1999/09/18 06:23:46 vixie Exp $ */ #ifndef _NETDB_H_ @@ -66,16 +97,33 @@ # include <sys/bitypes.h> #endif #include <sys/cdefs.h> +#include <netinet/in.h> +#include <stdio.h> #ifndef _PATH_HEQUIV -# define _PATH_HEQUIV "/etc/hosts.equiv" +#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 @@ -115,6 +163,17 @@ struct protoent { 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). @@ -128,6 +187,148 @@ struct protoent { #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 + + +#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)); @@ -153,6 +354,107 @@ void sethostent __P((int)); 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 *)); +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 +#endif +#if 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. */ diff --git a/contrib/bind/include/res_update.h b/contrib/bind/include/res_update.h new file mode 100644 index 0000000..cbbf9b8 --- /dev/null +++ b/contrib/bind/include/res_update.h @@ -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 8.1 1999/10/07 08:24:13 vixie 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/contrib/bind/include/resolv.h b/contrib/bind/include/resolv.h index 3bfd6bb..3065313 100644 --- a/contrib/bind/include/resolv.h +++ b/contrib/bind/include/resolv.h @@ -32,7 +32,7 @@ */ /* - * Portions Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -50,7 +50,7 @@ /* * @(#)resolv.h 8.1 (Berkeley) 6/2/93 - * $Id: resolv.h,v 8.12 1998/04/28 19:36:46 halley Exp $ + * $Id: resolv.h,v 8.29 1999/10/07 08:24:14 vixie Exp $ */ #ifndef _RESOLV_H_ @@ -73,16 +73,30 @@ * is new enough to contain a certain feature. */ -#define __RES 19960801 +#define __RES 19991006 /* - * This used to be defined in res_query.c, now it's in herror.c. It was - * never extern'd by any *.h file before it was placed here. herror.c is - * part of libresolv.a even though it might make more sense in libnetdb.a - * or even libnet.a. + * 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 */ -extern int h_errno; +#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. @@ -94,6 +108,29 @@ extern int h_errno; #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_in * 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_in *ns, + const u_char *query, + int querylen, + u_char *ans, + int anssiz, + int *resplen)); + +struct res_sym { + int number; /* Identifying number, like T_MX */ + char * name; /* Its symbolic name, like "MX" */ + char * humanname; /* Its fun name, like "mail exchanger" */ +}; + /* * Global defines and variables for resolver stub. */ @@ -105,6 +142,9 @@ extern int h_errno; #define RES_TIMEOUT 5 /* min. seconds between retries */ #define MAXRESOLVSORT 10 /* number of net to sort on */ #define RES_MAXNDOTS 15 /* should reflect bit field size */ +#define RES_MAXRETRANS 30 /* only for resolv.conf/RES_OPTIONS */ +#define RES_MAXRETRY 5 /* only for resolv.conf/RES_OPTIONS */ +#define RES_DFLRETRY 2 /* Default #/tries. */ struct __res_state { int retrans; /* retransmition time interval */ @@ -125,9 +165,25 @@ struct __res_state { struct in_addr addr; u_int32_t mask; } sort_list[MAXRESOLVSORT]; - char pad[72]; /* On an i386 this means 512b total. */ + res_send_qhook qhook; /* query hook */ + res_send_rhook rhook; /* response hook */ + int res_h_errno; /* last one set for this context */ + int _sock; /* PRIVATE: for res_send i/o */ + u_int _flags; /* PRIVATE: see below */ + char pad[52]; /* On an i386 this means 512b total. */ }; +typedef struct __res_state *res_state; + +/* + * Resolver flags (used to be discrete per-module statics ints). + */ +#define RES_F_VC 0x00000001 /* socket is TCP */ +#define RES_F_CONN 0x00000002 /* socket is connected */ + +/* res_findzonecut() options */ +#define RES_EXHAUSTIVE 0x00000001 /* always do all queries */ + /* * Resolver options (keep these in synch with res_debug.c, please) */ @@ -145,6 +201,9 @@ struct __res_state { #define RES_INSECURE2 0x00000800 /* type 2 security disabled */ #define RES_NOALIASES 0x00001000 /* shuts off HOSTALIASES feature */ #define RES_USE_INET6 0x00002000 /* use/map IPv6 in gethostbyname() */ +#define RES_ROTATE 0x00004000 /* rotate ns list after each query */ +#define RES_NOCHECKNAME 0x00008000 /* do not check names for sanity. */ +#define RES_KEEPTSIG 0x00010000 /* do not strip TSIG records */ #define RES_DEFAULT (RES_RECURSE | RES_DEFNAMES | RES_DNSRCH) @@ -168,81 +227,110 @@ struct __res_state { #define RES_PRF_INIT 0x00004000 /* 0x00008000 */ -typedef enum { res_goahead, res_nextns, res_modified, res_done, res_error } - res_sendhookact; - -typedef res_sendhookact (*res_send_qhook)__P((struct sockaddr_in * const *ns, - const u_char **query, - int *querylen, - u_char *ans, - int anssiz, - int *resplen)); +/* 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 -typedef res_sendhookact (*res_send_rhook)__P((const struct sockaddr_in *ns, - const u_char *query, - int querylen, - u_char *ans, - int anssiz, - int *resplen)); +#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 -struct res_sym { - int number; /* Identifying number, like T_MX */ - char * name; /* Its symbolic name, like "MX" */ - char * humanname; /* Its fun name, like "mail exchanger" */ -}; +__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 -extern struct __res_state _res; +#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 res_hnok __res_hnok -#define res_ownok __res_ownok -#define res_mailok __res_mailok -#define res_dnok __res_dnok -#define sym_ston __sym_ston -#define sym_ntos __sym_ntos -#define sym_ntop __sym_ntop #define b64_ntop __b64_ntop -#define b64_pton __b64_pton -#define loc_ntoa __loc_ntoa +#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 fp_resstat __fp_resstat -#define p_query __p_query -#define dn_skipname __dn_skipname -#define fp_resstat __fp_resstat -#define fp_query __fp_query -#define fp_nquery __fp_nquery -#define hostalias __hostalias -#define putlong __putlong -#define putshort __putshort +#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_query __p_query -#define p_cdnname __p_cdnname -#define p_section __p_section -#define p_cdname __p_cdname -#define p_fqnname __p_fqnname -#define p_fqname __p_fqname -#define p_option __p_option -#define p_secstodate __p_secstodate -#define dn_count_labels __dn_count_labels -#define dn_comp __dn_comp -#define dn_expand __dn_expand -#define res_init __res_init -#define res_randomid __res_randomid -#define res_query __res_query -#define res_search __res_search -#define res_querydomain __res_querydomain -#define res_mkquery __res_mkquery -#define res_send __res_send -#define res_isourserver __res_isourserver -#define res_nameinquery __res_nameinquery -#define res_queriesmatch __res_queriesmatch -#define res_close __res_close -#define res_mkupdate __res_mkupdate -#define res_mkupdrec __res_mkupdrec -#define res_freeupdrec __res_freeupdrec +#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_npquery __res_npquery +#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 __BEGIN_DECLS int res_hnok __P((const char *)); int res_ownok __P((const char *)); @@ -256,16 +344,12 @@ 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 fp_resstat __P((struct __res_state *, FILE *)); -void fp_query __P((const u_char *, FILE *)); -void fp_nquery __P((const u_char *, int, FILE *)); -const char * hostalias __P((const char *)); void putlong __P((u_int32_t, u_char *)); void putshort __P((u_int16_t, u_char *)); const char * p_class __P((int)); const char * p_time __P((u_int32_t)); const char * p_type __P((int)); -void p_query __P((const u_char *)); +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, @@ -278,26 +362,36 @@ 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)); -int res_init __P((void)); u_int res_randomid __P((void)); -int res_query __P((const char *, int, int, u_char *, int)); -int res_search __P((const char *, int, int, u_char *, int)); -int res_querydomain __P((const char *, const char *, int, int, - u_char *, int)); -int res_mkquery __P((int, const char *, int, int, const u_char *, - int, const u_char *, u_char *, int)); -int res_send __P((const u_char *, int, u_char *, int)); -int res_isourserver __P((const struct sockaddr_in *)); 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 *)); -void res_close __P((void)); const char * p_section __P((int section, int opcode)); -int res_update __P((ns_updrec *)); -int res_mkupdate __P((ns_updrec *, u_char *, int)); -ns_updrec * res_mkupdrec __P((int, const char *, u_int, u_int, u_long)); -void res_freeupdrec __P((ns_updrec *)); +/* 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_npquery __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)); __END_DECLS #endif /* !_RESOLV_H_ */ diff --git a/contrib/bind/lib/Makefile b/contrib/bind/lib/Makefile index 5029f2f..18fa7c8 100644 --- a/contrib/bind/lib/Makefile +++ b/contrib/bind/lib/Makefile @@ -1,4 +1,4 @@ -# Copyright (c) 1996 by Internet Software Consortium +# 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 @@ -13,9 +13,9 @@ # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS # SOFTWARE. -# $Id: Makefile,v 8.10 1997/09/26 17:56:00 halley Exp $ +# $Id: Makefile,v 8.22 1999/06/08 01:42:57 vixie Exp $ -SUBDIRS = resolv irs isc bsd inet nameser +SUBDIRS = resolv irs isc bsd inet nameser dst # these are only appropriate for BSD 4.4 or derivatives, and are used in # development. normal builds will be done in the top level directory and @@ -31,51 +31,70 @@ TOP= .. INCL= ${TOP}/include PORTINCL= ${TOP}/port/${SYSTYPE}/include LIBBIND= ${TOP}/lib/libbind.${A} +LIBBINDR= ${TOP}/lib/libbind_r.${A} LIBPORT= ${TOP}/port/libport.${A} RANLIB= ranlib -AR= ar cruv +AR= ar cru INSTALL= install CDEBUG= -g +REENTRANT=-D_REENTRANT +INSTALL_EXEC= +INSTALL_LIB=-o bin -g bin # Warning: this MARGS has RANLIB=: to prevent submakes from running ranlib MARGS = "SYSTYPE=${SYSTYPE}" "SHELL=${SHELL}" "A=${A}" "O=${O}" \ "CC=${CC}" "LEX=${LEX}" "YACC=${YACC}" "CDEBUG=${CDEBUG}" \ "SYSLIBS=${SYSLIBS}" "LDFLAGS=${LDFLAGS}" \ - "DESTDIR=${DESTDIR}" "PIDDIR=${PIDDIR}" "DESTMAN=${DESTMAN}" \ + "DESTDIR=${DESTDIR}" "DESTMAN=${DESTMAN}" \ "DESTBIN=${DESTBIN}" "DESTSBIN=${DESTSBIN}" "DESTEXEC=${DESTEXEC}" \ "DESTLIB=${DESTLIB}" "DESTINC=${DESTINC}" "DESTHELP=${DESTHELP}" \ "RANLIB=:" "AR=${AR}" "ARPREF=${ARPREF}" "ARSUFF=${ARSUFF}" \ - "INCL=../${INCL}" "PORTINCL=../${PORTINCL}" \ + "INCL=../${INCL}" "PORTINCL=../${PORTINCL}" "EXE=${EXE}" \ "LIBBIND=../${LIBBIND}" "LIBPORT=../${LIBPORT}" \ - "INSTALL=${INSTALL}" "CPPFLAGS=${CPPFLAGS}" "TOP=../${TOP}" + "INSTALL=${INSTALL}" "CPPFLAGS=${CPPFLAGS}" "TOP=../${TOP}" \ + "REENTRANT=${REENTRANT}" "INSTALL_LIB=${INSTALL_LIB}" \ + "INSTALL_EXEC=${INSTALL_EXEC}" "BOUNDS=${BOUNDS}" LIB = libbind.${A} LIBTS = ${TOP}/lib/libbind.ts +LIBR = libbind_r.${A} +LIBRTS = ${TOP}/lib/libbindr.ts all depend clean install distclean:: @for x in ${SUBDIRS}; do \ (cd $$x; pwd; ${MAKE} ${MARGS} $@); \ done -all:: ${LIBTS} +all:: ${LIBTS} ${LIBRTS} + +${LIBRTS}: ${LIBBINDR} + ${RANLIB} ${LIBBINDR} + sleep 1 && touch ${LIBRTS} ${LIBTS}: ${LIBBIND} ${RANLIB} ${LIBBIND} - touch ${LIBTS} + sleep 1 && touch ${LIBTS} distclean:: clean clean:: FRC rm -f *~ *.BAK *.CKP *.orig rm -f ${LIBBIND} ${LIBTS} + rm -f ${LIBBINDR} ${LIBRTS} install:: ${DESTDIR}${DESTLIB} ${DESTDIR}${DESTLIB}/${LIB} +install:: ${DESTDIR}${DESTLIB} ${DESTDIR}${DESTLIB}/${LIBR} ${DESTDIR}${DESTLIB}: mkdir -p ${DESTDIR}${DESTLIB} +${DESTDIR}${DESTLIB}/${LIBR}: ${LIBBINDR} + ${INSTALL} -c ${INSTALL_LIB} -m 644 ${LIBBINDR} \ + ${DESTDIR}${DESTLIB}/${LIBR} + ( cd ${DESTDIR}${DESTLIB} ; ${RANLIB} ${LIBR} ) + ${DESTDIR}${DESTLIB}/${LIB}: ${LIBBIND} - ${INSTALL} -c -o bin -g bin -m 644 ${LIBBIND} \ + ${INSTALL} -c ${INSTALL_LIB} -m 644 ${LIBBIND} \ ${DESTDIR}${DESTLIB}/${LIB} ( cd ${DESTDIR}${DESTLIB} ; ${RANLIB} ${LIB} ) diff --git a/contrib/bind/lib/dst/Makefile b/contrib/bind/lib/dst/Makefile new file mode 100644 index 0000000..f99813c --- /dev/null +++ b/contrib/bind/lib/dst/Makefile @@ -0,0 +1,96 @@ +# 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: Makefile,v 1.13 1999/03/07 09:33:47 vixie Exp $ + +# these are only appropriate for BSD 4.4 or derivatives, and are used in +# development. normal builds will be done in the top level directory and +# this Makefile will be invoked with a lot of overrides for the following: +SYSTYPE= bsdos +DESTDIR = +DESTLIB = /usr/local/lib +O=o +A=a +CC= cc +LD= ld +SHELL= /bin/sh +CDEBUG= -g +TOP= ../.. +INCL = ${TOP}/include +PORTINCL = ${TOP}/port/${SYSTYPE}/include +LIBBIND = ${TOP}/lib/libbind.${A} +LIBBINDR = ../${TOP}/lib/libbind_r.${A} +CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL} +LD_LIBFLAGS= -x -r +AR= ar cru +RANLIB= ranlib +INSTALL= install +INSTALL_EXEC= +INSTALL_LIB=-o bin -g bin +THREADED= threaded + +HDRS= md5.h md5_locl.h + +SRCS= dst_api.c prandom.c rsaref_link.c support.c bsafe_link.c \ + cylink_link.c hmac_link.c md5_dgst.c eay_dss_link.c + +OBJS= dst_api.${O} prandom.${O} rsaref_link.${O} support.${O} \ + bsafe_link.${O} cylink_link.${O} hmac_link.${O} md5_dgst.${O} \ + eay_dss_link.${O} + +CRYPTINCL= +CRYPTFLAGS= -DHMAC_MD5 -DUSE_MD5 + +all: ${LIBBIND} + +${LIBBIND}: ${OBJS} + ( cd ${THREADED} ; \ + ${AR} ${LIBBINDR} ${ARPREF} ${OBJS} ${ARSUFF} ; \ + ${RANLIB} ${LIBBINDR} ) + ${AR} ${LIBBIND} ${ARPREF} ${OBJS} ${ARSUFF} + ${RANLIB} ${LIBBIND} + +.c.${O}: + if test ! -d ${THREADED} ; then mkdir ${THREADED} ; fi + ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} ${REENTRANT} ${CRYPTINCL} ${CRYPTFLAGS} -c $*.c -o ${THREADED}/$*.${O} + -${LDS} ${LD} ${LD_LIBFLAGS} ${THREADED}/$*.${O} -o a.out && \ + ${LDS} mv a.out ${THREADED}/$*.${O} + ${CC} ${CPPFLAGS} ${CFLAGS} ${CRYPTINCL} ${CRYPTFLAGS} -c $*.c + -${LDS} ${LD} ${LD_LIBFLAGS} $*.${O} -o a.out && \ + ${LDS} mv a.out $*.${O} + +$(SRCS):: $(HDRS) + +distclean: clean + +clean: FRC + rm -f .depend a.out core ${LIB} tags + rm -f *.${O} *.BAK *.CKP *~ + rm -f prand_conf.h + rm -f ${THREADED}/*.${O} + -rmdir ${THREADED} + +depend: FRC + mkdep -I${INCL} -I${PORTINCL} ${CPPFLAGS} ${SRCS} + +links: FRC + @set -e; ln -s SRC/*.[ch] SRC/*.pl . + +install: + +FRC: + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. diff --git a/contrib/bind/lib/dst/README b/contrib/bind/lib/dst/README new file mode 100644 index 0000000..6283e58 --- /dev/null +++ b/contrib/bind/lib/dst/README @@ -0,0 +1,27 @@ +This directory in BIND contains the Domain Signature Tools (dst) +library. It was written by Trusted Information Systems, Inc. and +integrated into BIND by John Gilmore. It is used as a generic +crypto library interface by the DNS Security code in BIND. + + Installing Domain Signature Tools Library - dst + +1. Assess available crypto libraries: + + if you have DNSSAFE (the default) + CRYPTFLAGS must include -DDNSSAFE + CRYPTINCL must include -I../dnssafe + + if you have RSAREF + CRYPTFLAGS must include -DRSAREF + CRYPTINCL must include -I<path to rsa include files> + + if you have BSAFE + CRYPTFLAGS must include -DBSAFE + CRYPTINCL must include -I<path to bsafe include files> + + if you want HMAC-MD5 support + CRYPTFLAGs must include -DHMAC + +2. Building BIND as usual will include the dst library routines into + libbind.a, and link them into the BIND programs that use crypto + support. diff --git a/contrib/bind/lib/dst/bsafe_link.c b/contrib/bind/lib/dst/bsafe_link.c new file mode 100644 index 0000000..8b24d99 --- /dev/null +++ b/contrib/bind/lib/dst/bsafe_link.c @@ -0,0 +1,1125 @@ +#if defined(BSAFE) || defined(DNSSAFE) +static const char rcsid[] = "$Header: /proj/cvs/isc/bind/src/lib/dst/bsafe_link.c,v 1.11 1999/10/13 16:39:22 vixie 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() +{ + 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, + (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 (out_len < pub->exponent.len) /* not enough space */ + return (-1); + if (pub->exponent.len < 256) /* key exponent is <= 2040 bits */ + *op++ = (u_int8_t) pub->exponent.len; + else { /* key exponent is > 2040 bits */ + u_int16_t e = (u_int16_t) pub->exponent.len; + *op++ = 0; /* 3 byte lenght field */ + dst_s_put_int16(op, e); + op += sizeof(e); + n = 2; + } + n += pub->exponent.len; + memcpy(op, pub->exponent.data, n); + op += n; + n++; + + if ((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, (u_char *) 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(POINTER firstBlock, POINTER secondBlock, unsigned int len) +{ + return (memcmp(firstBlock, secondBlock, len)); +} + +void +T_memcpy(POINTER output, POINTER 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/contrib/bind/lib/dst/cylink_link.c b/contrib/bind/lib/dst/cylink_link.c new file mode 100644 index 0000000..c7cb276 --- /dev/null +++ b/contrib/bind/lib/dst/cylink_link.c @@ -0,0 +1,676 @@ +#ifdef CYLINK_DSS +static const char rcsid[] = "$Header: /proj/cvs/isc/bind/src/lib/dst/cylink_link.c,v 1.7 1999/10/13 16:39:22 vixie 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, (u_char *) 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, (u_char *) 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]; + + 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/contrib/bind/lib/dst/dst_api.c b/contrib/bind/lib/dst/dst_api.c new file mode 100644 index 0000000..6dde481 --- /dev/null +++ b/contrib/bind/lib/dst/dst_api.c @@ -0,0 +1,1068 @@ +#ifndef LINT +static const char rcsid[] = "$Header: /proj/cvs/isc/bind/src/lib/dst/dst_api.c,v 1.13 1999/10/13 16:39:22 vixie 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]; +char *key_file_fmt_str = "Private-key-format: v%s\nAlgorithm: %d (%s)\n"; +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 { + dst_path = (char *) malloc(len + 2); + memcpy(dst_path, s, len + 1); + if (dst_path[strlen(dst_path) - 1] != '/') { + dst_path[strlen(dst_path) + 1] = 0; + dst_path[strlen(dst_path)] = '/'; + } + } + } + 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 != 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/contrib/bind/lib/dst/dst_internal.h b/contrib/bind/lib/dst/dst_internal.h new file mode 100644 index 0000000..66bfed4 --- /dev/null +++ b/contrib/bind/lib/dst/dst_internal.h @@ -0,0 +1,163 @@ +#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) +#endif + +/* use our own special macro to FRRE memory */ + +#ifndef SAFE_FREE +#define SAFE_FREE(a) if(a != NULL){memset(a,0, sizeof(*a)); free(a); a=NULL;} +#define SAFE_FREE2(a,s) if (a != NULL && s > 0){memset(a,0, s);free(a); a=NULL;} +#endif + +typedef struct dst_func { + int (*sign)(const int mode, DST_KEY *key, void **context, + const u_int8_t *data, const 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 char *key_file_fmt_str; +extern 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(); + +int dst_rsaref_init(); + +int dst_hmac_md5_init(); + +int dst_cylink_init(); + +int dst_eay_dss_init(); + +/* 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 + + +#endif /* DST_INTERNAL_H */ diff --git a/contrib/bind/lib/dst/eay_dss_link.c b/contrib/bind/lib/dst/eay_dss_link.c new file mode 100644 index 0000000..b060bf0 --- /dev/null +++ b/contrib/bind/lib/dst/eay_dss_link.c @@ -0,0 +1,624 @@ +#ifdef EAY_DSS +static const char rcsid[] = "$Header: /proj/cvs/isc/bind/src/lib/dst/eay_dss_link.c,v 1.4 1999/10/13 16:39:23 vixie 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() +{ + 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 +int +dst_eay_dss_init() +{ + return (0); +} +#endif /* EAY_DSS */ diff --git a/contrib/bind/lib/dst/hmac_link.c b/contrib/bind/lib/dst/hmac_link.c new file mode 100644 index 0000000..1f96bca --- /dev/null +++ b/contrib/bind/lib/dst/hmac_link.c @@ -0,0 +1,493 @@ +#ifdef HMAC_MD5 +#ifndef LINT +static const char rcsid[] = "$Header: /proj/cvs/isc/bind/src/lib/dst/hmac_link.c,v 1.8 1999/10/15 21:30:07 vixie 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, (u_char *)data, len); + + if (mode & SIG_MODE_FINAL) { + if (signature == NULL || sig_len < MD5_LEN) + return (SIGN_FINAL_FAILURE); + MD5Final(signature, ctx); + + /* perform outer MD5 */ + MD5Init(ctx); + MD5Update(ctx, key->hk_opad, HMAC_LEN); + MD5Update(ctx, signature, MD5_LEN); + MD5Final(signature, ctx); + sign_len = MD5_LEN; + SAFE_FREE(ctx); + } + else { + if (context == NULL) + return (-1); + *context = (void *) ctx; + } + return (sign_len); +} + + +/************************************************************************** + * dst_hmac_md5_verify() + * Calls HMAC verification routines. There are three steps to + * verification, INIT (initialize structures), UPDATE (hash (more) data), + * FINAL (generate a signature). This routine performs one or more of + * these steps. + * Parameters + * mode SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL. + * dkey key to use for verify. + * data data signed. + * len length in bytes of data. + * signature signature. + * sig_len length in bytes of signature. + * returns + * 0 Success + * <0 Failure + */ + +static int +dst_hmac_md5_verify(const int mode, DST_KEY *d_key, void **context, + const u_char *data, const 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, (u_char *)data, len); + + if (mode & SIG_MODE_FINAL) { + u_char digest[MD5_LEN]; + if (signature == NULL || key == NULL || sig_len != MD5_LEN) + return (VERIFY_FINAL_FAILURE); + MD5Final(digest, ctx); + + /* perform outer MD5 */ + MD5Init(ctx); + MD5Update(ctx, key->hk_opad, HMAC_LEN); + MD5Update(ctx, digest, MD5_LEN); + MD5Final(digest, ctx); + + SAFE_FREE(ctx); + if (memcmp(digest, signature, MD5_LEN) != 0) + return (VERIFY_FINAL_FAILURE); + } + else { + if (context == NULL) + return (-1); + *context = (void *) ctx; + } + return (0); +} + + +/************************************************************************** + * dst_buffer_to_hmac_md5 + * Converts key from raw data to an HMAC Key + * This function gets in a pointer to the data + * Parameters + * hkey the HMAC key to be filled in + * key the key in raw format + * keylen the length of the key + * Return + * 0 Success + * <0 Failure + */ +static int +dst_buffer_to_hmac_md5(DST_KEY *dkey, const u_char *key, const 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, (u_char *)key, keylen); + MD5Final(tk, &ctx); + memset((void *) &ctx, 0, sizeof(ctx)); + key = tk; + local_keylen = MD5_LEN; + } + /* start out by storing key in pads */ + memcpy(hkey->hk_ipad, key, local_keylen); + memcpy(hkey->hk_opad, key, local_keylen); + + /* XOR key with hk_ipad and opad values */ + for (i = 0; i < HMAC_LEN; i++) { + hkey->hk_ipad[i] ^= HMAC_IPAD; + hkey->hk_opad[i] ^= HMAC_OPAD; + } + dkey->dk_key_size = local_keylen; + dkey->dk_KEY_struct = (void *) hkey; + return (1); +} + + +/************************************************************************** + * dst_hmac_md5_key_to_file_format + * Encodes an HMAC Key into the portable file format. + * Parameters + * hkey HMAC KEY structure + * buff output buffer + * buff_len size of output buffer + * Return + * 0 Failure - null input hkey + * -1 Failure - not enough space in output area + * N Success - Length of data returned in buff + */ + +static int +dst_hmac_md5_key_to_file_format(const DST_KEY *dkey, char *buff, + const 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; + + 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/contrib/bind/lib/dst/md5.h b/contrib/bind/lib/dst/md5.h new file mode 100644 index 0000000..c8b1580 --- /dev/null +++ b/contrib/bind/lib/dst/md5.h @@ -0,0 +1,101 @@ +/* crypto/md/md5.h */ +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_MD5_H +#define HEADER_MD5_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MD5_CBLOCK 64 +#define MD5_LBLOCK 16 +#define MD5_BLOCK 16 +#define MD5_LAST_BLOCK 56 +#define MD5_LENGTH_BLOCK 8 +#define MD5_DIGEST_LENGTH 16 + +typedef struct MD5state_st + { + unsigned long A,B,C,D; + unsigned long Nl,Nh; + unsigned long data[MD5_LBLOCK]; + int num; + } MD5_CTX; + +#ifndef NOPROTO +void MD5_Init(MD5_CTX *c); +void MD5_Update(MD5_CTX *c, unsigned char *data, unsigned long len); +void MD5_Final(unsigned char *md, MD5_CTX *c); +unsigned char *MD5(unsigned char *d, unsigned long n, unsigned char *md); +#else +void MD5_Init(); +void MD5_Update(); +void MD5_Final(); +unsigned char *MD5(); +#endif + +/* to provide backward compatabilty to RSAREF calls ogud@tis.com 1997/11/14 */ +#define MD5Init(c) MD5_Init(c) +#define MD5Update(c,data, len) MD5_Update(c,data,len) +#define MD5Final(md, c) MD5_Final(md, c) +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/bind/lib/dst/md5_dgst.c b/contrib/bind/lib/dst/md5_dgst.c new file mode 100644 index 0000000..82e5a38 --- /dev/null +++ b/contrib/bind/lib/dst/md5_dgst.c @@ -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" + +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 unsigned char *data; +unsigned long len; + { + register ULONG *p; + int sw,sc; + ULONG l; + + if (len == 0) return; + + l=(c->Nl+(len<<3))&0xffffffffL; + /* 95-05-24 eay Fixed a bug with the overflow handling, thanks to + * Wei Dai <weidai@eskimo.com> for pointing it out. */ + if (l < c->Nl) /* overflow */ + c->Nh++; + c->Nh+=(len>>29); + c->Nl=l; + + if (c->num != 0) + { + p=c->data; + sw=c->num>>2; + sc=c->num&0x03; + + if ((c->num+len) >= MD5_CBLOCK) + { + l= p[sw]; + p_c2l(data,l,sc); + p[sw++]=l; + for (; sw<MD5_LBLOCK; sw++) + { + c2l(data,l); + p[sw]=l; + } + len-=(MD5_CBLOCK-c->num); + + md5_block(c,p); + c->num=0; + /* drop through and do the rest */ + } + else + { + int ew,ec; + + c->num+=(int)len; + if ((sc+len) < 4) /* ugly, add char's to a word */ + { + l= p[sw]; + p_c2l_p(data,l,sc,len); + p[sw]=l; + } + else + { + ew=(c->num>>2); + ec=(c->num&0x03); + l= p[sw]; + p_c2l(data,l,sc); + p[sw++]=l; + for (; sw < ew; sw++) + { c2l(data,l); p[sw]=l; } + if (ec) + { + c2l_p(data,l,ec); + p[sw]=l; + } + } + return; + } + } + /* we now can process the input data in blocks of MD5_CBLOCK + * chars and save the leftovers to c->data. */ + p=c->data; + while (len >= MD5_CBLOCK) + { +#if defined(L_ENDIAN) || defined(B_ENDIAN) + memcpy(p,data,MD5_CBLOCK); + data+=MD5_CBLOCK; +#ifdef B_ENDIAN + for (sw=(MD5_LBLOCK/4); sw; sw--) + { + Endian_Reverse32(p[0]); + Endian_Reverse32(p[1]); + Endian_Reverse32(p[2]); + Endian_Reverse32(p[3]); + p+=4; + } +#endif +#else + for (sw=(MD5_LBLOCK/4); sw; sw--) + { + c2l(data,l); *(p++)=l; + c2l(data,l); *(p++)=l; + c2l(data,l); *(p++)=l; + c2l(data,l); *(p++)=l; + } +#endif + p=c->data; + md5_block(c,p); + len-=MD5_CBLOCK; + } + sc=(int)len; + c->num=sc; + if (sc) + { + sw=sc>>2; /* words to copy */ +#ifdef L_ENDIAN + p[sw]=0; + memcpy(p,data,sc); +#else + sc&=0x03; + for ( ; sw; sw--) + { c2l(data,l); *(p++)=l; } + c2l_p(data,l,sc); + *p=l; +#endif + } + } + +static void md5_block(c, X) +MD5_CTX *c; +register ULONG *X; + { + register ULONG A,B,C,D; + + A=c->A; + B=c->B; + C=c->C; + D=c->D; + + /* Round 0 */ + R0(A,B,C,D,X[ 0], 7,0xd76aa478L); + R0(D,A,B,C,X[ 1],12,0xe8c7b756L); + R0(C,D,A,B,X[ 2],17,0x242070dbL); + R0(B,C,D,A,X[ 3],22,0xc1bdceeeL); + R0(A,B,C,D,X[ 4], 7,0xf57c0fafL); + R0(D,A,B,C,X[ 5],12,0x4787c62aL); + R0(C,D,A,B,X[ 6],17,0xa8304613L); + R0(B,C,D,A,X[ 7],22,0xfd469501L); + R0(A,B,C,D,X[ 8], 7,0x698098d8L); + R0(D,A,B,C,X[ 9],12,0x8b44f7afL); + R0(C,D,A,B,X[10],17,0xffff5bb1L); + R0(B,C,D,A,X[11],22,0x895cd7beL); + R0(A,B,C,D,X[12], 7,0x6b901122L); + R0(D,A,B,C,X[13],12,0xfd987193L); + R0(C,D,A,B,X[14],17,0xa679438eL); + R0(B,C,D,A,X[15],22,0x49b40821L); + /* Round 1 */ + R1(A,B,C,D,X[ 1], 5,0xf61e2562L); + R1(D,A,B,C,X[ 6], 9,0xc040b340L); + R1(C,D,A,B,X[11],14,0x265e5a51L); + R1(B,C,D,A,X[ 0],20,0xe9b6c7aaL); + R1(A,B,C,D,X[ 5], 5,0xd62f105dL); + R1(D,A,B,C,X[10], 9,0x02441453L); + R1(C,D,A,B,X[15],14,0xd8a1e681L); + R1(B,C,D,A,X[ 4],20,0xe7d3fbc8L); + R1(A,B,C,D,X[ 9], 5,0x21e1cde6L); + R1(D,A,B,C,X[14], 9,0xc33707d6L); + R1(C,D,A,B,X[ 3],14,0xf4d50d87L); + R1(B,C,D,A,X[ 8],20,0x455a14edL); + R1(A,B,C,D,X[13], 5,0xa9e3e905L); + R1(D,A,B,C,X[ 2], 9,0xfcefa3f8L); + R1(C,D,A,B,X[ 7],14,0x676f02d9L); + R1(B,C,D,A,X[12],20,0x8d2a4c8aL); + /* Round 2 */ + R2(A,B,C,D,X[ 5], 4,0xfffa3942L); + R2(D,A,B,C,X[ 8],11,0x8771f681L); + R2(C,D,A,B,X[11],16,0x6d9d6122L); + R2(B,C,D,A,X[14],23,0xfde5380cL); + R2(A,B,C,D,X[ 1], 4,0xa4beea44L); + R2(D,A,B,C,X[ 4],11,0x4bdecfa9L); + R2(C,D,A,B,X[ 7],16,0xf6bb4b60L); + R2(B,C,D,A,X[10],23,0xbebfbc70L); + R2(A,B,C,D,X[13], 4,0x289b7ec6L); + R2(D,A,B,C,X[ 0],11,0xeaa127faL); + R2(C,D,A,B,X[ 3],16,0xd4ef3085L); + R2(B,C,D,A,X[ 6],23,0x04881d05L); + R2(A,B,C,D,X[ 9], 4,0xd9d4d039L); + R2(D,A,B,C,X[12],11,0xe6db99e5L); + R2(C,D,A,B,X[15],16,0x1fa27cf8L); + R2(B,C,D,A,X[ 2],23,0xc4ac5665L); + /* Round 3 */ + R3(A,B,C,D,X[ 0], 6,0xf4292244L); + R3(D,A,B,C,X[ 7],10,0x432aff97L); + R3(C,D,A,B,X[14],15,0xab9423a7L); + R3(B,C,D,A,X[ 5],21,0xfc93a039L); + R3(A,B,C,D,X[12], 6,0x655b59c3L); + R3(D,A,B,C,X[ 3],10,0x8f0ccc92L); + R3(C,D,A,B,X[10],15,0xffeff47dL); + R3(B,C,D,A,X[ 1],21,0x85845dd1L); + R3(A,B,C,D,X[ 8], 6,0x6fa87e4fL); + R3(D,A,B,C,X[15],10,0xfe2ce6e0L); + R3(C,D,A,B,X[ 6],15,0xa3014314L); + R3(B,C,D,A,X[13],21,0x4e0811a1L); + R3(A,B,C,D,X[ 4], 6,0xf7537e82L); + R3(D,A,B,C,X[11],10,0xbd3af235L); + R3(C,D,A,B,X[ 2],15,0x2ad7d2bbL); + R3(B,C,D,A,X[ 9],21,0xeb86d391L); + + c->A+=A&0xffffffffL; + c->B+=B&0xffffffffL; + c->C+=C&0xffffffffL; + c->D+=D&0xffffffffL; + } + +void MD5_Final(md, c) +unsigned char *md; +MD5_CTX *c; + { + register int i,j; + register ULONG l; + register ULONG *p; + static unsigned char end[4]={0x80,0x00,0x00,0x00}; + unsigned char *cp=end; + + /* c->num should definitly have room for at least one more byte. */ + p=c->data; + j=c->num; + i=j>>2; + + /* purify often complains about the following line as an + * Uninitialized Memory Read. While this can be true, the + * following p_c2l macro will reset l when that case is true. + * This is because j&0x03 contains the number of 'valid' bytes + * already in p[i]. If and only if j&0x03 == 0, the UMR will + * occur but this is also the only time p_c2l will do + * l= *(cp++) instead of l|= *(cp++) + * Many thanks to Alex Tang <altitude@cic.net> for pickup this + * 'potential bug' */ +#ifdef PURIFY + if ((j&0x03) == 0) p[i]=0; +#endif + l=p[i]; + p_c2l(cp,l,j&0x03); + p[i]=l; + i++; + /* i is the next 'undefined word' */ + if (c->num >= MD5_LAST_BLOCK) + { + for (; i<MD5_LBLOCK; i++) + p[i]=0; + md5_block(c,p); + i=0; + } + for (; i<(MD5_LBLOCK-2); i++) + p[i]=0; + p[MD5_LBLOCK-2]=c->Nl; + p[MD5_LBLOCK-1]=c->Nh; + md5_block(c,p); + cp=md; + l=c->A; l2c(l,cp); + l=c->B; l2c(l,cp); + l=c->C; l2c(l,cp); + l=c->D; l2c(l,cp); + + /* clear stuff, md5_block may be leaving some stuff on the stack + * but I'm not worried :-) */ + c->num=0; +/* memset((char *)&c,0,sizeof(c));*/ + } + +#ifdef undef +int printit(l) +unsigned long *l; + { + int i,ii; + + for (i=0; i<2; i++) + { + for (ii=0; ii<8; ii++) + { + fprintf(stderr,"%08lx ",l[i*8+ii]); + } + fprintf(stderr,"\n"); + } + } +#endif +#endif /* USE_MD5 */ diff --git a/contrib/bind/lib/dst/md5_locl.h b/contrib/bind/lib/dst/md5_locl.h new file mode 100644 index 0000000..b2f0028 --- /dev/null +++ b/contrib/bind/lib/dst/md5_locl.h @@ -0,0 +1,190 @@ +/* crypto/md/md5_locl.h */ +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include <stdlib.h> +#include <string.h> +#include "md5.h" + +#define ULONG unsigned long +#define UCHAR unsigned char +#define UINT unsigned int + +#if defined(NOCONST) +#define const +#endif + +#undef c2l +#define c2l(c,l) (l = ((unsigned long)(*((c)++))) , \ + l|=(((unsigned long)(*((c)++)))<< 8), \ + l|=(((unsigned long)(*((c)++)))<<16), \ + l|=(((unsigned long)(*((c)++)))<<24)) + +#undef p_c2l +#define p_c2l(c,l,n) { \ + switch (n) { \ + case 0: l =((unsigned long)(*((c)++))); \ + case 1: l|=((unsigned long)(*((c)++)))<< 8; \ + case 2: l|=((unsigned long)(*((c)++)))<<16; \ + case 3: l|=((unsigned long)(*((c)++)))<<24; \ + } \ + } + +/* NOTE the pointer is not incremented at the end of this */ +#undef c2l_p +#define c2l_p(c,l,n) { \ + l=0; \ + (c)+=n; \ + switch (n) { \ + case 3: l =((unsigned long)(*(--(c))))<<16; \ + case 2: l|=((unsigned long)(*(--(c))))<< 8; \ + case 1: l|=((unsigned long)(*(--(c)))) ; \ + } \ + } + +#undef p_c2l_p +#define p_c2l_p(c,l,sc,len) { \ + switch (sc) \ + { \ + case 0: l =((unsigned long)(*((c)++))); \ + if (--len == 0) break; \ + case 1: l|=((unsigned long)(*((c)++)))<< 8; \ + if (--len == 0) break; \ + case 2: l|=((unsigned long)(*((c)++)))<<16; \ + } \ + } + +#undef l2c +#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \ + *((c)++)=(unsigned char)(((l)>> 8)&0xff), \ + *((c)++)=(unsigned char)(((l)>>16)&0xff), \ + *((c)++)=(unsigned char)(((l)>>24)&0xff)) + +/* NOTE - c is not incremented as per l2c */ +#undef l2cn +#define l2cn(l1,l2,c,n) { \ + c+=n; \ + switch (n) { \ + case 8: *(--(c))=(unsigned char)(((l2)>>24)&0xff); \ + case 7: *(--(c))=(unsigned char)(((l2)>>16)&0xff); \ + case 6: *(--(c))=(unsigned char)(((l2)>> 8)&0xff); \ + case 5: *(--(c))=(unsigned char)(((l2) )&0xff); \ + case 4: *(--(c))=(unsigned char)(((l1)>>24)&0xff); \ + case 3: *(--(c))=(unsigned char)(((l1)>>16)&0xff); \ + case 2: *(--(c))=(unsigned char)(((l1)>> 8)&0xff); \ + case 1: *(--(c))=(unsigned char)(((l1) )&0xff); \ + } \ + } + +/* A nice byte order reversal from Wei Dai <weidai@eskimo.com> */ +#if defined(WIN32) +/* 5 instructions with rotate instruction, else 9 */ +#define Endian_Reverse32(a) \ + { \ + unsigned long l=(a); \ + (a)=((ROTATE(l,8)&0x00FF00FF)|(ROTATE(l,24)&0xFF00FF00)); \ + } +#else +/* 6 instructions with rotate instruction, else 8 */ +#define Endian_Reverse32(a) \ + { \ + unsigned long l=(a); \ + l=(((l&0xFF00FF00)>>8L)|((l&0x00FF00FF)<<8L)); \ + (a)=ROTATE(l,16L); \ + } +#endif +/* +#define F(x,y,z) (((x) & (y)) | ((~(x)) & (z))) +#define G(x,y,z) (((x) & (z)) | ((y) & (~(z)))) +*/ + +/* As pointed out by Wei Dai <weidai@eskimo.com>, the above can be + * simplified to the code below. Wei attributes these optimisations + * to Peter Gutmann's SHS code, and he attributes it to Rich Schroeppel. + */ +#define F(x,y,z) ((((y) ^ (z)) & (x)) ^ (z)) +#define G(x,y,z) ((((x) ^ (y)) & (z)) ^ (y)) +#define H(x,y,z) ((x) ^ (y) ^ (z)) +#define I(x,y,z) (((x) | (~(z))) ^ (y)) + +#undef ROTATE +#if defined(WIN32) +#define ROTATE(a,n) _lrotl(a,n) +#else +#define ROTATE(a,n) (((a)<<(n))|(((a)&0xffffffff)>>(32-(n)))) +#endif + + +#define R0(a,b,c,d,k,s,t) { \ + a+=((k)+(t)+F((b),(c),(d))); \ + a=ROTATE(a,s); \ + a+=b; };\ + +#define R1(a,b,c,d,k,s,t) { \ + a+=((k)+(t)+G((b),(c),(d))); \ + a=ROTATE(a,s); \ + a+=b; }; + +#define R2(a,b,c,d,k,s,t) { \ + a+=((k)+(t)+H((b),(c),(d))); \ + a=ROTATE(a,s); \ + a+=b; }; + +#define R3(a,b,c,d,k,s,t) { \ + a+=((k)+(t)+I((b),(c),(d))); \ + a=ROTATE(a,s); \ + a+=b; }; diff --git a/contrib/bind/lib/dst/prandom.c b/contrib/bind/lib/dst/prandom.c new file mode 100644 index 0000000..0a66e61 --- /dev/null +++ b/contrib/bind/lib/dst/prandom.c @@ -0,0 +1,851 @@ +#ifndef LINT +static const char rcsid[] = "$Header: /proj/cvs/isc/bind/src/lib/dst/prandom.c,v 1.8 1999/10/13 16:39:24 vixie 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 <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, u_char *input, + int size); +static int my_digest(dst_work *tmp, 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 < 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) + NULL; /* drain the pipe */ + pclose(pipe); + return (cnt); /* read how many bytes where read in */ +} + +/* + * digest_file() This function will read a file and run hash over it + * input is a file name + */ +static int +digest_file(dst_work *work) +{ + static int f_cnt = 0; + static unsigned long f_round = 0; + FILE *fp; + void *ctx; + const char *name; + int no, i; + struct stat st; + struct timeval tv; + u_char buf[1024]; + + if (f_round == 0 || files[f_cnt] == NULL || work->file_digest == NULL) + if (gettimeofday(&tv, NULL)) /* only do this if needed */ + return (0); + if (f_round == 0) /* first time called set to one hour ago */ + f_round = (tv.tv_sec - MAX_OLD); + name = files[f_cnt++]; + if (files[f_cnt] == NULL) { /* end of list of files */ + if(f_cnt <= 1) /* list is too short */ + return (0); + f_cnt = 0; /* start again on list */ + f_round += (tv.tv_sec - f_round)/2; /* set new cutoff */ + work->file_digest = dst_free_key(work->file_digest); + } + if (work->file_digest == NULL) { + work->file_digest = dst_buffer_to_key("", KEY_HMAC_MD5, 0, 0, + (u_char *)&tv, sizeof(tv)); + if (work->file_digest == NULL) + return (0); + } + if (access(name, R_OK) || stat(name, &st)) + return (0); /* no such file or not allowed to read it */ + if (strncmp(name, "/proc/", 6) && st.st_mtime < f_round) + return(0); /* file has not changed recently enough */ + if (dst_sign_data(SIG_MODE_INIT, work->file_digest, &ctx, + NULL, 0, NULL, 0)) { + work->file_digest = dst_free_key(work->file_digest); + return (0); + } + if ((fp = fopen(name, "r")) == NULL) + return (0); + for (no = 0; (i = fread(buf, sizeof(*buf), sizeof(buf), fp)) > 0; + no += i) + dst_sign_data(SIG_MODE_UPDATE, work->file_digest, &ctx, + buf, 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, (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, u_char *input, int size) +{ + u_char *tmp = input, *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; + tp = tmp = 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 != input) + SAFE_FREE2(tmp, tmp_size); + return (1); + } + } + if (tmp_size > 0) + SAFE_FREE2(tmp, 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, 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)); + if (i != hb_size) + EREPORT(("HMAC SIGNATURE FAILURE %d\n", i)); + cnt++; + if (size - out < i) /* Not all data is needed */ + semi_loc = i = size - out; + memcpy(&output[out], semi_old, i); + out += i; + } + return (out); +} diff --git a/contrib/bind/lib/dst/rsaref_link.c b/contrib/bind/lib/dst/rsaref_link.c new file mode 100644 index 0000000..19c9a67 --- /dev/null +++ b/contrib/bind/lib/dst/rsaref_link.c @@ -0,0 +1,754 @@ +#ifdef RSAREF +static const char rcsid[] = "$Header: /proj/cvs/isc/bind/src/lib/dst/rsaref_link.c,v 1.6 1999/10/13 16:39:24 vixie 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 +int /* rsaref is not available */ +dst_rsaref_init() +{ + return (0); +} +#endif /* RSAREF */ diff --git a/contrib/bind/lib/dst/support.c b/contrib/bind/lib/dst/support.c new file mode 100644 index 0000000..d50aa07 --- /dev/null +++ b/contrib/bind/lib/dst/support.c @@ -0,0 +1,461 @@ +static const char rcsid[] = "$Header: /proj/cvs/isc/bind/src/lib/dst/support.c,v 1.8 1999/10/13 16:39:24 vixie 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((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, + (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]; + int 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) +{ + 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/contrib/bind/lib/inet/Makefile b/contrib/bind/lib/inet/Makefile index 80bff87..04c4c1f 100644 --- a/contrib/bind/lib/inet/Makefile +++ b/contrib/bind/lib/inet/Makefile @@ -1,4 +1,4 @@ -# Copyright (c) 1996 by Internet Software Consortium +# 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 @@ -13,7 +13,7 @@ # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS # SOFTWARE. -# $Id: Makefile,v 8.8 1997/05/21 19:32:07 halley Exp $ +# $Id: Makefile,v 8.16 1999/03/03 08:07:16 vixie Exp $ # these are only appropriate for BSD 4.4 or derivatives, and are used in # development. normal builds will be done in the top level directory and @@ -31,36 +31,53 @@ TOP= ../.. INCL = ${TOP}/include PORTINCL = ${TOP}/port/${SYSTYPE}/include LIBBIND = ${TOP}/lib/libbind.${A} +LIBBINDR = ../${TOP}/lib/libbind_r.${A} CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL} LD_LIBFLAGS= -x -r -AR= ar cruv +AR= ar cru RANLIB= ranlib INSTALL= install +INSTALL_EXEC= +INSTALL_LIB=-o bin -g bin +THREADED= threaded SRCS= nsap_addr.c inet_addr.c inet_ntop.c inet_pton.c \ inet_ntoa.c inet_neta.c inet_net_ntop.c inet_net_pton.c \ + inet_cidr_ntop.c inet_cidr_pton.c \ inet_lnaof.c inet_makeaddr.c inet_netof.c inet_network.c OBJS= nsap_addr.${O} inet_addr.${O} inet_ntop.${O} inet_pton.${O} \ inet_ntoa.${O} inet_neta.${O} inet_net_ntop.${O} inet_net_pton.${O} \ + inet_cidr_ntop.${O} inet_cidr_pton.${O} \ inet_lnaof.${O} inet_makeaddr.${O} inet_netof.${O} inet_network.${O} - all: ${LIBBIND} ${LIBBIND}: ${OBJS} + ( cd ${THREADED} ; \ + ${AR} ${LIBBINDR} ${ARPREF} ${OBJS} ${ARSUFF} ; \ + ${RANLIB} ${LIBBINDR} ) ${AR} ${LIBBIND} ${ARPREF} ${OBJS} ${ARSUFF} ${RANLIB} ${LIBBIND} .c.${O}: - ${CC} ${CPPFLAGS} ${CFLAGS} -c $*.c - -${LDS} ${LD} ${LD_LIBFLAGS} $*.${O} && ${LDS} mv a.out $*.${O} + if test ! -d ${THREADED} ; then mkdir ${THREADED} ; fi + ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} ${REENTRANT} -c $*.c \ + -o ${THREADED}/$*.${O} + -${LDS} ${LD} ${LD_LIBFLAGS} ${THREADED}/$*.${O} -o a.out && \ + ${LDS} mv a.out ${THREADED}/$*.${O} + ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c + -${LDS} ${LD} ${LD_LIBFLAGS} $*.${O} -o a.out && \ + ${LDS} mv a.out $*.${O} distclean: clean clean: FRC rm -f .depend a.out core ${LIB} tags rm -f *.${O} *.BAK *.CKP *~ + rm -f ${THREADED}/*.${O} + -rmdir ${THREADED} + depend: FRC mkdep -I${INCL} -I${PORTINCL} ${CPPFLAGS} ${SRCS} diff --git a/contrib/bind/lib/inet/inet_addr.c b/contrib/bind/lib/inet/inet_addr.c index 1d3943b..3b54aa8 100644 --- a/contrib/bind/lib/inet/inet_addr.c +++ b/contrib/bind/lib/inet/inet_addr.c @@ -1,6 +1,4 @@ /* - * ++Copyright++ 1983, 1990, 1993 - * - * Copyright (c) 1983, 1990, 1993 * The Regents of the University of California. All rights reserved. * @@ -31,7 +29,9 @@ * 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 @@ -49,33 +49,48 @@ * 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-- + */ + +/* + * 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 char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93"; -static char rcsid[] = "$Id: inet_addr.c,v 8.7 1996/11/18 09:09:07 vixie Exp $"; +static const char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93"; +static const char rcsid[] = "$Id: inet_addr.c,v 8.11 1999/10/13 16:39:25 vixie 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" -/* these are compatibility routines, not needed on recent BSD releases */ +#include "port_after.h" /* * Ascii internet address interpretation routine. * The value returned is in network order. */ u_long -inet_addr(cp) - register const char *cp; -{ +inet_addr(const char *cp) { struct in_addr val; if (inet_aton(cp, &val)) @@ -91,15 +106,13 @@ inet_addr(cp) * cannot distinguish between failure and a local broadcast address. */ int -inet_aton(cp, addr) - register const char *cp; - struct in_addr *addr; -{ - register u_long val; - register int base, n; - register char c; - u_int parts[4]; - register u_int *pp = parts; +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 (;;) { @@ -110,22 +123,28 @@ inet_aton(cp, addr) */ if (!isdigit(c)) return (0); - val = 0; base = 10; + val = 0; base = 10; digit = 0; if (c == '0') { c = *++cp; if (c == 'x' || c == 'X') base = 16, c = *++cp; - else + 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; } @@ -136,7 +155,7 @@ inet_aton(cp, addr) * a.b.c (with c treated as 16 bits) * a.b (with b treated as 24 bits) */ - if (pp >= parts + 3) + if (pp >= parts + 3 || val > 0xff) return (0); *pp++ = val; c = *++cp; @@ -149,15 +168,16 @@ inet_aton(cp, addr) 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 0: - return (0); /* initial nondigit */ - case 1: /* a -- 32 bits */ break; @@ -179,7 +199,7 @@ inet_aton(cp, addr) val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); break; } - if (addr) + if (addr != NULL) addr->s_addr = htonl(val); return (1); } diff --git a/contrib/bind/lib/inet/inet_cidr_ntop.c b/contrib/bind/lib/inet/inet_cidr_ntop.c new file mode 100644 index 0000000..08352ab --- /dev/null +++ b/contrib/bind/lib/inet/inet_cidr_ntop.c @@ -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 8.4 1999/10/07 20:44:02 vixie 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; + int 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/contrib/bind/lib/inet/inet_cidr_pton.c b/contrib/bind/lib/inet/inet_cidr_pton.c new file mode 100644 index 0000000..4fae2c6 --- /dev/null +++ b/contrib/bind/lib/inet/inet_cidr_pton.c @@ -0,0 +1,153 @@ +/* + * 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 8.3 1999/01/08 19:23:41 vixie 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/contrib/bind/lib/inet/inet_lnaof.c b/contrib/bind/lib/inet/inet_lnaof.c index 9562024..97b80cf 100644 --- a/contrib/bind/lib/inet/inet_lnaof.c +++ b/contrib/bind/lib/inet/inet_lnaof.c @@ -32,7 +32,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)inet_lnaof.c 8.1 (Berkeley) 6/4/93"; +static const char sccsid[] = "@(#)inet_lnaof.c 8.1 (Berkeley) 6/4/93"; #endif /* LIBC_SCCS and not lint */ #include "port_before.h" diff --git a/contrib/bind/lib/inet/inet_makeaddr.c b/contrib/bind/lib/inet/inet_makeaddr.c index 8a4b082..49ea023 100644 --- a/contrib/bind/lib/inet/inet_makeaddr.c +++ b/contrib/bind/lib/inet/inet_makeaddr.c @@ -32,7 +32,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)inet_makeaddr.c 8.1 (Berkeley) 6/4/93"; +static const char sccsid[] = "@(#)inet_makeaddr.c 8.1 (Berkeley) 6/4/93"; #endif /* LIBC_SCCS and not lint */ #include "port_before.h" diff --git a/contrib/bind/lib/inet/inet_net_ntop.c b/contrib/bind/lib/inet/inet_net_ntop.c index 7f6526f..4e2f91f 100644 --- a/contrib/bind/lib/inet/inet_net_ntop.c +++ b/contrib/bind/lib/inet/inet_net_ntop.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.4 1996/11/18 09:09:08 vixie Exp $"; +static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.6 1999/01/08 19:23:42 vixie Exp $"; #endif #include "port_before.h" @@ -78,7 +78,7 @@ inet_net_ntop(af, src, bits, dst, size) * pointer to dst, or NULL if an error occurred (check errno). * note: * network byte order assumed. this means 192.5.5.240/28 has - * 0x11110000 in its fourth octet. + * 0b11110000 in its fourth octet. * author: * Paul Vixie (ISC), July 1996 */ @@ -102,6 +102,7 @@ inet_net_ntop_ipv4(src, bits, dst, size) if (size < sizeof "0") goto emsgsize; *dst++ = '0'; + size--; *dst = '\0'; } diff --git a/contrib/bind/lib/inet/inet_net_pton.c b/contrib/bind/lib/inet/inet_net_pton.c index 5f381c5..4d265b2 100644 --- a/contrib/bind/lib/inet/inet_net_pton.c +++ b/contrib/bind/lib/inet/inet_net_pton.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: inet_net_pton.c,v 1.8 1996/11/21 10:28:12 vixie Exp $"; +static const char rcsid[] = "$Id: inet_net_pton.c,v 1.11 1999/01/08 19:23:44 vixie Exp $"; #endif #include "port_before.h" @@ -26,7 +26,7 @@ static const char rcsid[] = "$Id: inet_net_pton.c,v 1.8 1996/11/21 10:28:12 vixi #include <netinet/in.h> #include <arpa/inet.h> -#include <assert.h> +#include <isc/assertions.h> #include <ctype.h> #include <errno.h> #include <stdio.h> @@ -85,7 +85,7 @@ inet_net_pton(af, src, dst, size) * not an IPv4 network specification. * note: * network byte order assumed. this means 192.5.5.240/28 has - * 0x11110000 in its fourth octet. + * 0b11110000 in its fourth octet. * author: * Paul Vixie (ISC), June 1996 */ @@ -107,31 +107,36 @@ inet_net_pton_ipv4(src, dst, size) /* Hexadecimal: Eat nybble string. */ if (size <= 0) goto emsgsize; - *dst = 0, dirty = 0; + dirty = 0; src++; /* skip x or X. */ - while ((ch = *src++) != '\0' && - isascii(ch) && isxdigit(ch)) { + while ((ch = *src++) != '\0' && isascii(ch) && isxdigit(ch)) { if (isupper(ch)) ch = tolower(ch); n = strchr(xdigits, ch) - xdigits; - assert(n >= 0 && n <= 15); - *dst |= n; - if (!dirty++) - *dst <<= 4; - else if (size-- > 0) - *++dst = 0, dirty = 0; + 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); } - if (dirty) - size--; } else if (isascii(ch) && isdigit(ch)) { /* Decimal: eat dotted digit string. */ for (;;) { tmp = 0; do { n = strchr(digits, ch) - digits; - assert(n >= 0 && n <= 9); + INSIST(n >= 0 && n <= 9); tmp *= 10; tmp += n; if (tmp > 255) @@ -159,7 +164,7 @@ inet_net_pton_ipv4(src, dst, size) bits = 0; do { n = strchr(digits, ch) - digits; - assert(n >= 0 && n <= 9); + INSIST(n >= 0 && n <= 9); bits *= 10; bits += n; } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch)); @@ -167,8 +172,6 @@ inet_net_pton_ipv4(src, dst, size) goto enoent; if (bits > 32) goto emsgsize; - if (bits > 32) - goto emsgsize; } /* Firey death and destruction unless we prefetched EOS. */ diff --git a/contrib/bind/lib/inet/inet_neta.c b/contrib/bind/lib/inet/inet_neta.c index 96c24f3..8665a9a 100644 --- a/contrib/bind/lib/inet/inet_neta.c +++ b/contrib/bind/lib/inet/inet_neta.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: inet_neta.c,v 1.5 1997/09/26 17:56:01 halley Exp $"; +static const char rcsid[] = "$Id: inet_neta.c,v 1.6 1999/01/08 19:23:45 vixie Exp $"; #endif #include "port_before.h" diff --git a/contrib/bind/lib/inet/inet_netof.c b/contrib/bind/lib/inet/inet_netof.c index 54b700c..e887530 100644 --- a/contrib/bind/lib/inet/inet_netof.c +++ b/contrib/bind/lib/inet/inet_netof.c @@ -32,7 +32,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)inet_netof.c 8.1 (Berkeley) 6/4/93"; +static const char sccsid[] = "@(#)inet_netof.c 8.1 (Berkeley) 6/4/93"; #endif /* LIBC_SCCS and not lint */ #include "port_before.h" diff --git a/contrib/bind/lib/inet/inet_network.c b/contrib/bind/lib/inet/inet_network.c index 485b0b9..d26369c 100644 --- a/contrib/bind/lib/inet/inet_network.c +++ b/contrib/bind/lib/inet/inet_network.c @@ -32,7 +32,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)inet_network.c 8.1 (Berkeley) 6/4/93"; +static const char sccsid[] = "@(#)inet_network.c 8.1 (Berkeley) 6/4/93"; #endif /* LIBC_SCCS and not lint */ #include "port_before.h" @@ -56,28 +56,35 @@ inet_network(cp) register u_long val, base, n, i; register char c; u_long parts[4], *pp = parts; + int digit; again: - val = 0; base = 10; + val = 0; base = 10; digit = 0; if (*cp == '0') - base = 8, cp++; + 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) + if (pp >= parts + 4 || val > 0xff) return (INADDR_NONE); *pp++ = val, cp++; goto again; diff --git a/contrib/bind/lib/inet/inet_ntoa.c b/contrib/bind/lib/inet/inet_ntoa.c index 6d1ec29..aaedcb6 100644 --- a/contrib/bind/lib/inet/inet_ntoa.c +++ b/contrib/bind/lib/inet/inet_ntoa.c @@ -32,8 +32,8 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)inet_ntoa.c 8.1 (Berkeley) 6/4/93"; -static char rcsid[] = "$Id: inet_ntoa.c,v 1.5 1997/09/26 17:56:01 halley Exp $"; +static const char sccsid[] = "@(#)inet_ntoa.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: inet_ntoa.c,v 1.7 1999/05/14 18:16:55 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ #include "port_before.h" @@ -52,7 +52,7 @@ static char rcsid[] = "$Id: inet_ntoa.c,v 1.5 1997/09/26 17:56:01 halley Exp $"; * Convert network-format internet address * to base 256 d.d.d.d representation. */ -char * +/*const*/ char * inet_ntoa(struct in_addr in) { static char ret[18]; diff --git a/contrib/bind/lib/inet/inet_ntop.c b/contrib/bind/lib/inet/inet_ntop.c index f575fce..0b85e70 100644 --- a/contrib/bind/lib/inet/inet_ntop.c +++ b/contrib/bind/lib/inet/inet_ntop.c @@ -1,4 +1,5 @@ -/* Copyright (c) 1996 by Internet Software Consortium. +/* + * 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 @@ -15,7 +16,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char rcsid[] = "$Id: inet_ntop.c,v 1.4 1996/11/18 09:09:10 vixie Exp $"; +static const char rcsid[] = "$Id: inet_ntop.c,v 1.8 1999/10/13 16:39:28 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ #include "port_before.h" @@ -77,7 +78,7 @@ inet_ntop(af, src, dst, size) /* const char * * inet_ntop4(src, dst, size) - * format an IPv4 address, more or less like inet_ntoa() + * format an IPv4 address * return: * `dst' (as a const) * notes: diff --git a/contrib/bind/lib/inet/inet_pton.c b/contrib/bind/lib/inet/inet_pton.c index 021e840..0a2927d 100644 --- a/contrib/bind/lib/inet/inet_pton.c +++ b/contrib/bind/lib/inet/inet_pton.c @@ -1,4 +1,5 @@ -/* Copyright (c) 1996 by Internet Software Consortium. +/* + * 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 @@ -15,7 +16,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char rcsid[] = "$Id: inet_pton.c,v 1.4 1996/11/18 09:09:11 vixie Exp $"; +static const char rcsid[] = "$Id: inet_pton.c,v 1.7 1999/10/13 16:39:28 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ #include "port_before.h" @@ -171,6 +172,8 @@ inet_pton6(src, dst) return (0); colonp = tp; continue; + } else if (*src == '\0') { + return (0); } if (tp + NS_INT16SZ > endp) return (0); @@ -202,6 +205,8 @@ inet_pton6(src, dst) 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; diff --git a/contrib/bind/lib/inet/nsap_addr.c b/contrib/bind/lib/inet/nsap_addr.c index e8dec96..b28acec 100644 --- a/contrib/bind/lib/inet/nsap_addr.c +++ b/contrib/bind/lib/inet/nsap_addr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1998 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char rcsid[] = "$Id: nsap_addr.c,v 8.8 1998/02/13 01:11:12 halley Exp $"; +static const char rcsid[] = "$Id: nsap_addr.c,v 8.10 1999/10/13 16:39:28 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ #include "port_before.h" diff --git a/contrib/bind/lib/irs/Makefile b/contrib/bind/lib/irs/Makefile index 55130d0..3421b8b 100644 --- a/contrib/bind/lib/irs/Makefile +++ b/contrib/bind/lib/irs/Makefile @@ -1,4 +1,4 @@ -# Copyright (c) 1996 by Internet Software Consortium +# 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 @@ -13,7 +13,7 @@ # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS # SOFTWARE. -# $Id: Makefile,v 8.6 1997/05/21 19:23:18 halley Exp $ +# $Id: Makefile,v 8.16 1999/02/22 02:47:58 vixie Exp $ # these are only appropriate for BSD 4.4 or derivatives, and are used in # development. normal builds will be done in the top level directory and @@ -26,29 +26,48 @@ A=a CC= cc LD= ld SHELL= /bin/sh -CDEBUG= -g +CDEBUG= -g TOP= ../.. INCL = ${TOP}/include PORTINCL = ${TOP}/port/${SYSTYPE}/include LIBBIND = ${TOP}/lib/libbind.${A} +LIBBINDR = ../${TOP}/lib/libbind_r.${A} CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL} +# -D__BIND_NOSTATIC -Wimplicit LD_LIBFLAGS= -x -r -AR= ar cruv +AR= ar cru RANLIB= ranlib INSTALL= install +INSTALL_EXEC= +INSTALL_LIB=-o bin -g bin +THREADED= threaded -SRCS= dns.c dns_gr.c dns_ho.c dns_nw.c dns_pr.c dns_pw.c dns_sv.c gen.c \ - gen_gr.c gen_ho.c gen_ng.c gen_nw.c gen_pr.c gen_pw.c gen_sv.c \ - getgrent.c gethostent.c getnetent.c getnetgrent.c getprotoent.c \ - getpwent.c getservent.c hesiod.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 +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 getgrent_r.c gethostent.c \ + gethostent_r.c getnameinfo.c getnetent.c getnetent_r.c \ + getnetgrent.c getnetgrent_r.c getprotoent.c \ + getprotoent_r.c getpwent.c getpwent_r.c getservent.c \ + getservent_r.c hesiod.c irs_data.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 \ + 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 OBJS= dns.${O} dns_gr.${O} dns_ho.${O} dns_nw.${O} dns_pr.${O} dns_pw.${O} \ - dns_sv.${O} gen.${O} gen_gr.${O} gen_ho.${O} gen_ng.${O} gen_nw.${O} \ - gen_pr.${O} gen_pw.${O} gen_sv.${O} getgrent.${O} gethostent.${O} \ - getnetent.${O} getnetgrent.${O} getprotoent.${O} getpwent.${O} \ - getservent.${O} hesiod.${O} irs_data.${O} lcl.${O} lcl_gr.${O} \ + dns_sv.${O} gai_strerror.${O} gen.${O} gen_gr.${O} gen_ho.${O} \ + gen_ng.${O} gen_nw.${O} gen_pr.${O} gen_pw.${O} gen_sv.${O} \ + getaddrinfo.${O} getgrent.${O} getgrent_r.${O} gethostent.${O} \ + gethostent_r.${O} getnameinfo.${O} getnetent.${O} getnetent_r.${O} \ + getnetgrent.${O} getnetgrent_r.${O} getprotoent.${O} \ + getprotoent_r.${O} getpwent.${O} getpwent_r.${O} getservent.${O} \ + getservent_r.${O} hesiod.${O} irs_data.${O} \ + irp.${O} irp_gr.${O} irp_ho.${O} irp_ng.${O} irp_nw.${O} \ + irp_pr.${O} irp_pw.${O} irp_sv.${O} irpmarshall.${O} \ + lcl.${O} lcl_gr.${O} \ lcl_ho.${O} lcl_ng.${O} lcl_nw.${O} lcl_pr.${O} lcl_pw.${O} \ lcl_sv.${O} nis.${O} nis_gr.${O} nis_ho.${O} nis_ng.${O} nis_nw.${O} \ nis_pr.${O} nis_pw.${O} nis_sv.${O} nul_ng.${O} util.${O} @@ -56,18 +75,29 @@ OBJS= dns.${O} dns_gr.${O} dns_ho.${O} dns_nw.${O} dns_pr.${O} dns_pw.${O} \ all: ${LIBBIND} ${LIBBIND}: ${OBJS} + -( cd ${THREADED} ; \ + ${AR} ${LIBBINDR} ${ARPREF} ${OBJS} ${ARSUFF} ; \ + ${RANLIB} ${LIBBINDR} ) ${AR} ${LIBBIND} ${ARPREF} ${OBJS} ${ARSUFF} ${RANLIB} ${LIBBIND} .c.${O}: - ${CC} ${CPPFLAGS} ${CFLAGS} -c $*.c - -${LDS} ${LD} ${LD_LIBFLAGS} $*.${O} && ${LDS} mv a.out $*.${O} + if test ! -d ${THREADED} ; then mkdir ${THREADED} ; fi + -(${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} ${REENTRANT} -c $*.c \ + -o ${THREADED}/$*.${O} ; \ + ${LDS} ${LD} ${LD_LIBFLAGS} ${THREADED}/$*.${O} && \ + ${LDS} mv a.out ${THREADED}/$*.${O}) + ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c + -${LDS} ${LD} ${LD_LIBFLAGS} $*.${O} -o a.out && \ + ${LDS} mv a.out $*.${O} distclean: clean clean: FRC rm -f .depend a.out core ${LIB} tags rm -f *.${O} *.BAK *.CKP *~ + rm -f ${THREADED}/*.${O} + -rmdir ${THREADED} depend: FRC mkdep -I${INCL} -I${PORTINCL} ${CPPFLAGS} ${SRCS} @@ -75,6 +105,10 @@ depend: FRC links: FRC @set -e; ln -s SRC/*.[ch] . +testirpd: testirpd.o ${LIBBIND} + ${CC} ${CDEBUG} ${LDFLAGS} -o testirpd testirpd.o ${LIBBIND} ${SYSLIBS} + + install: FRC: diff --git a/contrib/bind/lib/irs/Makefile.BSD b/contrib/bind/lib/irs/Makefile.BSD index 197e739..d30c417 100644 --- a/contrib/bind/lib/irs/Makefile.BSD +++ b/contrib/bind/lib/irs/Makefile.BSD @@ -1,4 +1,4 @@ -# BSDI $Id: Makefile.BSD,v 1.4 1996/10/25 07:22:55 vixie Exp $ +# BSDI $Id: Makefile.BSD,v 1.5 1999/01/18 07:46:47 vixie Exp $ # # @(#)Makefile 5.12 (Berkeley) 7/15/92 @@ -15,7 +15,8 @@ SRCS= lcl.c lcl_gr.c lcl_pw.c lcl_sv.c lcl_pr.c lcl_ho.c lcl_nw.c lcl_ng.c \ gen.c gen_gr.c gen_pw.c gen_sv.c gen_pr.c gen_ho.c gen_nw.c gen_ng.c \ getgrent.c getpwent.c getservent.c getprotoent.c gethostent.c \ getnetent.c getnetgrent.c \ - nul_ng.c irs_data.c \ + nul_ng.c irs_data.c irp.c irp_gr.c irp_ho.c irp_ng.c irp_nw.c \ + irp_pr.c irp_pw.c irp_sv.c irpd.c irpmarshall.c \ hesiod.c util.c bitncmp.c NOMAN= diff --git a/contrib/bind/lib/irs/README b/contrib/bind/lib/irs/README index d6b8792..cb81a9a 100644 --- a/contrib/bind/lib/irs/README +++ b/contrib/bind/lib/irs/README @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -18,7 +18,7 @@ This is the Information Retrieval Service (IRS). Designed by Paul Vixie (ISC) and Ted T'so (MIT), 1995. Written by Paul Vixie, Ted T'so and Sam Stoller, 1996. -$Id: README,v 1.4 1996/10/25 07:22:56 vixie Exp $ +$Id: README,v 1.5 1999/01/08 19:23:52 vixie Exp $ Introduction: diff --git a/contrib/bind/lib/irs/dns.c b/contrib/bind/lib/irs/dns.c index e7aa125..7ba7eec 100644 --- a/contrib/bind/lib/irs/dns.c +++ b/contrib/bind/lib/irs/dns.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1998 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: dns.c,v 1.11 1998/03/21 00:59:45 halley Exp $"; +static const char rcsid[] = "$Id: dns.c,v 1.14 1999/01/18 07:46:47 vixie Exp $"; #endif /* @@ -29,6 +29,14 @@ static const char rcsid[] = "$Id: dns.c,v 1.11 1998/03/21 00:59:45 halley Exp $" #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" @@ -40,6 +48,9 @@ static const char rcsid[] = "$Id: dns.c,v 1.11 1998/03/21 00:59:45 halley Exp $" /* 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 */ @@ -48,17 +59,19 @@ irs_dns_acc(const char *options) { struct irs_acc *acc; struct dns_p *dns; - if (!(acc = malloc(sizeof *acc))) { + if (!(acc = memget(sizeof *acc))) { errno = ENOMEM; return (NULL); } memset(acc, 0x5e, sizeof *acc); - if (!(dns = malloc(sizeof *dns))) { + if (!(dns = memget(sizeof *dns))) { errno = ENOMEM; - free(acc); + 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 @@ -83,20 +96,56 @@ irs_dns_acc(const char *options) { 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); - free(dns); - free(this); + memput(dns, sizeof *dns); + memput(this, sizeof *this); } diff --git a/contrib/bind/lib/irs/dns_gr.c b/contrib/bind/lib/irs/dns_gr.c index 9c91719..64cbe9b 100644 --- a/contrib/bind/lib/irs/dns_gr.c +++ b/contrib/bind/lib/irs/dns_gr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1998 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: dns_gr.c,v 1.15 1998/03/21 00:59:46 halley Exp $"; +static const char rcsid[] = "$Id: dns_gr.c,v 1.19 1999/01/18 07:46:48 vixie Exp $"; #endif /* @@ -39,6 +39,13 @@ static int __bind_irs_gr_unneeded; #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" @@ -53,7 +60,7 @@ struct pvt { /* * This is our private accessor data. It has a shared hesiod context. */ - struct dns_p *dns; + 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 @@ -77,6 +84,10 @@ 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, @@ -94,14 +105,14 @@ irs_dns_gr(struct irs_acc *this) { errno = ENODEV; return (NULL); } - if (!(pvt = (struct pvt *)malloc(sizeof *pvt))) { + if (!(pvt = memget(sizeof *pvt))) { errno = ENOMEM; return (NULL); } memset(pvt, 0, sizeof *pvt); pvt->dns = dns; - if (!(gr = (struct irs_gr *)malloc(sizeof *gr))) { - free(pvt); + if (!(gr = memget(sizeof *gr))) { + memput(pvt, sizeof *pvt); errno = ENOMEM; return (NULL); } @@ -114,6 +125,8 @@ irs_dns_gr(struct irs_acc *this) { 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); } @@ -127,8 +140,8 @@ gr_close(struct irs_gr *this) { free(pvt->group.gr_mem); if (pvt->membuf) free(pvt->membuf); - free(pvt); - free(this); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); } static struct group * @@ -247,4 +260,21 @@ get_hes_group(struct irs_gr *this, const char *name, const char *type) { 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/contrib/bind/lib/irs/dns_ho.c b/contrib/bind/lib/irs/dns_ho.c index 3a8c402..e319f96 100644 --- a/contrib/bind/lib/irs/dns_ho.c +++ b/contrib/bind/lib/irs/dns_ho.c @@ -32,7 +32,7 @@ */ /* - * Portions Copyright (c) 1996,1997 by Internet Software Consortium. + * 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 @@ -52,7 +52,7 @@ /* BIND Id: gethnamaddr.c,v 8.15 1996/05/22 04:56:30 vixie Exp $ */ #if defined(LIBC_SCCS) && !defined(lint) -static char rcsid[] = "$Id: dns_ho.c,v 1.18 1998/01/26 23:08:22 halley Exp $"; +static const char rcsid[] = "$Id: dns_ho.c,v 1.26 1999/10/15 19:49:09 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ /* Imports. */ @@ -75,6 +75,7 @@ static char rcsid[] = "$Id: dns_ho.c,v 1.18 1998/01/26 23:08:22 halley Exp $"; #include <stdio.h> #include <string.h> +#include <isc/memcluster.h> #include <irs.h> #include "port_after.h" @@ -88,8 +89,6 @@ static char rcsid[] = "$Id: dns_ho.c,v 1.18 1998/01/26 23:08:22 halley Exp $"; # define SPRINTF(x) sprintf x #endif -extern int h_errno; - /* Definitions. */ #define MAXALIASES 35 @@ -113,6 +112,8 @@ struct pvt { 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 { @@ -122,6 +123,8 @@ typedef union { 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. */ @@ -134,14 +137,19 @@ static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr, 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 void map_v4v6_hostent(struct hostent *hp, char **bp, int *len); -static void addrsort(char **, int); +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); +static int init(struct irs_ho *this); /* Exports. */ @@ -150,13 +158,14 @@ irs_dns_ho(struct irs_acc *this) { struct irs_ho *ho; struct pvt *pvt; - if (!(pvt = (struct pvt *)malloc(sizeof *pvt))) { + if (!(pvt = memget(sizeof *pvt))) { errno = ENOMEM; return (NULL); } memset(pvt, 0, sizeof *pvt); - if (!(ho = (struct irs_ho *)malloc(sizeof *ho))) { - free(pvt); + + if (!(ho = memget(sizeof *ho))) { + memput(pvt, sizeof *pvt); errno = ENOMEM; return (NULL); } @@ -169,6 +178,8 @@ irs_dns_ho(struct irs_acc *this) { ho->next = ho_next; ho->rewind = ho_rewind; ho->minimize = ho_minimize; + ho->res_get = ho_res_get; + ho->res_set = ho_res_set; return (ho); } @@ -178,18 +189,23 @@ 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) - free(pvt); - free(this); + 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 ((_res.options & RES_INIT) == 0 && res_init() == -1) + if (init(this) == -1) return (NULL); - if (_res.options & RES_USE_INET6) { + + if (pvt->res->options & RES_USE_INET6) { hp = ho_byname2(this, name, AF_INET6); if (hp) return (hp); @@ -200,11 +216,12 @@ ho_byname(struct irs_ho *this, const char *name) { static struct hostent * ho_byname2(struct irs_ho *this, const char *name, int af) { struct pvt *pvt = (struct pvt *)this->private; - int n, size, type, len; + int n, size, type; u_char buf[MAXPACKET]; + char tmp[NS_MAXDNAME]; const char *cp; - if ((_res.options & RES_INIT) == 0 && res_init() == -1) + if (init(this) == -1) return (NULL); switch (af) { @@ -217,20 +234,22 @@ ho_byname2(struct irs_ho *this, const char *name, int af) { type = T_AAAA; break; default: - h_errno = NETDB_INTERNAL; + 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_query() since we are not the only + * this is also done in res_nquery() since we are not the only * function that looks up host names. */ - if (!strchr(name, '.') && (cp = hostalias(name))) + if (!strchr(name, '.') && (cp = res_hostalias(pvt->res, name, + tmp, sizeof tmp))) name = cp; - if ((n = res_search(name, C_IN, type, buf, sizeof buf)) < 0) + if ((n = res_nsearch(pvt->res, name, C_IN, type, + buf, sizeof buf)) < 0) return (NULL); return (gethostans(this, buf, n, name, type, af, size)); } @@ -244,11 +263,13 @@ ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) { struct hostent *hp; int n, size; - if ((_res.options & RES_INIT) == 0 && res_init() == -1) + if (init(this) == -1) return (NULL); + if (af == AF_INET6 && len == IN6ADDRSZ && (!memcmp(uaddr, mapped, sizeof mapped) || - !memcmp(uaddr, tunnelled, sizeof tunnelled))) { + (!memcmp(uaddr, tunnelled, sizeof tunnelled) && + memcmp(&uaddr[sizeof tunnelled], v6local, sizeof(v6local))))) { /* Unmap. */ addr = (char *)addr + sizeof mapped; uaddr += sizeof mapped; @@ -264,12 +285,12 @@ ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) { break; default: errno = EAFNOSUPPORT; - h_errno = NETDB_INTERNAL; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); return (NULL); } if (size > len) { errno = EINVAL; - h_errno = NETDB_INTERNAL; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); return (NULL); } switch (af) { @@ -292,21 +313,21 @@ ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) { default: abort(); } - n = res_query(qbuf, C_IN, T_PTR, buf, sizeof buf); + n = res_nquery(pvt->res, qbuf, C_IN, T_PTR, buf, sizeof buf); if (n < 0) return (NULL); hp = gethostans(this, buf, n, qbuf, T_PTR, af, size); if (!hp) - return (NULL); /* h_errno was set by gethostans() */ + return (NULL); /* H_ERRNO was set by gethostans() */ 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 && (_res.options & RES_USE_INET6)) { + 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; } - h_errno = NETDB_SUCCESS; + RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS); return (hp); } @@ -322,7 +343,42 @@ ho_rewind(struct irs_ho *this) { static void ho_minimize(struct irs_ho *this) { - /* NOOP */ + 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; } /* Private. */ @@ -364,7 +420,7 @@ gethostans(struct irs_ho *this, * Find first satisfactory answer. */ if (ansbuf + HFIXEDSZ > eom) { - h_errno = NO_RECOVERY; + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); return (NULL); } hp = (HEADER *)ansbuf; @@ -374,27 +430,27 @@ gethostans(struct irs_ho *this, buflen = sizeof pvt->hostbuf; cp = ansbuf + HFIXEDSZ; if (qdcount != 1) { - h_errno = NO_RECOVERY; + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); return (NULL); } n = dn_expand(ansbuf, eom, cp, bp, buflen); - if ((n < 0) || !(*name_ok)(bp)) { - h_errno = NO_RECOVERY; + 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) { - h_errno = NO_RECOVERY; + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); return (NULL); } if (qtype == T_A || qtype == T_AAAA) { - /* res_send() has already verified that the query name is the + /* 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) { - h_errno = NO_RECOVERY; + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); return (NULL); } pvt->host.h_name = bp; @@ -413,7 +469,7 @@ gethostans(struct irs_ho *this, had_error = 0; while (ancount-- > 0 && cp < eom && !had_error) { n = dn_expand(ansbuf, eom, cp, bp, buflen); - if ((n < 0) || !(*name_ok)(bp)) { + if (n < 0 || !maybe_ok(pvt->res, bp, name_ok)) { had_error++; continue; } @@ -434,7 +490,7 @@ gethostans(struct irs_ho *this, if (ap >= &pvt->host_aliases[MAXALIASES-1]) continue; n = dn_expand(ansbuf, eom, cp, tbuf, sizeof tbuf); - if ((n < 0) || !(*name_ok)(tbuf)) { + if (n < 0 || !maybe_ok(pvt->res, tbuf, name_ok)) { had_error++; continue; } @@ -458,7 +514,7 @@ gethostans(struct irs_ho *this, } if (qtype == T_PTR && type == T_CNAME) { n = dn_expand(ansbuf, eom, cp, tbuf, sizeof tbuf); - if (n < 0 || !res_dnok(tbuf)) { + if (n < 0 || !maybe_dnok(pvt->res, tbuf)) { had_error++; continue; } @@ -481,12 +537,13 @@ gethostans(struct irs_ho *this, } switch (type) { case T_PTR: - if (strcasecmp(tname, bp) != 0) { + if (ns_samename(tname, bp) != 1) { cp += n; continue; } n = dn_expand(ansbuf, eom, cp, bp, buflen); - if (n < 0 || !res_hnok(bp) || n >= MAXHOSTNAMELEN) { + if (n < 0 || !maybe_hnok(pvt->res, bp) || + n >= MAXHOSTNAMELEN) { had_error++; break; } @@ -505,7 +562,7 @@ gethostans(struct irs_ho *this, break; case T_A: case T_AAAA: - if (strcasecmp(pvt->host.h_name, bp) != 0) { + if (ns_samename(pvt->host.h_name, bp) != 1) { cp += n; continue; } @@ -551,8 +608,8 @@ gethostans(struct irs_ho *this, *ap = NULL; *hap = NULL; - if (_res.nsort && haveanswer > 1 && qtype == T_A) - addrsort(pvt->h_addr_ptrs, haveanswer); + if (pvt->res->nsort && haveanswer > 1 && qtype == T_A) + addrsort(pvt->res, pvt->h_addr_ptrs, haveanswer); if (!pvt->host.h_name) { n = strlen(qname) + 1; /* for the \0 */ if (n > buflen || n >= MAXHOSTNAMELEN) @@ -562,13 +619,13 @@ gethostans(struct irs_ho *this, bp += n; buflen -= n; } - if (_res.options & RES_USE_INET6) + if (pvt->res->options & RES_USE_INET6) map_v4v6_hostent(&pvt->host, &bp, &buflen); - h_errno = NETDB_SUCCESS; + RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS); return (&pvt->host); } no_recovery: - h_errno = NO_RECOVERY; + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); return (NULL); } @@ -598,16 +655,16 @@ map_v4v6_hostent(struct hostent *hp, char **bpp, int *lenp) { } static void -addrsort(char **ap, int num) { +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 < _res.nsort; j++) - if (_res.sort_list[j].addr.s_addr == + for (j = 0 ; (unsigned)j < statp->nsort; j++) + if (statp->sort_list[j].addr.s_addr == (((struct in_addr *)(*p))->s_addr & - _res.sort_list[j].mask)) + statp->sort_list[j].mask)) break; aval[i] = j; if (needsort == 0 && i > 0 && j < aval[i-1]) @@ -635,3 +692,15 @@ addrsort(char **ap, int num) { 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/contrib/bind/lib/irs/dns_nw.c b/contrib/bind/lib/irs/dns_nw.c index 30767e7..66ef664 100644 --- a/contrib/bind/lib/irs/dns_nw.c +++ b/contrib/bind/lib/irs/dns_nw.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1998 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: dns_nw.c,v 1.13 1998/02/13 01:10:40 halley Exp $"; +static const char rcsid[] = "$Id: dns_nw.c,v 1.19 1999/10/15 19:49:10 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ /* Imports. */ @@ -38,6 +38,7 @@ static const char rcsid[] = "$Id: dns_nw.c,v 1.13 1998/02/13 01:10:40 halley Exp #include <stdlib.h> #include <string.h> +#include <isc/memcluster.h> #include <irs.h> #include "port_after.h" @@ -51,8 +52,6 @@ static const char rcsid[] = "$Id: dns_nw.c,v 1.13 1998/02/13 01:10:40 halley Exp # define SPRINTF(x) sprintf x #endif -extern int h_errno; - /* Definitions. */ #define MAXALIASES 35 @@ -67,6 +66,8 @@ struct pvt { struct nwent net; char * ali[MAXALIASES]; char buf[BUFSIZ+1]; + struct __res_state * res; + void (*free_res)(void *); }; typedef union { @@ -84,6 +85,10 @@ 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 *); @@ -92,9 +97,10 @@ static struct nwent * get1101answer(struct irs_nw *, enum by_what by_what, int af, const char *name, const u_char *addr, int addrlen); -static struct nwent * get1101mask(struct nwent *); +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. */ @@ -103,13 +109,13 @@ irs_dns_nw(struct irs_acc *this) { struct irs_nw *nw; struct pvt *pvt; - if (!(pvt = (struct pvt *)malloc(sizeof *pvt))) { + if (!(pvt = memget(sizeof *pvt))) { errno = ENOMEM; return (NULL); } memset(pvt, 0, sizeof *pvt); - if (!(nw = (struct irs_nw *)malloc(sizeof *nw))) { - free(pvt); + if (!(nw = memget(sizeof *nw))) { + memput(pvt, sizeof *pvt); errno = ENOMEM; return (NULL); } @@ -121,6 +127,8 @@ irs_dns_nw(struct irs_acc *this) { 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); } @@ -130,32 +138,47 @@ static void nw_close(struct irs_nw *this) { struct pvt *pvt = (struct pvt *)this->private; - free(pvt); - free(this); + 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; } - h_errno = NETDB_INTERNAL; + 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; } - h_errno = NETDB_INTERNAL; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); errno = EAFNOSUPPORT; return (NULL); } @@ -172,43 +195,80 @@ nw_rewind(struct irs_nw *this) { static void nw_minimize(struct irs_nw *this) { - /* NOOP */ + 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; - if ((_res.options & RES_INIT) == 0 && res_init() == -1) - return (NULL); - anslen = res_search(name, C_IN, T_PTR, ansbuf, sizeof ansbuf); + anslen = res_nsearch(pvt->res, name, C_IN, T_PTR, + ansbuf, sizeof ansbuf); if (anslen < 0) return (NULL); - return (get1101mask(get1101answer(this, ansbuf, anslen, by_name, - AF_INET, name, NULL, 0))); + 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) { - u_char ansbuf[MAXPACKET]; + 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; - h_errno = NETDB_INTERNAL; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); return (NULL); } if (make1101inaddr(net, len, qbuf, sizeof qbuf) < 0) return (NULL); - anslen = res_query(qbuf, C_IN, T_PTR, ansbuf, sizeof ansbuf); + anslen = res_nquery(pvt->res, qbuf, C_IN, T_PTR, + ansbuf, sizeof ansbuf); if (anslen < 0) return (NULL); - return (get1101mask(get1101answer(this, ansbuf, anslen, by_addr, - AF_INET, NULL, net, len))); + return (get1101mask(this, get1101answer(this, ansbuf, anslen, by_addr, + AF_INET, NULL, net, len))); } static struct nwent * @@ -225,7 +285,7 @@ get1101answer(struct irs_nw *this, /* Initialize, and parse header. */ eom = ansbuf + anslen; if (ansbuf + HFIXEDSZ > eom) { - h_errno = NO_RECOVERY; + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); return (NULL); } hp = (HEADER *)ansbuf; @@ -235,16 +295,16 @@ get1101answer(struct irs_nw *this, int n = dn_skipname(cp, eom); cp += n + QFIXEDSZ; if (n < 0 || cp > eom) { - h_errno = NO_RECOVERY; + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); return (NULL); } } ancount = ntohs(hp->ancount); if (!ancount) { if (hp->aa) - h_errno = HOST_NOT_FOUND; + RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); else - h_errno = TRY_AGAIN; + RES_SET_H_ERRNO(pvt->res, TRY_AGAIN); return (NULL); } @@ -264,7 +324,7 @@ get1101answer(struct irs_nw *this, int n = strlen(name) + 1; if (n > buflen) { - h_errno = NO_RECOVERY; + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); return (NULL); } pvt->net.n_name = strcpy(bp, name); @@ -277,7 +337,7 @@ get1101answer(struct irs_nw *this, int n = addrlen / 8 + ((addrlen % 8) != 0); if (INADDRSZ > buflen) { - h_errno = NO_RECOVERY; + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); return (NULL); } memset(bp, 0, INADDRSZ); @@ -298,9 +358,9 @@ get1101answer(struct irs_nw *this, int n = dn_expand(ansbuf, eom, cp, bp, buflen); cp += n; /* Owner */ - if (n < 0 || !res_dnok(bp) || + if (n < 0 || !maybe_dnok(pvt->res, bp) || cp + 3 * INT16SZ + INT32SZ > eom) { - h_errno = NO_RECOVERY; + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); return (NULL); } GETSHORT(type, cp); /* Type */ @@ -311,8 +371,8 @@ get1101answer(struct irs_nw *this, int nn; nn = dn_expand(ansbuf, eom, cp, bp, buflen); - if (nn < 0 || !res_hnok(bp) || nn != n) { - h_errno = NO_RECOVERY; + if (nn < 0 || !maybe_hnok(pvt->res, bp) || nn != n) { + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); return (NULL); } normalize_name(bp); @@ -320,7 +380,7 @@ get1101answer(struct irs_nw *this, case by_addr: { if (pvt->net.n_name == NULL) pvt->net.n_name = bp; - else if (strcasecmp(pvt->net.n_name, bp) == 0) + else if (ns_samename(pvt->net.n_name, bp) == 1) break; else *ap++ = bp; @@ -338,7 +398,7 @@ get1101answer(struct irs_nw *this, &b1, &b2, &b3, &b4) != 4) break; if (buflen < INADDRSZ) { - h_errno = NO_RECOVERY; + RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); return (NULL); } pvt->net.n_addr = bp; @@ -355,7 +415,7 @@ get1101answer(struct irs_nw *this, cp += n; /* RDATA */ } if (!haveanswer) { - h_errno = TRY_AGAIN; + RES_SET_H_ERRNO(pvt->res, TRY_AGAIN); return (NULL); } *ap = NULL; @@ -364,7 +424,8 @@ get1101answer(struct irs_nw *this, } static struct nwent * -get1101mask(struct nwent *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; @@ -379,7 +440,7 @@ get1101mask(struct nwent *nwent) { } /* Query for the A RR that would hold this network's mask. */ - anslen = res_query(qbuf, C_IN, T_A, ansbuf, sizeof ansbuf); + anslen = res_nquery(pvt->res, qbuf, C_IN, T_A, ansbuf, sizeof ansbuf); if (anslen < HFIXEDSZ) return (nwent); @@ -400,7 +461,7 @@ get1101mask(struct nwent *nwent) { while (--ancount >= 0 && cp < eom) { int n = dn_expand(ansbuf, eom, cp, owner, sizeof owner); - if (n < 0 || !res_dnok(owner)) + if (n < 0 || !maybe_dnok(pvt->res, owner)) break; cp += n; /* Owner */ if (cp + 3 * INT16SZ + INT32SZ > eom) @@ -412,7 +473,7 @@ get1101mask(struct nwent *nwent) { if (cp + n > eom) break; if (n == INADDRSZ && class == C_IN && type == T_A && - !strcasecmp(qbuf, owner)) { + ns_samename(qbuf, owner) == 1) { /* This A RR indicates the actual netmask. */ int nn, mm; @@ -485,3 +546,15 @@ normalize_name(char *name) { 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/contrib/bind/lib/irs/dns_p.h b/contrib/bind/lib/irs/dns_p.h index 5a4ef84..6b5fe11 100644 --- a/contrib/bind/lib/irs/dns_p.h +++ b/contrib/bind/lib/irs/dns_p.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,17 +16,24 @@ */ /* - * $Id: dns_p.h,v 1.7 1996/10/25 07:22:59 vixie Exp $ + * $Id: dns_p.h,v 1.11 1999/06/03 20:50:36 vixie 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; + void *hes_ctx; + struct __res_state *res; + void (*free_res) __P((void *)); }; /* diff --git a/contrib/bind/lib/irs/dns_pr.c b/contrib/bind/lib/irs/dns_pr.c index 2ca6aaf..77c6a93 100644 --- a/contrib/bind/lib/irs/dns_pr.c +++ b/contrib/bind/lib/irs/dns_pr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: dns_pr.c,v 1.9 1997/12/04 04:57:48 halley Exp $"; +static const char rcsid[] = "$Id: dns_pr.c,v 1.14 1999/09/04 22:06:14 vixie Exp $"; #endif /* Imports */ @@ -25,6 +25,8 @@ static const char rcsid[] = "$Id: dns_pr.c,v 1.9 1997/12/04 04:57:48 halley Exp #include <sys/types.h> #include <netinet/in.h> +#include <arpa/nameser.h> +#include <resolv.h> #include <stdio.h> #include <string.h> @@ -33,6 +35,7 @@ static const char rcsid[] = "$Id: dns_pr.c,v 1.9 1997/12/04 04:57:48 halley Exp #include <stdlib.h> #include <errno.h> +#include <isc/memcluster.h> #include <irs.h> #include "port_after.h" @@ -44,7 +47,7 @@ static const char rcsid[] = "$Id: dns_pr.c,v 1.9 1997/12/04 04:57:48 halley Exp /* Types. */ struct pvt { - struct dns_p * dns; + struct dns_p * dns; struct protoent proto; char * prbuf; }; @@ -57,6 +60,10 @@ 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 **); @@ -72,13 +79,13 @@ irs_dns_pr(struct irs_acc *this) { errno = ENODEV; return (NULL); } - if (!(pvt = malloc(sizeof *pvt))) { + if (!(pvt = memget(sizeof *pvt))) { errno = ENOMEM; return (NULL); } memset(pvt, 0, sizeof *pvt); - if (!(pr = malloc(sizeof *pr))) { - free(pvt); + if (!(pr = memget(sizeof *pr))) { + memput(pvt, sizeof *pvt); errno = ENOMEM; return (NULL); } @@ -91,6 +98,8 @@ irs_dns_pr(struct irs_acc *this) { 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); } @@ -104,7 +113,9 @@ pr_close(struct irs_pr *this) { free(pvt->proto.p_aliases); if (pvt->prbuf) free(pvt->prbuf); - free(this); + + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); } static struct protoent * @@ -155,6 +166,23 @@ pr_minimize(struct irs_pr *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 * diff --git a/contrib/bind/lib/irs/dns_pw.c b/contrib/bind/lib/irs/dns_pw.c index 97612d1..5344c6e 100644 --- a/contrib/bind/lib/irs/dns_pw.c +++ b/contrib/bind/lib/irs/dns_pw.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: dns_pw.c,v 1.13 1997/12/04 04:57:48 halley Exp $"; +static const char rcsid[] = "$Id: dns_pw.c,v 1.18 1999/09/04 22:06:14 vixie Exp $"; #endif #include "port_before.h" @@ -30,6 +30,13 @@ static int __bind_irs_pw_unneeded; #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" @@ -41,7 +48,7 @@ static int __bind_irs_pw_unneeded; /* Types. */ struct pvt { - struct dns_p *dns; + struct dns_p * dns; struct passwd passwd; char * pwbuf; }; @@ -54,6 +61,10 @@ 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 *); @@ -70,14 +81,14 @@ irs_dns_pw(struct irs_acc *this) { errno = ENODEV; return (NULL); } - if (!(pvt = malloc(sizeof *pvt))) { + if (!(pvt = memget(sizeof *pvt))) { errno = ENOMEM; return (NULL); } memset(pvt, 0, sizeof *pvt); pvt->dns = dns; - if (!(pw = malloc(sizeof *pw))) { - free(pvt); + if (!(pw = memget(sizeof *pw))) { + memput(pvt, sizeof *pvt); errno = ENOMEM; return (NULL); } @@ -89,6 +100,8 @@ irs_dns_pw(struct irs_acc *this) { 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); } @@ -100,7 +113,9 @@ pw_close(struct irs_pw *this) { if (pvt->pwbuf) free(pvt->pwbuf); - free(this); + + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); } static struct passwd * @@ -132,6 +147,23 @@ pw_minimize(struct irs_pw *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 * diff --git a/contrib/bind/lib/irs/dns_sv.c b/contrib/bind/lib/irs/dns_sv.c index 064e80a..ea0ba70 100644 --- a/contrib/bind/lib/irs/dns_sv.c +++ b/contrib/bind/lib/irs/dns_sv.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: dns_sv.c,v 1.12 1997/12/04 04:57:49 halley Exp $"; +static const char rcsid[] = "$Id: dns_sv.c,v 1.17 1999/09/04 22:06:14 vixie Exp $"; #endif /* Imports */ @@ -33,6 +33,12 @@ static const char rcsid[] = "$Id: dns_sv.c,v 1.12 1997/12/04 04:57:49 halley Exp #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" @@ -44,9 +50,11 @@ static const char rcsid[] = "$Id: dns_sv.c,v 1.12 1997/12/04 04:57:49 halley Exp /* Definitions */ struct pvt { - struct dns_p * dns; + struct dns_p * dns; struct servent serv; char * svbuf; + struct __res_state * res; + void (*free_res)(void *); }; /* Forward. */ @@ -58,6 +66,10 @@ 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 *); +static struct __res_state * sv_res_get(struct irs_sv *); +static void sv_res_set(struct irs_sv *, + struct __res_state *, + void (*)(void *)); static struct servent * parse_hes_list(struct irs_sv *, char **, const char *); @@ -74,14 +86,14 @@ irs_dns_sv(struct irs_acc *this) { errno = ENODEV; return (NULL); } - if (!(pvt = (struct pvt *)malloc(sizeof *pvt))) { + if (!(pvt = memget(sizeof *pvt))) { errno = ENOMEM; return (NULL); } memset(pvt, 0, sizeof *pvt); pvt->dns = dns; - if (!(sv = malloc(sizeof *sv))) { - free(pvt); + if (!(sv = memget(sizeof *sv))) { + memput(pvt, sizeof *pvt); errno = ENOMEM; return (NULL); } @@ -93,6 +105,8 @@ irs_dns_sv(struct irs_acc *this) { sv->rewind = sv_rewind; sv->close = sv_close; sv->minimize = sv_minimize; + sv->res_get = sv_res_get; + sv->res_set = sv_res_set; return (sv); } @@ -106,7 +120,11 @@ sv_close(struct irs_sv *this) { free(pvt->serv.s_aliases); if (pvt->svbuf) free(pvt->svbuf); - free(this); + + if (pvt->res && pvt->free_res) + (*pvt->free_res)(pvt->res); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); } static struct servent * @@ -248,3 +266,20 @@ static void sv_minimize(struct irs_sv *this) { /* NOOP */ } + +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); +} diff --git a/contrib/bind/lib/irs/gai_strerror.c b/contrib/bind/lib/irs/gai_strerror.c new file mode 100644 index 0000000..f56c6f5 --- /dev/null +++ b/contrib/bind/lib/irs/gai_strerror.c @@ -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> + +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/contrib/bind/lib/irs/gen.c b/contrib/bind/lib/irs/gen.c index 325a526..fe41088 100644 --- a/contrib/bind/lib/irs/gen.c +++ b/contrib/bind/lib/irs/gen.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1998 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if !defined(LINT) && !defined(CODECENTER) -static char rcsid[] = "$Id: gen.c,v 1.18 1998/03/21 00:59:46 halley Exp $"; +static const char rcsid[] = "$Id: gen.c,v 1.25 1999/10/13 16:39:29 vixie Exp $"; #endif /* @@ -35,13 +35,19 @@ static char rcsid[] = "$Id: gen.c,v 1.18 1998/03/21 00:59:46 halley Exp $"; #include "port_before.h" -#include <assert.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" @@ -60,6 +66,7 @@ static const struct nameval acc_names[irs_nacc+1] = { { "local", irs_lcl }, { "dns", irs_dns }, { "nis", irs_nis }, + { "irp", irs_irp }, { NULL, irs_nacc } }; @@ -73,6 +80,7 @@ static const accinit accs[irs_nacc+1] = { #else NULL, #endif + irs_irp_acc, NULL }; @@ -96,8 +104,11 @@ static const struct nameval option_names[] = { /* 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 *); +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, @@ -106,25 +117,27 @@ static int add_rule(struct gen_p *, /* Public */ struct irs_acc * -irs_gen_acc(const char *options) { +irs_gen_acc(const char *options, const char *conf_file) { struct irs_acc *acc; struct gen_p *irs; - if (!(acc = malloc(sizeof *acc))) { + if (!(acc = memget(sizeof *acc))) { errno = ENOMEM; return (NULL); } memset(acc, 0x5e, sizeof *acc); - if (!(irs = malloc(sizeof *irs))) { + if (!(irs = memget(sizeof *irs))) { errno = ENOMEM; - free(acc); + 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); + init_map_rules(irs, conf_file); acc->private = irs; #ifdef WANT_IRS_GR acc->gr_map = irs_gen_gr; @@ -141,12 +154,65 @@ irs_gen_acc(const char *options) { 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; @@ -182,11 +248,14 @@ gen_close(struct irs_acc *this) { /* 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. */ - free(irs); + memput(irs, sizeof *irs); /* The object. */ - free(this); + memput(this, sizeof *this); } /* Private */ @@ -205,7 +274,7 @@ static struct irs_rule * release_rule(struct irs_rule *rule) { struct irs_rule *next = rule->next; - free(rule); + memput(rule, sizeof *rule); return (next); } @@ -231,7 +300,7 @@ add_rule(struct gen_p *irs, if (acc == irs_nis) return (-1); #endif - new = (struct irs_rule *)malloc(sizeof *new); + new = memget(sizeof *new); if (new == NULL) return (-1); memset(new, 0x5e, sizeof *new); @@ -310,11 +379,15 @@ default_map_rules(struct gen_p *irs) { } static void -init_map_rules(struct gen_p *irs) { +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 = fopen(_PATH_IRS_CONF, "r")) == NULL) { + 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; } @@ -337,13 +410,13 @@ init_map_rules(struct gen_p *irs) { options[0] = '\0'; n = find_name(mapname, map_names); - assert(n < irs_nmap); + INSIST(n < irs_nmap); if (n < 0) continue; map = (enum irs_map_id) n; n = find_name(accname, acc_names); - assert(n < irs_nacc); + INSIST(n < irs_nacc); if (n < 0) continue; acc = (enum irs_acc_id) n; diff --git a/contrib/bind/lib/irs/gen_gr.c b/contrib/bind/lib/irs/gen_gr.c index b0c61a8..ae23d2c 100644 --- a/contrib/bind/lib/irs/gen_gr.c +++ b/contrib/bind/lib/irs/gen_gr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1998 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if !defined(LINT) && !defined(CODECENTER) -static char rcsid[] = "$Id: gen_gr.c,v 1.16 1998/03/21 00:59:47 halley Exp $"; +static const char rcsid[] = "$Id: gen_gr.c,v 1.21 1999/10/13 16:39:29 vixie Exp $"; #endif /* Imports */ @@ -29,12 +29,17 @@ static int __bind_irs_gr_unneeded; #include <sys/types.h> -#include <assert.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" @@ -59,6 +64,8 @@ struct pvt { size_t nmemb; /* Malloc'd max index of gr_mem[]. */ char * membuf; size_t membufsize; + struct __res_state * res; + void (*free_res)(void *); }; /* Forward */ @@ -71,6 +78,10 @@ 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); @@ -89,13 +100,13 @@ irs_gen_gr(struct irs_acc *this) { struct irs_gr *gr; struct pvt *pvt; - if (!(gr = malloc(sizeof *gr))) { + if (!(gr = memget(sizeof *gr))) { errno = ENOMEM; return (NULL); } memset(gr, 0x5e, sizeof *gr); - if (!(pvt = malloc(sizeof *pvt))) { - free(gr); + if (!(pvt = memget(sizeof *pvt))) { + memput(gr, sizeof *gr); errno = ENOMEM; return (NULL); } @@ -110,6 +121,8 @@ irs_gen_gr(struct irs_acc *this) { 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); } @@ -119,8 +132,8 @@ static void gr_close(struct irs_gr *this) { struct pvt *pvt = (struct pvt *)this->private; - free(pvt); - free(this); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); } static struct group * @@ -266,6 +279,46 @@ gr_minimize(struct irs_gr *this) { } } +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 @@ -310,7 +363,7 @@ grmerge(struct irs_gr *this, const struct group *src, int preserve) { * Enlarge destination membuf; cp points at new portion. */ n = sizenew(pvt->group.gr_mem, src->gr_mem); - assert((nnew == 0) == (n == 0)); + INSIST((nnew == 0) == (n == 0)); if (!preserve) { n += strlen(src->gr_name) + 1; n += strlen(src->gr_passwd) + 1; @@ -346,7 +399,7 @@ grmerge(struct irs_gr *this, const struct group *src, int preserve) { strcpy(cp, src->gr_passwd); cp += strlen(src->gr_passwd) + 1; } - assert(cp >= pvt->membuf && cp <= &pvt->membuf[pvt->membufsize]); + INSIST(cp >= pvt->membuf && cp <= &pvt->membuf[pvt->membufsize]); } static int diff --git a/contrib/bind/lib/irs/gen_ho.c b/contrib/bind/lib/irs/gen_ho.c index 7da829d..9e7a429 100644 --- a/contrib/bind/lib/irs/gen_ho.c +++ b/contrib/bind/lib/irs/gen_ho.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,19 +16,26 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char rcsid[] = "$Id: gen_ho.c,v 1.9 1997/12/04 04:57:50 halley Exp $"; +static const char rcsid[] = "$Id: gen_ho.c,v 1.15 1999/10/13 16:39:29 vixie 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" @@ -36,14 +43,14 @@ static char rcsid[] = "$Id: gen_ho.c,v 1.9 1997/12/04 04:57:50 halley Exp $"; #include "irs_p.h" #include "gen_p.h" -extern int h_errno; - /* Definitions */ struct pvt { struct irs_rule * rules; struct irs_rule * rule; struct irs_ho * ho; + struct __res_state * res; + void (*free_res)(void *); }; /* Forwards */ @@ -57,6 +64,12 @@ static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr, 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 int init(struct irs_ho *this); /* Exports */ @@ -66,17 +79,17 @@ irs_gen_ho(struct irs_acc *this) { struct irs_ho *ho; struct pvt *pvt; - if (!(ho = malloc(sizeof *ho))) { + if (!(pvt = memget(sizeof *pvt))) { errno = ENOMEM; return (NULL); } - memset(ho, 0x5e, sizeof *ho); - if (!(pvt = (struct pvt *)malloc(sizeof *pvt))) { - free(ho); + memset(pvt, 0, sizeof *pvt); + if (!(ho = memget(sizeof *ho))) { + memput(pvt, sizeof *pvt); errno = ENOMEM; return (NULL); } - memset(pvt, 0, sizeof *pvt); + memset(ho, 0x5e, sizeof *ho); pvt->rules = accpvt->map_rules[irs_ho]; pvt->rule = pvt->rules; ho->private = pvt; @@ -87,6 +100,8 @@ irs_gen_ho(struct irs_acc *this) { ho->next = ho_next; ho->rewind = ho_rewind; ho->minimize = ho_minimize; + ho->res_get = ho_res_get; + ho->res_set = ho_res_set; return (ho); } @@ -96,8 +111,11 @@ static void ho_close(struct irs_ho *this) { struct pvt *pvt = (struct pvt *)this->private; - free(pvt); - free(this); + 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 * @@ -106,14 +124,25 @@ ho_byname(struct irs_ho *this, const char *name) { 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; - h_errno = NETDB_INTERNAL; + 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; /* @@ -121,12 +150,14 @@ ho_byname(struct irs_ho *this, const char *name) { * 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 + * H_ERRNO is TRY_AGAIN, we continue to try other lookup * functions, otherwise we return the TRY_AGAIN error. */ - if (h_errno != TRY_AGAIN || errno != 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); } @@ -136,23 +167,36 @@ ho_byname2(struct irs_ho *this, const char *name, int af) { 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; - h_errno = NETDB_INTERNAL; + 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 (h_errno != TRY_AGAIN || errno != 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); } @@ -162,23 +206,38 @@ ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) { 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; - h_errno = NETDB_INTERNAL; + 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 (h_errno != TRY_AGAIN || errno != 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); } @@ -221,9 +280,64 @@ 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 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/contrib/bind/lib/irs/gen_ng.c b/contrib/bind/lib/irs/gen_ng.c index 3958380..064d616 100644 --- a/contrib/bind/lib/irs/gen_ng.c +++ b/contrib/bind/lib/irs/gen_ng.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if !defined(LINT) && !defined(CODECENTER) -static char rcsid[] = "$Id: gen_ng.c,v 1.9 1997/12/04 04:57:50 halley Exp $"; +static const char rcsid[] = "$Id: gen_ng.c,v 1.14 1999/10/13 16:39:29 vixie Exp $"; #endif /* Imports */ @@ -25,10 +25,15 @@ static char rcsid[] = "$Id: gen_ng.c,v 1.9 1997/12/04 04:57:50 halley Exp $"; #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" @@ -62,13 +67,13 @@ irs_gen_ng(struct irs_acc *this) { struct irs_ng *ng; struct pvt *pvt; - if (!(ng = malloc(sizeof *ng))) { + if (!(ng = memget(sizeof *ng))) { errno = ENOMEM; return (NULL); } memset(ng, 0x5e, sizeof *ng); - if (!(pvt = malloc(sizeof *pvt))) { - free(ng); + if (!(pvt = memget(sizeof *pvt))) { + memput(ng, sizeof *ng); errno = ENOMEM; return (NULL); } @@ -90,10 +95,11 @@ static void ng_close(struct irs_ng *this) { struct pvt *pvt = (struct pvt *)this->private; + ng_minimize(this); if (pvt->curgroup) free(pvt->curgroup); - free(pvt); - free(this); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); } static int diff --git a/contrib/bind/lib/irs/gen_nw.c b/contrib/bind/lib/irs/gen_nw.c index 8ae8074..fad436c 100644 --- a/contrib/bind/lib/irs/gen_nw.c +++ b/contrib/bind/lib/irs/gen_nw.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if !defined(LINT) && !defined(CODECENTER) -static char rcsid[] = "$Id: gen_nw.c,v 1.8 1997/12/04 04:57:50 halley Exp $"; +static const char rcsid[] = "$Id: gen_nw.c,v 1.13 1999/10/13 16:39:29 vixie Exp $"; #endif /* Imports */ @@ -25,10 +25,15 @@ static char rcsid[] = "$Id: gen_nw.c,v 1.8 1997/12/04 04:57:50 halley Exp $"; #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" @@ -41,6 +46,8 @@ static char rcsid[] = "$Id: gen_nw.c,v 1.8 1997/12/04 04:57:50 halley Exp $"; struct pvt { struct irs_rule * rules; struct irs_rule * rule; + struct __res_state * res; + void (*free_res)(void *); }; /* Forward */ @@ -51,6 +58,12 @@ 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 */ @@ -60,17 +73,17 @@ irs_gen_nw(struct irs_acc *this) { struct irs_nw *nw; struct pvt *pvt; - if (!(nw = (struct irs_nw *)malloc(sizeof *nw))) { + if (!(pvt = memget(sizeof *pvt))) { errno = ENOMEM; return (NULL); } - memset(nw, 0x5e, sizeof *nw); - if (!(pvt = (struct pvt *)malloc(sizeof *pvt))) { - free(nw); + memset(pvt, 0, sizeof *pvt); + if (!(nw = memget(sizeof *nw))) { + memput(pvt, sizeof *pvt); errno = ENOMEM; return (NULL); } - memset(pvt, 0, sizeof *pvt); + memset(nw, 0x5e, sizeof *nw); pvt->rules = accpvt->map_rules[irs_nw]; pvt->rule = pvt->rules; nw->private = pvt; @@ -80,6 +93,8 @@ irs_gen_nw(struct irs_acc *this) { 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); } @@ -89,8 +104,13 @@ static void nw_close(struct irs_nw *this) { struct pvt *pvt = (struct pvt *)this->private; - free(pvt); - free(this); + 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 * @@ -99,6 +119,9 @@ nw_next(struct irs_nw *this) { 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); @@ -122,13 +145,17 @@ nw_byname(struct irs_nw *this, const char *name, int type) { 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; - h_errno = NETDB_INTERNAL; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); rval = (*nw->byname)(nw, name, type); if (rval != NULL) return (rval); - if (h_errno != TRY_AGAIN && !(rule->flags & IRS_CONTINUE)) + if (pvt->res->res_h_errno != TRY_AGAIN && + !(rule->flags & IRS_CONTINUE)) break; } return (NULL); @@ -141,13 +168,17 @@ nw_byaddr(struct irs_nw *this, void *net, int length, int type) { 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; - h_errno = NETDB_INTERNAL; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); rval = (*nw->byaddr)(nw, net, length, type); if (rval != NULL) return (rval); - if (h_errno != TRY_AGAIN && !(rule->flags & IRS_CONTINUE)) + if (pvt->res->res_h_errno != TRY_AGAIN && + !(rule->flags & IRS_CONTINUE)) break; } return (NULL); @@ -170,9 +201,62 @@ 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/contrib/bind/lib/irs/gen_p.h b/contrib/bind/lib/irs/gen_p.h index 92e115d..b8210b0 100644 --- a/contrib/bind/lib/irs/gen_p.h +++ b/contrib/bind/lib/irs/gen_p.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ /* - * $Id: gen_p.h,v 1.7 1996/11/21 10:28:15 vixie Exp $ + * $Id: gen_p.h,v 1.10 1999/01/18 07:46:50 vixie Exp $ */ /* Notes: @@ -43,6 +43,7 @@ enum irs_acc_id { irs_lcl, /* Local. */ irs_dns, /* DNS or Hesiod. */ irs_nis, /* Sun NIS ("YP"). */ + irs_irp, /* IR protocol. */ irs_nacc }; @@ -92,13 +93,15 @@ struct gen_p { const 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 *)); +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 *)); diff --git a/contrib/bind/lib/irs/gen_pr.c b/contrib/bind/lib/irs/gen_pr.c index 096be51..de09571 100644 --- a/contrib/bind/lib/irs/gen_pr.c +++ b/contrib/bind/lib/irs/gen_pr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if !defined(LINT) && !defined(CODECENTER) -static char rcsid[] = "$Id: gen_pr.c,v 1.8 1997/12/04 04:57:51 halley Exp $"; +static const char rcsid[] = "$Id: gen_pr.c,v 1.12 1999/10/13 16:39:30 vixie Exp $"; #endif /* Imports */ @@ -24,11 +24,15 @@ static char rcsid[] = "$Id: gen_pr.c,v 1.8 1997/12/04 04:57:51 halley Exp $"; #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" @@ -41,6 +45,8 @@ static char rcsid[] = "$Id: gen_pr.c,v 1.8 1997/12/04 04:57:51 halley Exp $"; struct pvt { struct irs_rule * rules; struct irs_rule * rule; + struct __res_state * res; + void (*free_res)(void *); }; /* Forward */ @@ -51,6 +57,10 @@ 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 */ @@ -60,13 +70,13 @@ irs_gen_pr(struct irs_acc *this) { struct irs_pr *pr; struct pvt *pvt; - if (!(pr = (struct irs_pr *)malloc(sizeof *pr))) { + if (!(pr = memget(sizeof *pr))) { errno = ENOMEM; return (NULL); } memset(pr, 0x5e, sizeof *pr); - if (!(pvt = (struct pvt *)malloc(sizeof *pvt))) { - free(pr); + if (!(pvt = memget(sizeof *pvt))) { + memput(pr, sizeof *pr); errno = ENOMEM; return (NULL); } @@ -80,6 +90,8 @@ irs_gen_pr(struct irs_acc *this) { 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); } @@ -89,8 +101,8 @@ static void pr_close(struct irs_pr *this) { struct pvt *pvt = (struct pvt *)this->private; - free(pvt); - free(this); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); } static struct protoent * @@ -172,3 +184,43 @@ pr_minimize(struct irs_pr *this) { (*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/contrib/bind/lib/irs/gen_pw.c b/contrib/bind/lib/irs/gen_pw.c index aaa82df..d80a64b 100644 --- a/contrib/bind/lib/irs/gen_pw.c +++ b/contrib/bind/lib/irs/gen_pw.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if !defined(LINT) && !defined(CODECENTER) -static char rcsid[] = "$Id: gen_pw.c,v 1.10 1997/12/04 04:57:51 halley Exp $"; +static const char rcsid[] = "$Id: gen_pw.c,v 1.14 1999/10/13 16:39:30 vixie Exp $"; #endif /* Imports */ @@ -28,12 +28,16 @@ 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" @@ -46,6 +50,8 @@ static int __bind_irs_pw_unneeded; struct pvt { struct irs_rule * rules; struct irs_rule * rule; + struct __res_state * res; + void (*free_res)(void *); }; /* Forward */ @@ -56,6 +62,10 @@ 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 */ @@ -65,13 +75,13 @@ irs_gen_pw(struct irs_acc *this) { struct irs_pw *pw; struct pvt *pvt; - if (!(pw = (struct irs_pw *)malloc(sizeof *pw))) { + if (!(pw = memget(sizeof *pw))) { errno = ENOMEM; return (NULL); } memset(pw, 0x5e, sizeof *pw); - if (!(pvt = (struct pvt *)malloc(sizeof *pvt))) { - free(pw); + if (!(pvt = memget(sizeof *pvt))) { + memput(pw, sizeof *pvt); errno = ENOMEM; return (NULL); } @@ -85,6 +95,8 @@ irs_gen_pw(struct irs_acc *this) { 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); } @@ -94,8 +106,8 @@ static void pw_close(struct irs_pw *this) { struct pvt *pvt = (struct pvt *)this->private; - free(pvt); - free(this); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); } static struct passwd * @@ -178,4 +190,44 @@ pw_minimize(struct irs_pw *this) { } } +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/contrib/bind/lib/irs/gen_sv.c b/contrib/bind/lib/irs/gen_sv.c index 22f0cde..e0c1cb6 100644 --- a/contrib/bind/lib/irs/gen_sv.c +++ b/contrib/bind/lib/irs/gen_sv.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if !defined(LINT) && !defined(CODECENTER) -static char rcsid[] = "$Id: gen_sv.c,v 1.8 1997/12/04 04:57:52 halley Exp $"; +static const char rcsid[] = "$Id: gen_sv.c,v 1.12 1999/10/13 16:39:30 vixie Exp $"; #endif /* Imports */ @@ -24,11 +24,15 @@ static char rcsid[] = "$Id: gen_sv.c,v 1.8 1997/12/04 04:57:52 halley Exp $"; #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" @@ -41,6 +45,8 @@ static char rcsid[] = "$Id: gen_sv.c,v 1.8 1997/12/04 04:57:52 halley Exp $"; struct pvt { struct irs_rule * rules; struct irs_rule * rule; + struct __res_state * res; + void (*free_res)(void *); }; /* Forward */ @@ -52,6 +58,10 @@ static struct servent * sv_byname(struct irs_sv *, 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 */ @@ -61,13 +71,13 @@ irs_gen_sv(struct irs_acc *this) { struct irs_sv *sv; struct pvt *pvt; - if (!(sv = (struct irs_sv *)malloc(sizeof *sv))) { + if (!(sv = memget(sizeof *sv))) { errno = ENOMEM; return (NULL); } memset(sv, 0x5e, sizeof *sv); - if (!(pvt = (struct pvt *)malloc(sizeof *pvt))) { - free(sv); + if (!(pvt = memget(sizeof *pvt))) { + memput(sv, sizeof *sv); errno = ENOMEM; return (NULL); } @@ -81,6 +91,8 @@ irs_gen_sv(struct irs_acc *this) { 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); } @@ -90,8 +102,8 @@ static void sv_close(struct irs_sv *this) { struct pvt *pvt = (struct pvt *)this->private; - free(pvt); - free(this); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); } static struct servent * @@ -173,3 +185,43 @@ sv_minimize(struct irs_sv *this) { (*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/contrib/bind/lib/irs/getaddrinfo.c b/contrib/bind/lib/irs/getaddrinfo.c new file mode 100644 index 0000000..f95a681 --- /dev/null +++ b/contrib/bind/lib/irs/getaddrinfo.c @@ -0,0 +1,505 @@ +/*- + * Copyright (c) 1997 Berkeley Software Design, Inc. All rights reserved. + * The Berkeley Software Design Inc. software License Agreement specifies + * the terms and conditions for redistribution. + * + * BSDI $Id: getaddrinfo.c,v 8.3 1999/06/11 01:25:58 vixie Exp $ + */ + +#include <port_before.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <netinet/in.h> +#include <netdb.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <arpa/nameser.h> +#include <resolv.h> +#include <arpa/inet.h> +#include <port_after.h> + +#define SA(addr) ((struct sockaddr *)(addr)) +#define SIN(addr) ((struct sockaddr_in *)(addr)) +#define SIN6(addr) ((struct sockaddr_in6 *)(addr)) +#define SUN(addr) ((struct sockaddr_un *)(addr)) + +static struct addrinfo + *ai_reverse(struct addrinfo *oai), + *ai_clone(struct addrinfo *oai, int family), + *ai_alloc(int family, int addrlen); +#ifdef AF_LOCAL +static int get_local(const char *name, int socktype, struct addrinfo **res); +#endif + +static int add_ipv4(const char *hostname, int flags, struct addrinfo **aip, + int socktype, int port); +static int add_ipv6(const char *hostname, int flags, struct addrinfo **aip, + int socktype, int port); +static void set_order(int, int (**)()); + +#define FOUND_IPV4 0x1 +#define FOUND_IPV6 0x2 +#define FOUND_MAX 2 + +int +getaddrinfo(const char *hostname, const char *servname, + const struct addrinfo *hints, struct addrinfo **res) +{ + struct servent *sp; + char *proto; + int family, socktype, flags, protocol; + struct addrinfo *ai, *ai_list; + int port, err, i; + int (*net_order[FOUND_MAX+1])(); + + if (hostname == NULL && servname == NULL) + return (EAI_NONAME); + + proto = NULL; + if (hints != NULL) { + if (hints->ai_flags & ~(AI_MASK)) + return (EAI_BADFLAGS); + if (hints->ai_addrlen || hints->ai_canonname || + hints->ai_addr || hints->ai_next) { + errno = EINVAL; + return (EAI_SYSTEM); + } + family = hints->ai_family; + socktype = hints->ai_socktype; + protocol = hints->ai_protocol; + flags = hints->ai_flags; + switch (family) { + case AF_UNSPEC: + switch (hints->ai_socktype) { + case SOCK_STREAM: proto = "tcp"; break; + case SOCK_DGRAM: proto = "udp"; break; + } + break; + case AF_INET: + case AF_INET6: + switch (hints->ai_socktype) { + case 0: break; + case SOCK_STREAM: proto = "tcp"; break; + case SOCK_DGRAM: proto = "udp"; break; + case SOCK_RAW: break; + default: return (EAI_SOCKTYPE); + } + break; +#ifdef AF_LOCAL + case AF_LOCAL: + switch (hints->ai_socktype) { + case 0: break; + case SOCK_STREAM: break; + case SOCK_DGRAM: break; + default: return (EAI_SOCKTYPE); + } + break; +#endif + default: + return (EAI_FAMILY); + } + } else { + protocol = 0; + family = 0; + socktype = 0; + flags = 0; + } + +#ifdef AF_LOCAL + /* + * First, deal with AF_LOCAL. If the family was not set, + * then assume AF_LOCAL if the first character of the + * hostname/servname is '/'. + */ + + if (hostname && + (family == AF_LOCAL || (family == 0 && *hostname == '/'))) + return (get_local(hostname, socktype, res)); + + if (servname && + (family == AF_LOCAL || (family == 0 && *servname == '/'))) + return (get_local(servname, socktype, res)); +#endif + + /* + * Ok, only AF_INET and AF_INET6 left. + */ + ai_list = NULL; + + /* + * First, look up the service name (port) if it was + * requested. If the socket type wasn't specified, then + * try and figure it out. + */ + if (servname) { + char *e; + + port = strtol(servname, &e, 10); + if (*e == '\0') { + if (socktype == 0) + return (EAI_SOCKTYPE); + if (port < 0 || port > 65535) + return (EAI_SERVICE); + port = htons(port); + } else { + sp = getservbyname(servname, proto); + if (sp == NULL) + return (EAI_SERVICE); + port = sp->s_port; + if (socktype == 0) { + if (strcmp(sp->s_proto, "tcp")) + socktype = SOCK_STREAM; + else if (strcmp(sp->s_proto, "udp")) + socktype = SOCK_DGRAM; + } + } + } else + port = 0; + + /* + * Next, deal with just a service name, and no hostname. + * (we verified that one of them was non-null up above). + */ + if (hostname == NULL && (flags & AI_PASSIVE) != 0) { + if (family == AF_INET || family == 0) { + ai = ai_alloc(AF_INET, sizeof(struct sockaddr_in)); + if (ai == NULL) + return (EAI_MEMORY); + ai->ai_socktype = socktype; + ai->ai_protocol = protocol; + SIN(ai->ai_addr)->sin_port = port; + ai->ai_next = ai_list; + ai_list = ai; + } + + if (family == AF_INET6 || family == 0) { + ai = ai_alloc(AF_INET6, sizeof(struct sockaddr_in6)); + if (ai == NULL) { + freeaddrinfo(ai_list); + return (EAI_MEMORY); + } + ai->ai_socktype = socktype; + ai->ai_protocol = protocol; + SIN6(ai->ai_addr)->sin6_port = port; + ai->ai_next = ai_list; + ai_list = ai; + } + + *res = ai_list; + return (0); + } + + /* + * If the family isn't specified or AI_NUMERICHOST specified, + * check first to see if it * is a numeric address. + * Though the gethostbyname2() routine + * will recognize numeric addresses, it will only recognize + * the format that it is being called for. Thus, a numeric + * AF_INET address will be treated by the AF_INET6 call as + * a domain name, and vice versa. Checking for both numerics + * here avoids that. + */ + if (hostname != NULL && + (family == 0 || (flags & AI_NUMERICHOST) != 0)) { + char abuf[sizeof(struct in6_addr)]; + char nbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx00")]; + int addrsize, addroff; + + if (inet_aton(hostname, (struct in_addr *)abuf)) { + if (family == AF_INET6) { + /* Convert to a V4 mapped address */ + struct in6_addr *a6 = (struct in6_addr *)abuf; + memcpy(&a6->s6_addr[12], &a6->s6_addr[0], 4); + memset(&a6->s6_addr[10], 0xff, 2); + memset(&a6->s6_addr[0], 0, 10); + goto inet6_addr; + } + addrsize = sizeof(struct in_addr); + addroff = (char *)(&SIN(0)->sin_addr) - (char *)0; + family = AF_INET; + goto common; + + } else if (inet_pton(AF_INET6, hostname, abuf)) { + if (family && family != AF_INET6) + return (EAI_NONAME); + inet6_addr: + addrsize = sizeof(struct in6_addr); + addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0; + family = AF_INET6; + + common: + if ((ai = ai_clone(ai_list, family)) == NULL) + return (EAI_MEMORY); + ai_list = ai; + ai->ai_socktype = socktype; + SIN(ai->ai_addr)->sin_port = port; + memcpy((char *)ai->ai_addr + addroff, abuf, addrsize); + if (flags & AI_CANONNAME) { + inet_ntop(family, abuf, nbuf, sizeof(nbuf)); + ai->ai_canonname = strdup(nbuf); + } + goto done; + } else if ((flags & AI_NUMERICHOST) != 0){ + return (EAI_NONAME); + } + } + + set_order(family, net_order); + for (i = 0; i < FOUND_MAX; i++) { + if (net_order[i] == NULL) + break; + if ((err = (net_order[i])(hostname, flags, &ai_list, + socktype, port)) != 0) + return(err); + } + + if (ai_list == NULL) + return (EAI_NODATA); + +done: + ai_list = ai_reverse(ai_list); + + *res = ai_list; + return (0); +} + +static void +set_order(family, net_order) + int family; + int (**net_order)(); +{ + char *order, *tok; + int found; + + if (family) { + switch (family) { + case AF_INET: + *net_order++ = add_ipv4; + break; + case AF_INET6: + *net_order++ = add_ipv6; + break; + } + } else { + order = getenv("NET_ORDER"); + found = 0; + while (order != NULL) { + /* We ignore any unknown names. */ + tok = strsep(&order, ":"); + if (strcasecmp(tok, "inet6") == 0) { + if ((found & FOUND_IPV6) == 0) + *net_order++ = add_ipv6; + found |= FOUND_IPV6; + } else if (strcasecmp(tok, "inet") == 0 || + strcasecmp(tok, "inet4") == 0) { + if ((found & FOUND_IPV4) == 0) + *net_order++ = add_ipv4; + found |= FOUND_IPV4; + } + } + + /* Add in anything that we didn't find */ + if ((found & FOUND_IPV4) == 0) + *net_order++ = add_ipv4; + if ((found & FOUND_IPV6) == 0) + *net_order++ = add_ipv6; + } + *net_order = NULL; + return; +} + +static char v4_loop[4] = { 127, 0, 0, 1 }; + +static int +add_ipv4(const char *hostname, int flags, struct addrinfo **aip, + int socktype, int port) +{ + struct addrinfo *ai; + struct hostent *hp; + char **addr; + + if (hostname == NULL && (flags & AI_PASSIVE) == 0) { + if ((ai = ai_clone(*aip, AF_INET)) == NULL) { + freeaddrinfo(*aip); + return(EAI_MEMORY); + } + + *aip = ai; + ai->ai_socktype = socktype; + SIN(ai->ai_addr)->sin_port = port; + memcpy(&SIN(ai->ai_addr)->sin_addr, v4_loop, 4); + } else if ((hp = gethostbyname2(hostname, AF_INET)) != NULL) { + for (addr = hp->h_addr_list; *addr; addr++) { + if ((ai = ai_clone(*aip, hp->h_addrtype)) == NULL) { + freeaddrinfo(*aip); + return(EAI_MEMORY); + } + *aip = ai; + ai->ai_socktype = socktype; + + /* We get IPv6 addresses if RES_USE_INET6 is set */ + if (hp->h_addrtype == AF_INET6) { + SIN6(ai->ai_addr)->sin6_port = port; + memcpy(&SIN6(ai->ai_addr)->sin6_addr, *addr, + hp->h_length); + } else { + SIN(ai->ai_addr)->sin_port = port; + memcpy(&SIN(ai->ai_addr)->sin_addr, *addr, + hp->h_length); + } + if (flags & AI_CANONNAME) + ai->ai_canonname = strdup(hp->h_name); + } + } + return(0); +} + +static char v6_loop[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + +static int +add_ipv6(const char *hostname, int flags, struct addrinfo **aip, + int socktype, int port) +{ + struct addrinfo *ai; + struct hostent *hp; + char **addr; + + if (hostname == NULL && (flags & AI_PASSIVE) == 0) { + if ((ai = ai_clone(*aip, AF_INET6)) == NULL) { + freeaddrinfo(*aip); + return(EAI_MEMORY); + } + + *aip = ai; + ai->ai_socktype = socktype; + SIN6(ai->ai_addr)->sin6_port = port; + memcpy(&SIN6(ai->ai_addr)->sin6_addr, v6_loop, 16); + } else if ((hp = gethostbyname2(hostname, AF_INET6)) != NULL) { + for (addr = hp->h_addr_list; *addr; addr++) { + if ((ai = ai_clone(*aip, AF_INET6)) == NULL) { + freeaddrinfo(*aip); + return (EAI_MEMORY); + } + *aip = ai; + ai->ai_socktype = socktype; + SIN6(ai->ai_addr)->sin6_port = port; + memcpy(&SIN6(ai->ai_addr)->sin6_addr, *addr, + hp->h_length); + if (flags & AI_CANONNAME) + ai->ai_canonname = strdup(hp->h_name); + } + } + return (0); +} + +void +freeaddrinfo(struct addrinfo *ai) { + struct addrinfo *ai_next; + + while (ai != NULL) { + ai_next = ai->ai_next; + if (ai->ai_addr) + free(ai->ai_addr); + if (ai->ai_canonname) + free(ai->ai_canonname); + free(ai); + ai = ai_next; + } +} + +#ifdef AF_LOCAL +static int +get_local(const char *name, int socktype, struct addrinfo **res) { + struct addrinfo *ai; + struct sockaddr_un *sun; + + if (socktype == 0) + return (EAI_SOCKTYPE); + + if ((ai = ai_alloc(AF_LOCAL, sizeof(*sun))) == NULL) + return (EAI_MEMORY); + + sun = SUN(ai->ai_addr); + strncpy(sun->sun_path, name, sizeof(sun->sun_path)); + + ai->ai_socktype = socktype; + /* + * ai->ai_flags, ai->ai_protocol, ai->ai_canonname, + * and ai->ai_next were initialized to zero. + */ + + *res = ai; + return (0); +} +#endif + +/* + * Allocate an addrinfo structure, and a sockaddr structure + * of the specificed length. We initialize: + * ai_addrlen + * ai_family + * ai_addr + * ai_addr->sa_family + * ai_addr->sa_len (HAVE_SA_LEN) + * and everything else is initialized to zero. + */ +static struct addrinfo * +ai_alloc(int family, int addrlen) { + struct addrinfo *ai; + + if ((ai = (struct addrinfo *)calloc(1, sizeof(*ai))) == NULL) + return (NULL); + + if ((ai->ai_addr = SA(calloc(1, addrlen))) == NULL) { + free(ai); + return (NULL); + } + ai->ai_addrlen = addrlen; + ai->ai_family = family; + ai->ai_addr->sa_family = family; +#ifdef HAVE_SA_LEN + ai->ai_addr->sa_len = addrlen; +#endif + return (ai); +} + +static struct addrinfo * +ai_clone(struct addrinfo *oai, int family) { + struct addrinfo *ai; + + ai = ai_alloc(family, ((family == AF_INET6) ? + sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))); + + if (ai == NULL) { + freeaddrinfo(oai); + return (NULL); + } + if (oai == NULL) + return (ai); + + ai->ai_flags = oai->ai_flags; + ai->ai_socktype = oai->ai_socktype; + ai->ai_protocol = oai->ai_protocol; + ai->ai_canonname = NULL; + ai->ai_next = oai; + return (ai); +} + +static struct addrinfo * +ai_reverse(struct addrinfo *oai) { + struct addrinfo *nai, *tai; + + nai = NULL; + + while (oai) { + /* grab one off the old list */ + tai = oai; + oai = oai->ai_next; + /* put it on the front of the new list */ + tai->ai_next = nai; + nai = tai; + } + return (nai); +} diff --git a/contrib/bind/lib/irs/getgrent.c b/contrib/bind/lib/irs/getgrent.c index df34447fb0..866e8c5 100644 --- a/contrib/bind/lib/irs/getgrent.c +++ b/contrib/bind/lib/irs/getgrent.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1998 by Internet Software Consortium. + * 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 @@ -16,21 +16,25 @@ */ #if !defined(LINT) && !defined(CODECENTER) -static char rcsid[] = "$Id: getgrent.c,v 1.13 1998/03/21 00:59:47 halley Exp $"; +static const char rcsid[] = "$Id: getgrent.c,v 1.19 1999/10/13 16:39:30 vixie Exp $"; #endif /* Imports */ #include "port_before.h" -#ifndef WANT_IRS_GR +#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 <irs.h> @@ -41,87 +45,150 @@ static int __bind_irs_gr_unneeded; /* Forward */ -static struct irs_gr * init(void); +static struct net_data *init(void); void endgrent(void); /* Public */ struct group * getgrent() { - struct irs_gr *gr = init(); - - if (!gr) - return (NULL); - net_data.gr_last = (*gr->next)(gr); - return (net_data.gr_last); + struct net_data *net_data = init(); + + return (getgrent_p(net_data)); } struct group * getgrnam(const char *name) { - struct irs_gr *gr = init(); - - if (!gr) + 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(const char *name, gid_t basegid, gid_t *groups, int *ngroups) { + 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) + 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); + return (net_data->gr_last); } struct group * -getgrgid(gid_t gid) { - struct irs_gr *gr = init(); - - if (!gr) +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 && - 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) + if (net_data->gr_stayopen && net_data->gr_last && + 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); + return (net_data->gr_last); } int -setgroupent(int stayopen) { - struct irs_gr *gr = init(); - - if (!gr) +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); + net_data->gr_stayopen = (stayopen != 0); + if (stayopen == 0) + net_data_minimize(net_data); return (1); } #ifdef SETGRENT_VOID void -setgrent() { - (void)setgroupent(0); +setgrent_p(struct net_data *net_data) { + (void)setgroupent_p(0, net_data); } #else int -setgrent() { - return (setgroupent(0)); +setgrent_p(struct net_data *net_data) { + return (setgroupent_p(0, net_data)); } #endif /* SETGRENT_VOID */ void -endgrent() { - struct irs_gr *gr = init(); +endgrent_p(struct net_data *net_data) { + struct irs_gr *gr; - if (gr != NULL) + if ((net_data != NULL) && ((gr = net_data->gr) != NULL)) (*gr->minimize)(gr); } int -getgrouplist(const char *name, gid_t basegid, gid_t *groups, int *ngroups) { - struct irs_gr *gr = init(); - - if (!gr) { +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); } @@ -130,18 +197,25 @@ getgrouplist(const char *name, gid_t basegid, gid_t *groups, int *ngroups) { /* Private */ -static struct irs_gr * +static struct net_data * init() { - if (!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) { + 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); + errno = EIO; + return (NULL); + } + (*net_data->gr->res_set)(net_data->gr, net_data->res, + NULL); } - return (net_data.gr); + + return (net_data); } #endif /* WANT_IRS_GR */ diff --git a/contrib/bind/lib/irs/getgrent_r.c b/contrib/bind/lib/irs/getgrent_r.c new file mode 100644 index 0000000..df055db --- /dev/null +++ b/contrib/bind/lib/irs/getgrent_r.c @@ -0,0 +1,219 @@ +/* + * 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 8.4 1999/01/18 07:46:51 vixie 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 <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/contrib/bind/lib/irs/gethostent.c b/contrib/bind/lib/irs/gethostent.c index 669cb95..ac66520 100644 --- a/contrib/bind/lib/irs/gethostent.c +++ b/contrib/bind/lib/irs/gethostent.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996,1997 by Internet Software Consortium. + * 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 @@ -16,17 +16,21 @@ */ #if !defined(LINT) && !defined(CODECENTER) -static char rcsid[] = "$Id: gethostent.c,v 1.13 1997/12/04 04:57:52 halley Exp $"; +static const char rcsid[] = "$Id: gethostent.c,v 1.25 1999/10/19 22:27:20 cyarnell 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> @@ -37,8 +41,10 @@ static char rcsid[] = "$Id: gethostent.c,v 1.13 1997/12/04 04:57:52 halley Exp $ #include <resolv.h> #include <stdio.h> #include <string.h> +#include <unistd.h> #include <irs.h> +#include <isc/memcluster.h> #include "port_after.h" @@ -57,156 +63,747 @@ struct pvt { /* Forward */ -static struct irs_ho * init(void); -static void freepvt(void); -static struct hostent * fakeaddr(const char *, int); +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 ((_res.options & RES_INIT) == 0 && res_init() == -1) + if (!net_data) return (NULL); - if (_res.options & RES_USE_INET6) { - hp = gethostbyname2(name, AF_INET6); + + if (net_data->res->options & RES_USE_INET6) { + hp = gethostbyname2_p(name, AF_INET6, net_data); if (hp) return (hp); } - return (gethostbyname2(name, AF_INET)); + return (gethostbyname2_p(name, AF_INET, net_data)); } struct hostent * -gethostbyname2(const char *name, int af) { - struct irs_ho *ho = init(); +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 (!ho) + if (!net_data || !(ho = net_data->ho)) return (NULL); - if (net_data.ho_stayopen && net_data.ho_last) { - if (!strcasecmp(name, net_data.ho_last->h_name)) - return (net_data.ho_last); - for (hap = net_data.ho_last->h_aliases; hap && *hap; hap++) - if (!strcasecmp(name, *hap)) - return (net_data.ho_last); + if (net_data->ho_stayopen && net_data->ho_last) { + 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 = hostalias(name))) + if (!strchr(name, '.') && (cp = res_hostalias(net_data->res, name, + tmp, sizeof tmp))) name = cp; - if ((hp = fakeaddr(name, af)) != NULL) + if ((hp = fakeaddr(name, af, net_data)) != NULL) return (hp); - net_data.ho_last = (*ho->byname2)(ho, name, af); - if (!net_data.ho_stayopen) + net_data->ho_last = (*ho->byname2)(ho, name, af); + if (!net_data->ho_stayopen) endhostent(); - return (net_data.ho_last); + return (net_data->ho_last); } struct hostent * -gethostbyaddr(const char *addr, int len, int af) { - struct irs_ho *ho = init(); +gethostbyaddr_p(const char *addr, int len, int af, struct net_data *net_data) { + struct irs_ho *ho; char **hap; - if (!ho) + 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; + 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) + 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); + return (net_data->ho_last); } + struct hostent * -gethostent() { - struct irs_ho *ho = init(); +gethostent_p(struct net_data *net_data) { + struct irs_ho *ho; + struct hostent *hp; - if (!ho) + if (!net_data || !(ho = net_data->ho)) return (NULL); - net_data.ho_last = (*ho->next)(ho); - return (net_data.ho_last); + 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(int stayopen) { - struct irs_ho *ho = init(); +sethostent_p(int stayopen, struct net_data *net_data) { + struct irs_ho *ho; - if (!ho) + if (!net_data || !(ho = net_data->ho)) return; - freepvt(); + freepvt(net_data); (*ho->rewind)(ho); - net_data.ho_stayopen = (stayopen != 0); + net_data->ho_stayopen = (stayopen != 0); + if (stayopen == 0) + net_data_minimize(net_data); } void -endhostent() { - struct irs_ho *ho = init(); +endhostent_p(struct net_data *net_data) { + struct irs_ho *ho; - if (ho != NULL) + if ((net_data != NULL) && ((ho = net_data->ho) != NULL)) (*ho->minimize)(ho); } -/* Private */ +#if !defined(HAS_INET6_STRUCTS) || defined(MISSING_IN6ADDR_ANY) +static const struct in6_addr in6addr_any; +#endif -static struct irs_ho * -init() { - if ((_res.options & RES_INIT) == 0 && res_init() == -1) +#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 (!net_data_init()) - goto error; - if (!net_data.ho) - net_data.ho = (*net_data.irs->ho_map)(net_data.irs); - if (!net_data.ho) { - error: errno = EIO; - h_errno = NETDB_INTERNAL; + } + + /* 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); } - return (net_data.ho); + + /* Literal address? */ + if (v4 == 1 || v6 == 1) { + char *addr_list[2]; + char *aliases[1]; + + he.h_name = (char *)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((struct in6_addr *)src)) || + (af == AF_INET6 && IN6_IS_ADDR_V4MAPPED((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((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) { + struct ifconf ifc; + struct ifreq ifreq; + struct in_addr in4; + struct in6_addr in6; + char *buf = NULL, *cp, *cplim; + static 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; + ifc.ifc_len = bufsiz; + ifc.ifc_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(&ifc) >= 0) + break; +#else + if ((n = ioctl(s, SIOCGIFCONF, (char *)&ifc)) != -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 + * ifc.ifc_len is too near to the end of the + * buffer we will grow it just in case and + * retry. + */ + if (ifc.ifc_len + 2 * sizeof(ifreq) < 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 + ifc.ifc_len; /* skip over if's with big ifr_addr's */ + for (cp = buf; + (*have_v4 == 0 || *have_v6 == 0) && cp < cplim; + cp += cpsize) { + memcpy(&ifreq, cp, sizeof ifreq); +#ifdef HAVE_SA_LEN +#ifdef FIX_ZERO_SA_LEN + if (ifreq.ifr_addr.sa_len == 0) + ifreq.ifr_addr.sa_len = 16; +#endif +#ifdef HAVE_MINIMUM_IFREQ + cpsize = sizeof ifreq; + if (ifreq.ifr_addr.sa_len > sizeof (struct sockaddr)) + cpsize += (int)ifreq.ifr_addr.sa_len - + (int)(sizeof (struct sockaddr)); +#else + cpsize = sizeof ifreq.ifr_name + ifreq.ifr_addr.sa_len; +#endif /* HAVE_MINIMUM_IFREQ */ +#elif defined SIOCGIFCONF_ADDR + cpsize = sizeof ifreq; +#else + cpsize = sizeof ifreq.ifr_name; + /* XXX maybe this should be a hard error? */ + if (ioctl(s, SIOCGIFADDR, (char *)&ifreq) < 0) + continue; +#endif + switch (ifreq.ifr_addr.sa_family) { + case AF_INET: + if (*have_v4 == 0) { + memcpy(&in4, + &((struct sockaddr_in *) + &ifreq.ifr_addr)->sin_addr, sizeof in4); + if (in4.s_addr == INADDR_ANY) + break; + n = ioctl(s, SIOCGIFFLAGS, (char *)&ifreq); + if (n < 0) + break; + if ((ifreq.ifr_flags & IFF_UP) == 0) + break; + *have_v4 = 1; + } + break; + case AF_INET6: + if (*have_v6 == 0) { + memcpy(&in6, + &((struct sockaddr_in6 *) + &ifreq.ifr_addr)->sin6_addr, sizeof in6); + if (memcmp(&in6, &in6addr_any, sizeof in6) == 0) + break; + n = ioctl(s, SIOCGIFFLAGS, (char *)&ifreq); + if (n < 0) + break; + if ((ifreq.ifr_flags & IFF_UP) == 0) + break; + *have_v6 = 1; + } + break; + } + } + if (buf != NULL) + memput(buf, bufsiz); + close(s); + return (0); + err_ret: + if (buf != NULL) + memput(buf, bufsiz); + if (s != -1) + close(s); + 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() { - if (net_data.ho_data) { - free(net_data.ho_data); - net_data.ho_data = NULL; +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) { +fakeaddr(const char *name, int af, struct net_data *net_data) { struct pvt *pvt; - const char *cp; - freepvt(); - net_data.ho_data = malloc(sizeof(struct pvt)); - if (!net_data.ho_data) { + freepvt(net_data); + net_data->ho_data = malloc(sizeof (struct pvt)); + if (!net_data->ho_data) { errno = ENOMEM; - h_errno = NETDB_INTERNAL; + RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL); return (NULL); } - pvt = net_data.ho_data; + pvt = net_data->ho_data; /* - * Unlike its forebear (inet_aton), our friendly inet_pton() is strict + * 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 + * 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) { - h_errno = HOST_NOT_FOUND; + 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) { + switch(af) { case AF_INET: pvt->host.h_length = NS_INADDRSZ; break; @@ -215,7 +812,7 @@ fakeaddr(const char *name, int af) { break; default: errno = EAFNOSUPPORT; - h_errno = NETDB_INTERNAL; + RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL); return (NULL); } pvt->host.h_name = pvt->name; @@ -224,9 +821,7 @@ fakeaddr(const char *name, int af) { pvt->addrs[0] = (char *)pvt->addr; pvt->addrs[1] = NULL; pvt->host.h_addr_list = pvt->addrs; - if (af == AF_INET && (_res.options & RES_USE_INET6)) - map_v4v6_address(pvt->addr, pvt->addr); - h_errno = NETDB_SUCCESS; + RES_SET_H_ERRNO(net_data->res, NETDB_SUCCESS); return (&pvt->host); } @@ -243,21 +838,23 @@ fakeaddr(const char *name, int af) { */ strncpy(hname2, hp->h_name, MAXDNAME); hname2[MAXDNAME] = '\0'; - old_options = _res.options; - _res.options &= ~RES_DNSRCH; - _res.options |= RES_DEFNAMES; + old_options = net_data->res->options; + net_data->res->options &= ~RES_DNSRCH; + net_data->res->options |= RES_DEFNAMES; if (!(rhp = gethostbyname(hname2))) { - _res.options = old_options; - h_errno = HOST_NOT_FOUND; + net_data->res->options = old_options; + RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND); return (NULL); } - _res.options = old_options; + net_data->res->options = old_options; for (haddr = rhp->h_addr_list; *haddr; haddr++) if (!memcmp(*haddr, addr, INADDRSZ)) break; if (!*haddr) { - h_errno = HOST_NOT_FOUND; + RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND); return (NULL); } } #endif /* grot */ + +#endif /*__BIND_NOSTATIC*/ diff --git a/contrib/bind/lib/irs/gethostent_r.c b/contrib/bind/lib/irs/gethostent_r.c new file mode 100644 index 0000000..5da1a96 --- /dev/null +++ b/contrib/bind/lib/irs/gethostent_r.c @@ -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 8.4 1999/01/18 07:46:52 vixie 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 <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; + i++; + } + 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/contrib/bind/lib/irs/getnameinfo.c b/contrib/bind/lib/irs/getnameinfo.c new file mode 100644 index 0000000..3157c66 --- /dev/null +++ b/contrib/bind/lib/irs/getnameinfo.c @@ -0,0 +1,230 @@ +/* + * 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; + int 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}, +}; + +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 + int len; +#endif + int family, i; + char *addr, *p; + u_long v4a; + 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 = ((struct sockinet *)sa)->si_port; /* network byte order */ + addr = (char *)sa + afd->a_off; + + if (serv == NULL || servlen == 0) { + /* what we should do? */ + } else if (flags & NI_NUMERICSERV) { + snprintf(numserv, strlen(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) > servlen) + return ENI_MEMORY; + strcpy(serv, sp->s_name); + } else + return ENI_NOSERVNAME; + } + + switch (sa->sa_family) { + case AF_INET: + v4a = ((struct sockaddr_in *)sa)->sin_addr.s_addr; + if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) + flags |= NI_NUMERICHOST; + v4a >>= IN_CLASSA_NSHIFT; + if (v4a == 0 || v4a == IN_LOOPBACKNET) + flags |= NI_NUMERICHOST; + break; + case AF_INET6: + pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[0]; + 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) > 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) > 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) > hostlen) + return ENI_MEMORY; + strcpy(host, numaddr); + } + } + return SUCCESS; +} diff --git a/contrib/bind/lib/irs/getnetent.c b/contrib/bind/lib/irs/getnetent.c index 17132f6..b63ddaf 100644 --- a/contrib/bind/lib/irs/getnetent.c +++ b/contrib/bind/lib/irs/getnetent.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,15 +16,18 @@ */ #if !defined(LINT) && !defined(CODECENTER) -static char rcsid[] = "$Id: getnetent.c,v 1.10 1997/12/04 04:57:53 halley Exp $"; +static const char rcsid[] = "$Id: getnetent.c,v 1.17 1999/10/13 16:39:30 vixie 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> @@ -32,6 +35,7 @@ static char rcsid[] = "$Id: getnetent.c,v 1.10 1997/12/04 04:57:53 halley Exp $" #include <ctype.h> #include <errno.h> #include <netdb.h> +#include <resolv.h> #include <stdlib.h> #include <string.h> @@ -52,10 +56,10 @@ struct pvt { /* Forward */ -static struct irs_nw * init(void); -static struct netent * nw_to_net(struct nwent *); -static void freepvt(void); -static struct netent * fakeaddr(const char *, int af); +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 */ @@ -67,118 +71,182 @@ static struct netent * fakeaddr(const char *, int af); struct netent * getnetent() { - struct irs_nw *nw = init(); - - if (!nw) - return (NULL); - net_data.nw_last = nw_to_net((*nw->next)(nw)); - return (net_data.nw_last); + struct net_data *net_data = init(); + + return (getnetent_p(net_data)); } struct netent * getnetbyname(const char *name) { - struct irs_nw *nw = init(); + 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 (!nw) + + 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 (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); + return (net_data->nw_last); } - if ((np = fakeaddr(name, AF_INET)) != NULL) + if ((np = fakeaddr(name, AF_INET, net_data)) != NULL) return (np); - net_data.nw_last = nw_to_net((*nw->byname)(nw, name, AF_INET)); - if (!net_data.nw_stayopen) + 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); + return (net_data->nw_last); } struct netent * -getnetbyaddr(unsigned long net, int type) { - struct irs_nw *nw = init(); +getnetbyaddr_p(unsigned long net, int type, struct net_data *net_data) { + struct irs_nw *nw; u_char addr[4]; int bits; - - if (!nw) + + 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); - - addr[3] = (0xFF000000 & net) >> 24; - addr[2] = (0x00FF0000 & net) >> 16; - addr[1] = (0x0000FF00 & net) >> 8; - addr[0] = (0x000000FF & net); - - /* Use the old class rules to figure out the network bits. */ - if (addr[3] >= 240) - bits = 32; - else if (addr[3] >= 224) - bits = 4; - else if (addr[3] >= 192) - bits = 24; - else if (addr[3] >= 128) - bits = 16; - else + 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; - - net_data.nw_last = nw_to_net((*nw->byaddr)(nw, addr, bits, AF_INET)); - if (!net_data.nw_stayopen) + } 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); + return (net_data->nw_last); } + + + void -setnetent(int stayopen) { - struct irs_nw *nw = init(); - - if (!nw) +setnetent_p(int stayopen, struct net_data *net_data) { + struct irs_nw *nw; + + if (!net_data || !(nw = net_data->nw)) return; - freepvt(); + freepvt(net_data); (*nw->rewind)(nw); - net_data.nw_stayopen = (stayopen != 0); + net_data->nw_stayopen = (stayopen != 0); + if (stayopen == 0) + net_data_minimize(net_data); } void -endnetent() { - struct irs_nw *nw = init(); +endnetent_p(struct net_data *net_data) { + struct irs_nw *nw; - if (nw != NULL) + if ((net_data != NULL) && ((nw = net_data->nw) != NULL)) (*nw->minimize)(nw); } /* Private */ -static struct irs_nw * +static struct net_data * init() { - if (!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) { + 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); + errno = EIO; + return (NULL); + } + (*net_data->nw->res_set)(net_data->nw, net_data->res, NULL); } - return (net_data.nw); + + return (net_data); } static void -freepvt() { - if (net_data.nw_data) { - free(net_data.nw_data); - net_data.nw_data = NULL; +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) { +fakeaddr(const char *name, int af, struct net_data *net_data) { struct pvt *pvt; const char *cp; u_long tmp; @@ -186,7 +254,7 @@ fakeaddr(const char *name, int af) { if (af != AF_INET) { /* XXX should support IPv6 some day */ errno = EAFNOSUPPORT; - h_errno = NETDB_INTERNAL; + RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL); return (NULL); } if (!isascii(name[0]) || !isdigit(name[0])) @@ -201,7 +269,7 @@ fakeaddr(const char *name, int af) { tmp = inet_network(name); if (tmp == INADDR_NONE) { - h_errno = HOST_NOT_FOUND; + RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND); return (NULL); } @@ -209,14 +277,14 @@ fakeaddr(const char *name, int af) { * Fake up a netent as if we'd actually * done a lookup. */ - freepvt(); - net_data.nw_data = malloc(sizeof(struct pvt)); - if (!net_data.nw_data) { + freepvt(net_data); + net_data->nw_data = malloc(sizeof (struct pvt)); + if (!net_data->nw_data) { errno = ENOMEM; - h_errno = NETDB_INTERNAL; + RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL); return (NULL); } - pvt = net_data.nw_data; + pvt = net_data->nw_data; strncpy(pvt->name, name, MAXDNAME); pvt->name[MAXDNAME] = '\0'; @@ -230,29 +298,29 @@ fakeaddr(const char *name, int af) { } static struct netent * -nw_to_net(struct nwent *nwent) { +nw_to_net(struct nwent *nwent, struct net_data *net_data) { struct pvt *pvt; u_long addr = 0; - int i; + int i; int msbyte; if (!nwent || nwent->n_addrtype != AF_INET) return (NULL); - freepvt(); - net_data.nw_data = malloc(sizeof(struct pvt)); - if (!net_data.nw_data) { + freepvt(net_data); + net_data->nw_data = malloc(sizeof (struct pvt)); + if (!net_data->nw_data) { errno = ENOMEM; - h_errno = NETDB_INTERNAL; + RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL); return (NULL); } - pvt = net_data.nw_data; + 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 @@ -269,4 +337,4 @@ nw_to_net(struct nwent *nwent) { return (&pvt->netent); } - +#endif /*__BIND_NOSTATIC*/ diff --git a/contrib/bind/lib/irs/getnetent_r.c b/contrib/bind/lib/irs/getnetent_r.c new file mode 100644 index 0000000..b78b45a --- /dev/null +++ b/contrib/bind/lib/irs/getnetent_r.c @@ -0,0 +1,191 @@ +/* + * 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 8.4 1999/01/18 07:46:52 vixie 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 <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/contrib/bind/lib/irs/getnetgrent.c b/contrib/bind/lib/irs/getnetgrent.c index 0acb776..8c5f5f8 100644 --- a/contrib/bind/lib/irs/getnetgrent.c +++ b/contrib/bind/lib/irs/getnetgrent.c @@ -1,5 +1,5 @@ /* - * Portions Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,14 +16,22 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: getnetgrent.c,v 1.9 1997/12/04 04:57:53 halley Exp $"; +static const char rcsid[] = "$Id: getnetgrent.c,v 1.14 1999/10/07 20:44:03 vixie 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> @@ -34,60 +42,100 @@ static const char rcsid[] = "$Id: getnetgrent.c,v 1.9 1997/12/04 04:57:53 halley /* Forward */ -static struct irs_ng * init(void); +static struct net_data *init(void); + /* Public */ void setnetgrent(const char *netgroup) { - struct irs_ng *ng = init(); - - if (ng != NULL) - (*ng->rewind)(ng, netgroup); + struct net_data *net_data = init(); + + setnetgrent_p(netgroup, net_data); } -void +void endnetgrent(void) { - struct irs_ng *ng = init(); - - if (ng) - (*ng->close)(ng); - net_data.ng = NULL; + 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 irs_ng *ng = init(); - - if (!ng) + struct net_data *net_data = init(); + + return (innetgr_p(netgroup, host, user, domain, net_data)); +} + +int +getnetgrent(char **host, char **user, 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(char **host, char **user, char **domain) { - struct irs_ng *ng = init(); - struct netgrp *ngent; - - if (!ng) +getnetgrent_p(char **host, char **user, 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 irs_ng * +static struct net_data * init(void) { - - if (!net_data_init()) + 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); + 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.ng); + + return (net_data); } + +#endif /*__BIND_NOSTATIC*/ diff --git a/contrib/bind/lib/irs/getnetgrent_r.c b/contrib/bind/lib/irs/getnetgrent_r.c new file mode 100644 index 0000000..e0c366c --- /dev/null +++ b/contrib/bind/lib/irs/getnetgrent_r.c @@ -0,0 +1,134 @@ +/* + * 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 8.4 1999/01/18 07:46:52 vixie 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 <netinet/in.h> +#include <netdb.h> +#include <port_after.h> + +#ifdef NGR_R_RETURN + +static NGR_R_RETURN +copy_protoent(char **, char **, char **, char *, char *, 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) { + 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 +endnetgrent_r(NGR_R_ENT_ARGS) { + endnetgrent(); + NGR_R_END_RESULT(NGR_R_OK); +} + +/* Private */ + +static int +copy_protoent(char **machinep, char **userp, char **domainp, + char *mp, char *up, char *dp, NGR_R_COPY_ARGS) { + char *cp; + int i, 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/contrib/bind/lib/irs/getprotoent.c b/contrib/bind/lib/irs/getprotoent.c index f79a1c6..e3bfc37 100644 --- a/contrib/bind/lib/irs/getprotoent.c +++ b/contrib/bind/lib/irs/getprotoent.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,16 +16,22 @@ */ #if !defined(LINT) && !defined(CODECENTER) -static char rcsid[] = "$Id: getprotoent.c,v 1.9 1997/12/04 04:57:53 halley Exp $"; +static const char rcsid[] = "$Id: getprotoent.c,v 1.15 1999/10/13 16:39:31 vixie 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> @@ -36,85 +42,132 @@ static char rcsid[] = "$Id: getprotoent.c,v 1.9 1997/12/04 04:57:53 halley Exp $ /* Forward */ -static struct irs_pr * init(void); +static struct net_data *init(void); /* Public */ struct protoent * getprotoent() { - struct irs_pr *pr = init(); - - if (!pr) - return (NULL); - net_data.pr_last = (*pr->next)(pr); - return (net_data.pr_last); + struct net_data *net_data = init(); + + return (getprotoent_p(net_data)); } struct protoent * getprotobyname(const char *name) { - struct irs_pr *pr = init(); + 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 (!pr) + 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 (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); + return (net_data->pr_last); } - net_data.pr_last = (*pr->byname)(pr, name); - if (!net_data.pr_stayopen) + net_data->pr_last = (*pr->byname)(pr, name); + if (!net_data->pr_stayopen) endprotoent(); - return (net_data.pr_last); + return (net_data->pr_last); } struct protoent * -getprotobynumber(int proto) { - struct irs_pr *pr = init(); +getprotobynumber_p(int proto, struct net_data *net_data) { + struct irs_pr *pr; - if (!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) + 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); + return (net_data->pr_last); } void -setprotoent(int stayopen) { - struct irs_pr *pr = init(); +setprotoent_p(int stayopen, struct net_data *net_data) { + struct irs_pr *pr; - if (!pr) + if (!net_data || !(pr = net_data->pr)) return; (*pr->rewind)(pr); - net_data.pr_stayopen = (stayopen != 0); + net_data->pr_stayopen = (stayopen != 0); + if (stayopen == 0) + net_data_minimize(net_data); } void -endprotoent() { - struct irs_pr *pr = init(); +endprotoent_p(struct net_data *net_data) { + struct irs_pr *pr; - if (pr != NULL) + if ((net_data != NULL) && ((pr = net_data->pr) != NULL)) (*pr->minimize)(pr); } /* Private */ -static struct irs_pr * +static struct net_data * init() { - if (!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) { + 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); + errno = EIO; + return (NULL); + } + (*net_data->pr->res_set)(net_data->pr, net_data->res, NULL); } - return (net_data.pr); + + return (net_data); } + +#endif /*__BIND_NOSTATIC*/ diff --git a/contrib/bind/lib/irs/getprotoent_r.c b/contrib/bind/lib/irs/getprotoent_r.c new file mode 100644 index 0000000..e5c54d7 --- /dev/null +++ b/contrib/bind/lib/irs/getprotoent_r.c @@ -0,0 +1,185 @@ +/* + * 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 8.4 1999/01/18 07:46:52 vixie 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 <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/contrib/bind/lib/irs/getpwent.c b/contrib/bind/lib/irs/getpwent.c index 8e4d897..94f2df5 100644 --- a/contrib/bind/lib/irs/getpwent.c +++ b/contrib/bind/lib/irs/getpwent.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,21 +16,25 @@ */ #if !defined(LINT) && !defined(CODECENTER) -static char rcsid[] = "$Id: getpwent.c,v 1.13 1998/03/21 00:59:48 halley Exp $"; +static const char rcsid[] = "$Id: getpwent.c,v 1.20 1999/10/13 16:39:31 vixie Exp $"; #endif /* Imports */ #include "port_before.h" -#ifndef WANT_IRS_PW +#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> @@ -41,95 +45,155 @@ static int __bind_irs_pw_unneeded; /* Forward */ -static struct irs_pw * init(void); +static struct net_data * init(void); /* Public */ struct passwd * getpwent(void) { - struct irs_pw *pw = init(); + struct net_data *net_data = init(); - if (!pw) - return (NULL); - net_data.pw_last = (*pw->next)(pw); - return (net_data.pw_last); + return (getpwent_p(net_data)); } struct passwd * getpwnam(const char *name) { - struct irs_pw *pw = init(); - - if (!pw) + 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(); + + return (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) + 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); + return (net_data->pw_last); } struct passwd * -getpwuid(uid_t uid) { - struct irs_pw *pw = init(); +getpwuid_p(uid_t uid, struct net_data *net_data) { + struct irs_pw *pw; - if (!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) + 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); + return (net_data->pw_last); } int -setpassent(int stayopen) { - struct irs_pw *pw = init(); - - if (!pw) +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); + net_data->pw_stayopen = (stayopen != 0); + if (stayopen == 0) + net_data_minimize(net_data); return (1); } #ifdef SETPWENT_VOID void -setpwent() { - (void) setpassent(0); +setpwent_p(struct net_data *net_data) { + (void) setpassent_p(0, net_data); } #else -int -setpwent() { - return (setpassent(0)); +int +setpwent_p(struct net_data *net_data) { + return (setpassent_p(0, net_data)); } #endif void -endpwent() { - struct irs_pw *pw = init(); +endpwent_p(struct net_data *net_data) { + struct irs_pw *pw; - if (pw != NULL) + if ((net_data != NULL) && ((pw = net_data->pw) != NULL)) (*pw->minimize)(pw); } /* Private */ -static struct irs_pw * +static struct net_data * init() { - if (!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) { + 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); + errno = EIO; + return (NULL); + } + (*net_data->pw->res_set)(net_data->pw, net_data->res, NULL); } - return (net_data.pw); + + return (net_data); } #endif /* WANT_IRS_PW */ diff --git a/contrib/bind/lib/irs/getpwent_r.c b/contrib/bind/lib/irs/getpwent_r.c new file mode 100644 index 0000000..761fa45 --- /dev/null +++ b/contrib/bind/lib/irs/getpwent_r.c @@ -0,0 +1,253 @@ +/* + * 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 8.3 1999/01/08 19:24:33 vixie 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 +setpwent_r(PASS_R_ENT_ARGS) { + + setpwent(); +#ifdef PASS_R_SET_RESULT + return (PASS_R_SET_RESULT); +#endif +} + +PASS_R_END_RETURN +endpwent_r(PASS_R_ENT_ARGS) { + + 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 i, n; + int numptr, 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/contrib/bind/lib/irs/getservent.c b/contrib/bind/lib/irs/getservent.c index 64ac2dc..d2b8b50 100644 --- a/contrib/bind/lib/irs/getservent.c +++ b/contrib/bind/lib/irs/getservent.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,16 +16,22 @@ */ #if !defined(LINT) && !defined(CODECENTER) -static char rcsid[] = "$Id: getservent.c,v 1.10 1997/12/04 04:57:54 halley Exp $"; +static const char rcsid[] = "$Id: getservent.c,v 1.16 1999/10/13 16:39:31 vixie 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> @@ -36,87 +42,135 @@ static char rcsid[] = "$Id: getservent.c,v 1.10 1997/12/04 04:57:54 halley Exp $ /* Forward */ -static struct irs_sv * init(void); +static struct net_data *init(void); /* Public */ struct servent * getservent(void) { - struct irs_sv *sv = init(); - - if (!sv) - return (NULL); - net_data.sv_last = (*sv->next)(sv); - return (net_data.sv_last); + struct net_data *net_data = init(); + + return (getservent_p(net_data)); } struct servent * getservbyname(const char *name, const char *proto) { - struct irs_sv *sv = init(); + 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 (!sv) + + 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 (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); + return (net_data->sv_last); } - net_data.sv_last = (*sv->byname)(sv, name, proto); - if (!net_data.sv_stayopen) + net_data->sv_last = (*sv->byname)(sv, name, proto); + if (!net_data->sv_stayopen) endservent(); - return (net_data.sv_last); + return (net_data->sv_last); } struct servent * -getservbyport(int port, const char *proto) { - struct irs_sv *sv = init(); - - if (!sv) +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); + 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(int stayopen) { - struct irs_sv *sv = init(); +setservent_p(int stayopen, struct net_data *net_data) { + struct irs_sv *sv; - if (!sv) + if (!net_data || !(sv = net_data->sv)) return; (*sv->rewind)(sv); - net_data.sv_stayopen = (stayopen != 0); + net_data->sv_stayopen = (stayopen != 0); + if (stayopen == 0) + net_data_minimize(net_data); } void -endservent() { - struct irs_sv *sv = init(); +endservent_p(struct net_data *net_data) { + struct irs_sv *sv; - if (sv != NULL) + if ((net_data != NULL) && ((sv = net_data->sv) != NULL)) (*sv->minimize)(sv); } /* Private */ -static struct irs_sv * +static struct net_data * init() { - if (!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) { + 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); + errno = EIO; + return (NULL); + } + (*net_data->sv->res_set)(net_data->sv, net_data->res, NULL); } - return (net_data.sv); + + return (net_data); } + +#endif /*__BIND_NOSTATIC*/ diff --git a/contrib/bind/lib/irs/getservent_r.c b/contrib/bind/lib/irs/getservent_r.c new file mode 100644 index 0000000..4da9dc2 --- /dev/null +++ b/contrib/bind/lib/irs/getservent_r.c @@ -0,0 +1,206 @@ +/* + * 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 8.3 1999/01/08 19:24:36 vixie 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 <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/contrib/bind/lib/irs/hesiod.c b/contrib/bind/lib/irs/hesiod.c index a56d213..54a6657 100644 --- a/contrib/bind/lib/irs/hesiod.c +++ b/contrib/bind/lib/irs/hesiod.c @@ -1,9 +1,9 @@ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: hesiod.c,v 1.15 1998/01/26 23:08:24 halley Exp $"; +static const char rcsid[] = "$Id: hesiod.c,v 1.20 1999/02/22 04:09:06 vixie Exp $"; #endif /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -65,6 +65,7 @@ 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 */ @@ -131,15 +132,16 @@ hesiod_init(void **context) { goto cleanup; } +#if 0 + if (res_ninit(ctx->res) < 0) + goto cleanup; +#endif + *context = ctx; return (0); cleanup: - if (ctx->LHS) - free(ctx->LHS); - if (ctx->RHS) - free(ctx->RHS); - free(ctx); + hesiod_end(ctx); return (-1); } @@ -149,12 +151,18 @@ hesiod_init(void **context) { 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; } /* @@ -226,11 +234,17 @@ hesiod_resolve(void *context, const char *name, const char *type) { char *bindname = hesiod_to_bind(context, name, type); char **retvec; - if (!bindname) + if (bindname == NULL) + return (NULL); + if (init(ctx) == -1) { + free(bindname); return (NULL); + } - if ((retvec = get_txt_records(ctx, C_IN, bindname))) + if ((retvec = get_txt_records(ctx, C_IN, bindname))) { + free(bindname); return (retvec); + } if (errno != ENOENT) return (NULL); @@ -322,8 +336,6 @@ parse_config_file(struct hesiod_p *ctx, const char *filename) { /* * Given a DNS class and a DNS name, do a lookup for TXT records, and * return a list of them. - * - * XXX we're still using the non-thread safe res_* routines. */ static char ** get_txt_records(struct hesiod_p *ctx, int class, const char *name) { @@ -333,7 +345,6 @@ get_txt_records(struct hesiod_p *ctx, int class, const char *name) { int dlen; /* len of data section */ u_char *data; /* pointer to data */ } rr; - struct __res_state save_res; HEADER *hp; u_char qbuf[MAX_HESRESP], abuf[MAX_HESRESP]; u_char *cp, *erdata, *eom; @@ -342,22 +353,15 @@ get_txt_records(struct hesiod_p *ctx, int class, const char *name) { int i, j, n, skip; /* - * Construct the query and send it. We play games with _res - * since we don't have our own resolver state. Once the - * resolver routines are rewritten to use their own context - * variable, we'll use it here. + * Construct the query and send it. */ - if ((_res.options & RES_INIT) == 0 && res_init() == -1) - return (NULL); - save_res = _res; - n = res_mkquery(QUERY, name, class, T_TXT, NULL, 0, - NULL, qbuf, MAX_HESRESP); + 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_send(qbuf, n, abuf, MAX_HESRESP); - _res = save_res; + n = res_nsend(ctx->res, qbuf, n, abuf, MAX_HESRESP); if (n < 0) { errno = ECONNREFUSED; return (NULL); @@ -452,3 +456,48 @@ get_txt_records(struct hesiod_p *ctx, int class, const char *name) { 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/contrib/bind/lib/irs/hesiod_p.h b/contrib/bind/lib/irs/hesiod_p.h index d2204db..eb32166 100644 --- a/contrib/bind/lib/irs/hesiod_p.h +++ b/contrib/bind/lib/irs/hesiod_p.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -20,7 +20,7 @@ */ /* - * $Id: hesiod_p.h,v 1.6 1996/11/18 09:09:32 vixie Exp $ + * $Id: hesiod_p.h,v 1.9 1999/01/08 19:24:39 vixie Exp $ */ /* @@ -36,6 +36,11 @@ 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 diff --git a/contrib/bind/lib/irs/irp.c b/contrib/bind/lib/irs/irp.c new file mode 100644 index 0000000..c2b64ab --- /dev/null +++ b/contrib/bind/lib/irs/irp.c @@ -0,0 +1,583 @@ +/* + * 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 8.5 1999/10/13 17:11:18 vixie 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; + + 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; + struct sockaddr_un uaddr; + long ipaddr; + const char *irphost; + int code; + char text[256]; + int socklen = 0; + + if (pvt->fdCxn != -1) { + perror("fd != 1"); + return (-1); + } + + memset(&uaddr, 0, sizeof uaddr); + memset(&iaddr, 0, sizeof iaddr); + + irphost = getenv(IRPD_HOST_ENV); + if (irphost == NULL) { + irphost = "127.0.0.1"; + } + + 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 { + 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 > sizeof buffer - 2) { + 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/contrib/bind/lib/irs/irp_gr.c b/contrib/bind/lib/irs/irp_gr.c new file mode 100644 index 0000000..4e2a28c --- /dev/null +++ b/contrib/bind/lib/irs/irp_gr.c @@ -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 8.1 1999/01/18 07:46:53 vixie 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 && 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/contrib/bind/lib/irs/irp_ho.c b/contrib/bind/lib/irs/irp_ho.c new file mode 100644 index 0000000..7bfd0e2 --- /dev/null +++ b/contrib/bind/lib/irs/irp_ho.c @@ -0,0 +1,418 @@ +/* + * 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 8.2 1999/10/13 16:39:31 vixie 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); + + +/* 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; + + 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); + } +} + diff --git a/contrib/bind/lib/irs/irp_ng.c b/contrib/bind/lib/irs/irp_ng.c new file mode 100644 index 0000000..e96f66c --- /dev/null +++ b/contrib/bind/lib/irs/irp_ng.c @@ -0,0 +1,266 @@ +/* + * 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 8.2 1999/10/13 16:39:31 vixie 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 *, char **, char **, 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, char **host, char **user, char **domain) + * + * Notes: + * + * Get the next netgroup item from the cache. + * + */ + +static int +ng_next(struct irs_ng *this, char **host, char **user, 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; + + 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/contrib/bind/lib/irs/irp_nw.c b/contrib/bind/lib/irs/irp_nw.c new file mode 100644 index 0000000..c0bcbfa --- /dev/null +++ b/contrib/bind/lib/irs/irp_nw.c @@ -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 8.1 1999/01/18 07:46:54 vixie 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/contrib/bind/lib/irs/irp_p.h b/contrib/bind/lib/irs/irp_p.h new file mode 100644 index 0000000..adf8174 --- /dev/null +++ b/contrib/bind/lib/irs/irp_p.h @@ -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 8.1 1999/01/18 07:46:54 vixie 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/contrib/bind/lib/irs/irp_pr.c b/contrib/bind/lib/irs/irp_pr.c new file mode 100644 index 0000000..1de304e --- /dev/null +++ b/contrib/bind/lib/irs/irp_pr.c @@ -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 8.1 1999/01/18 07:46:54 vixie 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/contrib/bind/lib/irs/irp_pw.c b/contrib/bind/lib/irs/irp_pw.c new file mode 100644 index 0000000..f23cb73 --- /dev/null +++ b/contrib/bind/lib/irs/irp_pw.c @@ -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 8.1 1999/01/18 07:46:54 vixie 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/contrib/bind/lib/irs/irp_sv.c b/contrib/bind/lib/irs/irp_sv.c new file mode 100644 index 0000000..6a12c5b --- /dev/null +++ b/contrib/bind/lib/irs/irp_sv.c @@ -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 8.1 1999/01/18 07:46:54 vixie 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/contrib/bind/lib/irs/irpmarshall.c b/contrib/bind/lib/irs/irpmarshall.c new file mode 100644 index 0000000..8f7c330 --- /dev/null +++ b/contrib/bind/lib/irs/irpmarshall.c @@ -0,0 +1,2332 @@ +/* + * 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 8.5 1999/10/13 17:11:19 vixie 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" + + +static char *strndup(const char *str, size_t len); +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]; + 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(char **host, char **user, 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(char **host, char **user, char **domain, char *buffer) { + char *p, *q; + char fieldsep = ','; + int myerrno = EINVAL; + + if (user == NULL || host == NULL || domain == 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); + } + + 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 (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); +} + + + + + +/* + * 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); +} + +#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/contrib/bind/lib/irs/irs_data.c b/contrib/bind/lib/irs/irs_data.c index 7f23751..f31fe69 100644 --- a/contrib/bind/lib/irs/irs_data.c +++ b/contrib/bind/lib/irs/irs_data.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,24 +16,179 @@ */ #if !defined(LINT) && !defined(CODECENTER) -static char rcsid[] = "$Id: irs_data.c,v 1.7 1997/12/04 04:57:54 halley Exp $"; +static const char rcsid[] = "$Id: irs_data.c,v 1.14 1999/10/13 16:39:31 vixie 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() { +#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; +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 -int -net_data_init() { - if (!net_data.irs) - net_data.irs = irs_gen_acc(""); - return (net_data.irs != NULL); + 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/contrib/bind/lib/irs/irs_data.h b/contrib/bind/lib/irs/irs_data.h index 4356b57..c82d767 100644 --- a/contrib/bind/lib/irs/irs_data.h +++ b/contrib/bind/lib/irs/irs_data.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,10 +16,11 @@ */ /* - * $Id: irs_data.h,v 1.7 1997/12/04 04:57:55 halley Exp $ + * $Id: irs_data.h,v 1.12 1999/01/18 07:46:55 vixie Exp $ */ -#define net_data __net_data +#ifndef __BIND_NOSTATIC + #define net_data_init __net_data_init struct net_data { @@ -37,7 +38,8 @@ struct net_data { struct passwd * pw_last; struct servent * sv_last; struct protoent * pr_last; - struct netent * nw_last; + struct netent * nw_last; /* should have been ne_last */ + struct nwent * nww_last; struct hostent * ho_last; unsigned int gr_stayopen :1; @@ -50,8 +52,11 @@ struct net_data { void * nw_data; void * ho_data; - char fill[512 - 68]; /* 68 = sizeof(above) */ + struct __res_state * res; /* for gethostent.c */ + }; -extern struct net_data net_data; -extern int net_data_init(void); +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/contrib/bind/lib/irs/irs_p.h b/contrib/bind/lib/irs/irs_p.h index bc49665..d14f7d1 100644 --- a/contrib/bind/lib/irs/irs_p.h +++ b/contrib/bind/lib/irs/irs_p.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,21 +16,34 @@ */ /* - * $Id: irs_p.h,v 1.6 1997/12/04 04:57:55 halley Exp $ + * $Id: irs_p.h,v 1.8 1999/01/08 19:24:42 vixie 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/contrib/bind/lib/irs/lcl.c b/contrib/bind/lib/irs/lcl.c index badbdfe..46c7743 100644 --- a/contrib/bind/lib/irs/lcl.c +++ b/contrib/bind/lib/irs/lcl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1998 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if !defined(LINT) && !defined(CODECENTER) -static char rcsid[] = "$Id: lcl.c,v 1.11 1998/03/21 00:59:49 halley Exp $"; +static const char rcsid[] = "$Id: lcl.c,v 1.15 1999/10/13 16:39:32 vixie Exp $"; #endif /* Imports */ @@ -27,6 +27,13 @@ static char rcsid[] = "$Id: lcl.c,v 1.11 1998/03/21 00:59:49 halley Exp $"; #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" @@ -37,6 +44,9 @@ static char rcsid[] = "$Id: lcl.c,v 1.11 1998/03/21 00:59:49 halley Exp $"; /* 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 */ @@ -45,17 +55,19 @@ irs_lcl_acc(const char *options) { struct irs_acc *acc; struct lcl_p *lcl; - if (!(acc = malloc(sizeof *acc))) { + if (!(acc = memget(sizeof *acc))) { errno = ENOMEM; return (NULL); } memset(acc, 0x5e, sizeof *acc); - if (!(lcl = malloc(sizeof *lcl))) { + 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; @@ -72,17 +84,55 @@ irs_lcl_acc(const char *options) { 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) - free(lcl); - free(this); + if (lcl) { + if (lcl->free_res) + (*lcl->free_res)(lcl->res); + memput(lcl, sizeof *lcl); + } + memput(this, sizeof *this); } diff --git a/contrib/bind/lib/irs/lcl_gr.c b/contrib/bind/lib/irs/lcl_gr.c index 5a5d503..acb85ee 100644 --- a/contrib/bind/lib/irs/lcl_gr.c +++ b/contrib/bind/lib/irs/lcl_gr.c @@ -32,7 +32,7 @@ */ /* - * Portions Copyright (c) 1996, 1998 by Internet Software Consortium. + * 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 @@ -49,7 +49,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: lcl_gr.c,v 1.20 1998/03/21 00:59:49 halley Exp $"; +static const char rcsid[] = "$Id: lcl_gr.c,v 1.25 1999/10/13 17:11:19 vixie 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 */ @@ -64,6 +64,9 @@ static int __bind_irs_gr_unneeded; #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> @@ -74,11 +77,14 @@ static int __bind_irs_gr_unneeded; #include <unistd.h> #include <irs.h> - -#include "port_after.h" +#include <isc/memcluster.h> #include "irs_p.h" #include "lcl_p.h" +#include "irp_p.h" + +#include "port_after.h" + /* Types. */ @@ -123,13 +129,13 @@ irs_lcl_gr(struct irs_acc *this) { struct irs_gr *gr; struct pvt *pvt; - if (!(gr = malloc(sizeof *gr))) { + if (!(gr = memget(sizeof *gr))) { errno = ENOMEM; return (NULL); } memset(gr, 0x5e, sizeof *gr); - if (!(pvt = malloc(sizeof *pvt))) { - free(gr); + if (!(pvt = memget(sizeof *pvt))) { + memput(gr, sizeof *gr); errno = ENOMEM; return (NULL); } @@ -142,6 +148,8 @@ irs_lcl_gr(struct irs_acc *this) { gr->rewind = gr_rewind; gr->list = make_group_list; gr->minimize = gr_minimize; + gr->res_get = NULL; + gr->res_set = NULL; return (gr); } @@ -157,8 +165,8 @@ gr_close(struct irs_gr *this) { free(pvt->group.gr_mem); if (pvt->membuf) free(pvt->membuf); - free(pvt); - free(this); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); } static struct group * @@ -271,13 +279,12 @@ grnext(struct pvt *pvt) { 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 linelen, n; + size_t n; char *bp, **m, *p; /* Read lines until we find one that matches our search criteria. */ for (;;) { - bp = grnext(pvt); - if (bp == NULL) + if ((bp = grnext(pvt)) == NULL) return (NULL); /* Optimize the usual case of searching for a name. */ @@ -320,8 +327,10 @@ grscan(struct irs_gr *this, int search, gid_t gid, const char *name) { * to account for the NULL terminator. As above, allocate * largest of INITIAL_NMEMB, or 2*n. */ - for (n = 2, p = bp; (p = strpbrk(p, ", ")) != NULL; ++p, ++n) - (void)NULL; + 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; diff --git a/contrib/bind/lib/irs/lcl_ho.c b/contrib/bind/lib/irs/lcl_ho.c index b285d1c..5939207 100644 --- a/contrib/bind/lib/irs/lcl_ho.c +++ b/contrib/bind/lib/irs/lcl_ho.c @@ -32,7 +32,7 @@ */ /* - * Portions Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -52,7 +52,7 @@ /* BIND Id: gethnamaddr.c,v 8.15 1996/05/22 04:56:30 vixie Exp $ */ #if defined(LIBC_SCCS) && !defined(lint) -static char rcsid[] = "$Id: lcl_ho.c,v 1.15 1997/12/04 04:57:56 halley Exp $"; +static const char rcsid[] = "$Id: lcl_ho.c,v 1.25 1999/10/13 17:11:19 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ /* Imports. */ @@ -77,6 +77,7 @@ static char rcsid[] = "$Id: lcl_ho.c,v 1.15 1997/12/04 04:57:56 halley Exp $"; #include <string.h> #include <irs.h> +#include <isc/memcluster.h> #include "port_after.h" @@ -89,8 +90,6 @@ static char rcsid[] = "$Id: lcl_ho.c,v 1.15 1997/12/04 04:57:56 halley Exp $"; # define SPRINTF(x) sprintf x #endif -extern int h_errno; - /* Definitions. */ #define MAXALIASES 35 @@ -110,6 +109,8 @@ struct pvt { 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 { @@ -131,8 +132,13 @@ static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr, 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 size_t ns_namelen(const char *); +static int init(struct irs_ho *this); /* Portability. */ @@ -147,12 +153,13 @@ irs_lcl_ho(struct irs_acc *this) { struct irs_ho *ho; struct pvt *pvt; - if (!(pvt = (struct pvt *)malloc(sizeof *pvt))) { + if (!(pvt = memget(sizeof *pvt))) { errno = ENOMEM; return (NULL); } memset(pvt, 0, sizeof *pvt); - if (!(ho = malloc(sizeof *ho))) { + if (!(ho = memget(sizeof *ho))) { + memput(pvt, sizeof *pvt); errno = ENOMEM; return (NULL); } @@ -165,6 +172,8 @@ irs_lcl_ho(struct irs_acc *this) { ho->next = ho_next; ho->rewind = ho_rewind; ho->minimize = ho_minimize; + ho->res_get = ho_res_get; + ho->res_set = ho_res_set; return (ho); } @@ -174,19 +183,24 @@ 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); - free(pvt); - free(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 hostent *hp; - if ((_res.options & RES_INIT) == 0 && res_init() == -1) + if (init(this) == -1) return (NULL); - if (_res.options & RES_USE_INET6) { + + if (pvt->res->options & RES_USE_INET6) { hp = ho_byname2(this, name, AF_INET6); if (hp) return (hp); @@ -196,12 +210,14 @@ ho_byname(struct irs_ho *this, const char *name) { 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 ((_res.options & RES_INIT) == 0 && res_init() == -1) + if (init(this) == -1) return (NULL); + ho_rewind(this); n = ns_namelen(name); while ((hp = ho_next(this)) != NULL) { @@ -220,21 +236,23 @@ ho_byname2(struct irs_ho *this, const char *name, int af) { } found: if (!hp) { - h_errno = HOST_NOT_FOUND; + RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); return (NULL); } - h_errno = NETDB_SUCCESS; + 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 ((_res.options & RES_INIT) == 0 && res_init() == -1) + if (init(this) == -1) return (NULL); + if (af == AF_INET6 && len == IN6ADDRSZ && (!memcmp(uaddr, mapped, sizeof mapped) || !memcmp(uaddr, tunnelled, sizeof tunnelled))) { @@ -253,12 +271,12 @@ ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) { break; default: errno = EAFNOSUPPORT; - h_errno = NETDB_INTERNAL; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); return (NULL); } if (size > len) { errno = EINVAL; - h_errno = NETDB_INTERNAL; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); return (NULL); } @@ -289,10 +307,10 @@ ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) { } found: if (!hp) { - h_errno = HOST_NOT_FOUND; + RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); return (NULL); } - h_errno = NETDB_SUCCESS; + RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS); return (hp); } @@ -300,33 +318,67 @@ static struct hostent * ho_next(struct irs_ho *this) { struct pvt *pvt = (struct pvt *)this->private; char *cp, **q, *p; - int af, len; + 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) { - h_errno = NETDB_INTERNAL; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); return (NULL); } + bufp = pvt->hostbuf; + bufsiz = sizeof pvt->hostbuf; + offset = 0; again: - if (!(p = fgets(pvt->hostbuf, sizeof pvt->hostbuf, pvt->fp))) { - h_errno = HOST_NOT_FOUND; + 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 (*p == '#') + 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; - if (!(cp = strpbrk(p, "#\n"))) + } + + p -= offset; + offset = 0; + + if (*p == '#') goto again; - *cp = '\0'; + if ((cp = strpbrk(p, "#\n")) != NULL) + *cp = '\0'; if (!(cp = strpbrk(p, " \t"))) goto again; *cp++ = '\0'; - if ((_res.options & RES_USE_INET6) && - inet_pton(AF_INET6, p, pvt->host_addr) > 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 (_res.options & RES_USE_INET6) { + if (pvt->res->options & RES_USE_INET6) { map_v4v6_address((char*)pvt->host_addr, (char*)pvt->host_addr); af = AF_INET6; @@ -360,7 +412,9 @@ ho_next(struct irs_ho *this) { *cp++ = '\0'; } *q = NULL; - h_errno = NETDB_SUCCESS; + if (dbuf) + free(dbuf); + RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS); return (&pvt->host); } @@ -389,6 +443,40 @@ ho_minimize(struct irs_ho *this) { (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; } /* Private. */ @@ -401,3 +489,15 @@ ns_namelen(const char *s) { (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/contrib/bind/lib/irs/lcl_ng.c b/contrib/bind/lib/irs/lcl_ng.c index ca7e7e2..03acbf6 100644 --- a/contrib/bind/lib/irs/lcl_ng.c +++ b/contrib/bind/lib/irs/lcl_ng.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1998 by Internet Software Consortium. + * 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 @@ -16,13 +16,17 @@ */ #if !defined(LINT) && !defined(CODECENTER) -static char rcsid[] = "$Id: lcl_ng.c,v 1.12 1998/02/13 01:10:41 halley Exp $"; +static const char rcsid[] = "$Id: lcl_ng.c,v 1.16 1999/10/13 16:39:32 vixie 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> @@ -30,6 +34,7 @@ static char rcsid[] = "$Id: lcl_ng.c,v 1.12 1998/02/13 01:10:41 halley Exp $"; #include <unistd.h> #include <irs.h> +#include <isc/memcluster.h> #include "port_after.h" @@ -100,13 +105,13 @@ irs_lcl_ng(struct irs_acc *this) { struct irs_ng *ng; struct pvt *pvt; - if (!(ng = malloc(sizeof *ng))) { + if (!(ng = memget(sizeof *ng))) { errno = ENOMEM; return (NULL); } memset(ng, 0x5e, sizeof *ng); - if (!(pvt = malloc(sizeof *pvt))) { - free(ng); + if (!(pvt = memget(sizeof *pvt))) { + memput(ng, sizeof *ng); errno = ENOMEM; return (NULL); } @@ -129,8 +134,8 @@ ng_close(struct irs_ng *this) { if (pvt->fp != NULL) fclose(pvt->fp); freelists(this); - free(pvt); - free(this); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); } /* diff --git a/contrib/bind/lib/irs/lcl_nw.c b/contrib/bind/lib/irs/lcl_nw.c index 09a324c..0d41ec4 100644 --- a/contrib/bind/lib/irs/lcl_nw.c +++ b/contrib/bind/lib/irs/lcl_nw.c @@ -32,7 +32,7 @@ */ /* - * Portions Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -49,7 +49,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: lcl_nw.c,v 1.13 1997/12/04 04:57:57 halley Exp $"; +static const char rcsid[] = "$Id: lcl_nw.c,v 1.21 1999/10/15 19:49:10 vixie 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 */ @@ -59,18 +59,21 @@ static const char rcsid[] = "$Id: lcl_nw.c,v 1.13 1997/12/04 04:57:57 halley Exp #include "port_before.h" #include <sys/types.h> +#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> -#include <sys/socket.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" @@ -87,6 +90,8 @@ struct pvt { struct nwent net; char * aliases[MAXALIASES]; char addr[MAXADDRSIZE]; + struct __res_state * res; + void (*free_res)(void *); }; /* Forward */ @@ -97,6 +102,12 @@ 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. */ @@ -111,17 +122,17 @@ irs_lcl_nw(struct irs_acc *this) { struct irs_nw *nw; struct pvt *pvt; - if (!(nw = (struct irs_nw *)malloc(sizeof *nw))) { + if (!(pvt = memget(sizeof *pvt))) { errno = ENOMEM; return (NULL); } - memset(nw, 0x5e, sizeof *nw); - if (!(pvt = (struct pvt *)malloc(sizeof *pvt))) { - free(nw); + memset(pvt, 0, sizeof *pvt); + if (!(nw = memget(sizeof *nw))) { + memput(pvt, sizeof *pvt); errno = ENOMEM; return (NULL); } - memset(pvt, 0, sizeof *pvt); + memset(nw, 0x5e, sizeof *nw); nw->private = pvt; nw->close = nw_close; nw->byname = nw_byname; @@ -129,6 +140,8 @@ irs_lcl_nw(struct irs_acc *this) { 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); } @@ -138,16 +151,22 @@ 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); - free(pvt); - free(this); + 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) @@ -161,13 +180,16 @@ 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 (strcasecmp(p->n_name, name) == 0 && + if (ns_samename(p->n_name, name) == 1 && p->n_addrtype == type) break; for (ap = p->n_aliases; *ap; ap++) - if ((strcasecmp(*ap, name) == 0) && + if ((ns_samename(*ap, name) == 1) && (p->n_addrtype == type)) goto found; } @@ -195,24 +217,60 @@ nw_rewind(struct irs_nw *this) { 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) { - h_errno = NETDB_INTERNAL; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); return (NULL); } + bufp = pvt->line; + bufsiz = sizeof(pvt->line); + again: - p = fgets(pvt->line, BUFSIZ, pvt->fp); + p = fgets(bufp + offset, bufsiz - offset, pvt->fp); if (p == NULL) - return (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) - goto again; - *cp = '\0'; + if (cp != NULL) + *cp = '\0'; pvt->net.n_name = p; cp = strpbrk(p, " \t"); if (cp == NULL) @@ -245,15 +303,67 @@ nw_next(struct irs_nw *this) { } } *q = NULL; - return (&pvt->net); + 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/contrib/bind/lib/irs/lcl_p.h b/contrib/bind/lib/irs/lcl_p.h index 058aeaa..b9e3b3e 100644 --- a/contrib/bind/lib/irs/lcl_p.h +++ b/contrib/bind/lib/irs/lcl_p.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ /* - * $Id: lcl_p.h,v 1.5 1996/10/25 07:23:19 vixie Exp $ + * $Id: lcl_p.h,v 1.7 1999/01/08 19:24:51 vixie Exp $ */ /* @@ -30,7 +30,8 @@ * Object state. */ struct lcl_p { - void *placeholder; + struct __res_state * res; + void (*free_res) __P((void *)); }; /* diff --git a/contrib/bind/lib/irs/lcl_pr.c b/contrib/bind/lib/irs/lcl_pr.c index 101f99d..5162115 100644 --- a/contrib/bind/lib/irs/lcl_pr.c +++ b/contrib/bind/lib/irs/lcl_pr.c @@ -32,7 +32,7 @@ */ /* - * Portions Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -49,7 +49,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: lcl_pr.c,v 1.11 1997/12/04 04:57:57 halley Exp $"; +static const char rcsid[] = "$Id: lcl_pr.c,v 1.18 1999/10/13 17:11:20 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ /* extern */ @@ -57,6 +57,9 @@ static const char rcsid[] = "$Id: lcl_pr.c,v 1.11 1997/12/04 04:57:57 halley Exp #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> @@ -65,6 +68,7 @@ static const char rcsid[] = "$Id: lcl_pr.c,v 1.11 1997/12/04 04:57:57 halley Exp #include <stdlib.h> #include <irs.h> +#include <isc/memcluster.h> #include "port_after.h" @@ -79,10 +83,10 @@ static const char rcsid[] = "$Id: lcl_pr.c,v 1.11 1997/12/04 04:57:57 halley Exp /* Types */ struct pvt { - FILE *fp; - char line[BUFSIZ+1]; - struct protoent proto; - char *proto_aliases[MAXALIASES]; + FILE * fp; + char line[BUFSIZ+1]; + struct protoent proto; + char * proto_aliases[MAXALIASES]; }; /* Forward */ @@ -107,12 +111,12 @@ irs_lcl_pr(struct irs_acc *this) { struct irs_pr *pr; struct pvt *pvt; - if (!(pr = (struct irs_pr *)malloc(sizeof *pr))) { + if (!(pr = memget(sizeof *pr))) { errno = ENOMEM; return (NULL); } - if (!(pvt = (struct pvt *)malloc(sizeof *pvt))) { - free(pr); + if (!(pvt = memget(sizeof *pvt))) { + memput(pr, sizeof *this); errno = ENOMEM; return (NULL); } @@ -124,6 +128,8 @@ irs_lcl_pr(struct irs_acc *this) { pr->next = pr_next; pr->rewind = pr_rewind; pr->minimize = pr_minimize; + pr->res_get = NULL; + pr->res_set = NULL; return (pr); } @@ -135,8 +141,8 @@ pr_close(struct irs_pr *this) { if (pvt->fp) (void) fclose(pvt->fp); - free(pvt); - free(this); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); } static struct protoent * @@ -189,20 +195,54 @@ 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(pvt->line, BUFSIZ, pvt->fp)) == NULL) + 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) - goto again; - *cp = '\0'; + if (cp != NULL) + *cp = '\0'; pvt->proto.p_name = p; cp = strpbrk(p, " \t"); if (cp == NULL) diff --git a/contrib/bind/lib/irs/lcl_pw.c b/contrib/bind/lib/irs/lcl_pw.c index 1f3e870..2655677 100644 --- a/contrib/bind/lib/irs/lcl_pw.c +++ b/contrib/bind/lib/irs/lcl_pw.c @@ -32,7 +32,7 @@ */ /* - * Portions Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -49,7 +49,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: lcl_pw.c,v 1.16 1998/02/13 01:10:42 halley Exp $"; +static const char rcsid[] = "$Id: lcl_pw.c,v 1.19 1999/01/18 07:46:57 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ /* Extern */ @@ -61,6 +61,10 @@ 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> @@ -73,6 +77,7 @@ static int __bind_irs_pw_unneeded; #include <utmp.h> #include <unistd.h> +#include <isc/memcluster.h> #include <irs.h> #include "port_after.h" @@ -115,12 +120,12 @@ irs_lcl_pw(struct irs_acc *this) { struct irs_pw *pw; struct pvt *pvt; - if (!(pw = malloc(sizeof *pw))) { + if (!(pw = memget(sizeof *pw))) { errno = ENOMEM; return (NULL); } memset(pw, 0x5e, sizeof *pw); - if (!(pvt = malloc(sizeof *pvt))) { + if (!(pvt = memget(sizeof *pvt))) { free(pw); errno = ENOMEM; return (NULL); @@ -133,6 +138,8 @@ irs_lcl_pw(struct irs_acc *this) { pw->byuid = pw_byuid; pw->rewind = pw_rewind; pw->minimize = pw_minimize; + pw->res_get = NULL; + pw->res_set = NULL; return (pw); } @@ -147,9 +154,9 @@ pw_close(struct irs_pw *this) { pvt->pw_db = NULL; } if (pvt->line) - free(pvt->line); - free(pvt); - free(this); + memput(pvt->line, pvt->max); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); } static struct passwd * @@ -262,9 +269,20 @@ hashpw(struct irs_pw *this, DBT *key) { if ((pvt->pw_db->get)(pvt->pw_db, key, &data, 0)) return (0); p = (char *)data.data; - if (data.size > pvt->max && - (pvt->line = realloc(pvt->line, pvt->max += 1024)) == NULL) - return (0); + 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; diff --git a/contrib/bind/lib/irs/lcl_sv.c b/contrib/bind/lib/irs/lcl_sv.c index 0da9984..7e5bec9 100644 --- a/contrib/bind/lib/irs/lcl_sv.c +++ b/contrib/bind/lib/irs/lcl_sv.c @@ -32,7 +32,7 @@ */ /* - * Portions Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -49,7 +49,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: lcl_sv.c,v 1.11 1997/12/04 04:57:58 halley Exp $"; +static const char rcsid[] = "$Id: lcl_sv.c,v 1.20 1999/10/07 20:44:03 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ /* extern */ @@ -58,31 +58,42 @@ static const char rcsid[] = "$Id: lcl_sv.c,v 1.11 1997/12/04 04:57:58 halley Exp #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" -#define MAXALIASES 35 +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) ((size_t)sprintf x) +#endif /* Types */ struct pvt { - FILE * fp; - char line[BUFSIZ+1]; - struct servent serv; - char * serv_aliases[MAXALIASES]; +#ifdef IRS_LCL_SV_DB + DB * dbh; + int dbf; +#endif + struct lcl_sv sv; }; /* Forward */ @@ -94,6 +105,10 @@ static struct servent * sv_byname(struct irs_sv *, 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 */ @@ -108,13 +123,13 @@ irs_lcl_sv(struct irs_acc *this) { struct irs_sv *sv; struct pvt *pvt; - if (!(sv = (struct irs_sv *)malloc(sizeof *sv))) { + if ((sv = memget(sizeof *sv)) == NULL) { errno = ENOMEM; return (NULL); } memset(sv, 0x5e, sizeof *sv); - if (!(pvt = (struct pvt *)malloc(sizeof *pvt))) { - free(sv); + if ((pvt = memget(sizeof *pvt)) == NULL) { + memput(sv, sizeof *sv); errno = ENOMEM; return (NULL); } @@ -126,6 +141,11 @@ irs_lcl_sv(struct irs_acc *this) { 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); } @@ -135,120 +155,278 @@ static void sv_close(struct irs_sv *this) { struct pvt *pvt = (struct pvt *)this->private; - if (pvt->fp) - fclose(pvt->fp); - free(pvt); - free(this); +#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) { - register struct servent *p; - register char **cp; - - sv_rewind(this); - 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; +#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; + 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) { - register struct servent *p; - - sv_rewind(this); - while ((p = sv_next(this))) { - if (p->s_port != port) - continue; - if (proto == NULL || strcmp(p->s_proto, proto) == 0) - break; - } - return (p); +#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->fp) { - if (fseek(pvt->fp, 0L, SEEK_SET) == 0) + if (pvt->sv.fp) { + if (fseek(pvt->sv.fp, 0L, SEEK_SET) == 0) return; - (void)fclose(pvt->fp); + (void)fclose(pvt->sv.fp); + pvt->sv.fp = NULL; } - if (!(pvt->fp = fopen(_PATH_SERVICES, "r" ))) +#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; - if (fcntl(fileno(pvt->fp), F_SETFD, 1) < 0) { - (void)fclose(pvt->fp); - pvt->fp = NULL; + } +#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; - char *p; - register char *cp, **q; - if (!pvt->fp) +#ifdef IRS_LCL_SV_DB + if (pvt->dbh != NULL) + NULL; + else +#endif + if (pvt->sv.fp != NULL) + NULL; + else sv_rewind(this); - if (!pvt->fp) + +#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(pvt->line, BUFSIZ, pvt->fp)) == NULL) + if ((p = fgets(sv->line, BUFSIZ, sv->fp)) == NULL) return (NULL); if (*p == '#') goto again; - cp = strpbrk(p, "#\n"); - if (cp == NULL) - goto again; - *cp = '\0'; - pvt->serv.s_name = p; - p = strpbrk(p, " \t"); - if (p == NULL) + 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++; - cp = strpbrk(p, ",/"); - if (cp == NULL) + if (*p == '\0' || *p == '#' || *p == '\n') goto again; - *cp++ = '\0'; - pvt->serv.s_port = htons((u_short)atoi(p)); - pvt->serv.s_proto = cp; - q = pvt->serv.s_aliases = pvt->serv_aliases; - cp = strpbrk(cp, " \t"); - if (cp != NULL) - *cp++ = '\0'; - while (cp && *cp) { - if (*cp == ' ' || *cp == '\t') { - cp++; - continue; - } - if (q < &pvt->serv_aliases[MAXALIASES - 1]) - *q++ = cp; - cp = strpbrk(cp, " \t"); - if (cp != NULL) - *cp++ = '\0'; + 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 (&pvt->serv); + return (&sv->serv); } -static void -sv_minimize(struct irs_sv *this) { - struct pvt *pvt = (struct pvt *)this->private; +/* Private. */ - if (pvt->fp != NULL) { - (void)fclose(pvt->fp); - pvt->fp = NULL; +#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/contrib/bind/lib/irs/nis.c b/contrib/bind/lib/irs/nis.c index d53bde9..fcd9b79 100644 --- a/contrib/bind/lib/irs/nis.c +++ b/contrib/bind/lib/irs/nis.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1998 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: nis.c,v 1.10 1998/03/21 00:59:50 halley Exp $"; +static const char rcsid[] = "$Id: nis.c,v 1.13 1999/01/18 07:46:58 vixie Exp $"; #endif /* Imports */ @@ -34,6 +34,12 @@ static const char rcsid[] = "$Id: nis.c,v 1.10 1998/03/21 00:59:50 halley Exp $" #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" @@ -45,6 +51,9 @@ static const char rcsid[] = "$Id: nis.c,v 1.10 1998/03/21 00:59:50 halley Exp $" /* 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 */ @@ -56,13 +65,13 @@ irs_nis_acc(const char *options) { if (yp_get_default_domain(&domain) != 0) return (NULL); - if (!(nis = malloc(sizeof *nis))) { + if (!(nis = memget(sizeof *nis))) { errno = ENOMEM; return (NULL); } memset(nis, 0, sizeof *nis); - if (!(acc = malloc(sizeof *acc))) { - free(nis); + if (!(acc = memget(sizeof *acc))) { + memput(nis, sizeof *nis); errno = ENOMEM; return (NULL); } @@ -84,19 +93,57 @@ irs_nis_acc(const char *options) { 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); - free(nis); - free(this); + memput(nis, sizeof *nis); + memput(this, sizeof *this); } #endif /*WANT_IRS_NIS*/ diff --git a/contrib/bind/lib/irs/nis_gr.c b/contrib/bind/lib/irs/nis_gr.c index aa2f30c..713437a 100644 --- a/contrib/bind/lib/irs/nis_gr.c +++ b/contrib/bind/lib/irs/nis_gr.c @@ -32,7 +32,7 @@ */ /* - * Portions Copyright (c) 1996, 1997, 1998 by Internet Software Consortium. + * 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 @@ -49,7 +49,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: nis_gr.c,v 1.13 1998/03/21 00:59:50 halley Exp $"; +static const char rcsid[] = "$Id: nis_gr.c,v 1.20 1999/01/30 00:53:16 vixie 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 */ @@ -64,6 +64,10 @@ static int __bind_irs_gr_unneeded; #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> @@ -77,6 +81,8 @@ static int __bind_irs_gr_unneeded; #include <string.h> #include <unistd.h> +#include <isc/memcluster.h> + #include <irs.h> #include "port_after.h" @@ -130,13 +136,13 @@ irs_nis_gr(struct irs_acc *this) { struct irs_gr *gr; struct pvt *pvt; - if (!(gr = malloc(sizeof *gr))) { + if (!(gr = memget(sizeof *gr))) { errno = ENOMEM; return (NULL); } memset(gr, 0x5e, sizeof *gr); - if (!(pvt = malloc(sizeof *pvt))) { - free(gr); + if (!(pvt = memget(sizeof *pvt))) { + memput(gr, sizeof *gr); errno = ENOMEM; return (NULL); } @@ -151,6 +157,8 @@ irs_nis_gr(struct irs_acc *this) { gr->rewind = gr_rewind; gr->list = make_group_list; gr->minimize = gr_minimize; + gr->res_get = NULL; + gr->res_set = NULL; return (gr); } @@ -164,8 +172,8 @@ gr_close(struct irs_gr *this) { free(pvt->group.gr_mem); if (pvt->membuf) free(pvt->membuf); - free(pvt); - free(this); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); } static struct group * @@ -286,6 +294,9 @@ makegroupent(struct irs_gr *this) { goto cleanup; cp++; + if (*cp && cp[strlen(cp)-1] == '\n') + cp[strlen(cp)-1] = '\0'; + /* * Parse the members out. */ diff --git a/contrib/bind/lib/irs/nis_ho.c b/contrib/bind/lib/irs/nis_ho.c index 65bdb4b..07d2274 100644 --- a/contrib/bind/lib/irs/nis_ho.c +++ b/contrib/bind/lib/irs/nis_ho.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char rcsid[] = "$Id: nis_ho.c,v 1.10 1997/12/04 04:57:59 halley Exp $"; +static const char rcsid[] = "$Id: nis_ho.c,v 1.16 1999/10/13 16:39:32 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ /* Imports */ @@ -46,6 +46,7 @@ static int __bind_irs_nis_unneeded; #include <stdio.h> #include <string.h> +#include <isc/memcluster.h> #include <irs.h> #include "port_after.h" @@ -53,8 +54,6 @@ static int __bind_irs_nis_unneeded; #include "irs_p.h" #include "nis_p.h" -extern int h_errno; - /* Definitions */ #define MAXALIASES 35 @@ -78,6 +77,8 @@ struct pvt { 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 }; @@ -98,9 +99,14 @@ static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr, 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 hostent * makehostent(struct irs_ho *this); static void nisfree(struct pvt *, enum do_what); +static int init(struct irs_ho *this); /* Public */ @@ -109,17 +115,17 @@ irs_nis_ho(struct irs_acc *this) { struct irs_ho *ho; struct pvt *pvt; - if (!(ho = malloc(sizeof *ho))) { + if (!(pvt = memget(sizeof *pvt))) { errno = ENOMEM; return (NULL); } - memset(ho, 0x5e, sizeof *ho); - if (!(pvt = (struct pvt *)malloc(sizeof *pvt))) { - free(ho); + memset(pvt, 0, sizeof *pvt); + if (!(ho = memget(sizeof *ho))) { + memput(pvt, sizeof *pvt); errno = ENOMEM; return (NULL); } - memset(pvt, 0, sizeof *pvt); + memset(ho, 0x5e, sizeof *ho); pvt->needrewind = 1; pvt->nis_domain = ((struct nis_p *)this->private)->domain; ho->private = pvt; @@ -130,6 +136,8 @@ irs_nis_ho(struct irs_acc *this) { ho->next = ho_next; ho->rewind = ho_rewind; ho->minimize = ho_minimize; + ho->res_set = ho_res_set; + ho->res_get = ho_res_get; return (ho); } @@ -139,18 +147,23 @@ static void ho_close(struct irs_ho *this) { struct pvt *pvt = (struct pvt *)this->private; + ho_minimize(this); nisfree(pvt, do_all); - free(pvt); - free(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 hostent *hp; - if ((_res.options & RES_INIT) == 0 && res_init() == -1) + if (init(this) == -1) return (NULL); - if (_res.options & RES_USE_INET6) { + + if (pvt->res->options & RES_USE_INET6) { hp = ho_byname2(this, name, AF_INET6); if (hp) return (hp); @@ -163,11 +176,14 @@ ho_byname2(struct irs_ho *this, const char *name, int af) { struct pvt *pvt = (struct pvt *)this->private; int r; + if (init(this) == -1) + return (NULL); + nisfree(pvt, do_val); r = yp_match(pvt->nis_domain, hosts_byname, (char *)name, strlen(name), &pvt->curval_data, &pvt->curval_len); if (r != 0) { - h_errno = HOST_NOT_FOUND; + RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); return (NULL); } return (makehostent(this)); @@ -180,6 +196,9 @@ ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) { 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))) { @@ -190,14 +209,14 @@ ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) { len = INADDRSZ; } if (inet_ntop(af, uaddr, tmp, sizeof tmp) == NULL) { - h_errno = NETDB_INTERNAL; + 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) { - h_errno = HOST_NOT_FOUND; + RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); return (NULL); } return (makehostent(this)); @@ -209,6 +228,9 @@ ho_next(struct irs_ho *this) { struct hostent *rval; int r; + if (init(this) == -1) + return (NULL); + do { if (pvt->needrewind) { nisfree(pvt, do_all); @@ -230,7 +252,7 @@ ho_next(struct irs_ho *this) { pvt->curkey_len = newkey_len; } if (r != 0) { - h_errno = HOST_NOT_FOUND; + RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); return (NULL); } rval = makehostent(this); @@ -247,7 +269,42 @@ ho_rewind(struct irs_ho *this) { static void ho_minimize(struct irs_ho *this) { - /* NOOP */ + 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; } /* Private */ @@ -260,17 +317,17 @@ makehostent(struct irs_ho *this) { int af, len; p = pvt->curval_data; - if ((cp = strchr(p, '#')) != NULL) + if ((cp = strpbrk(p, "#\n")) != NULL) *cp = '\0'; if (!(cp = strpbrk(p, spaces))) return (NULL); *cp++ = '\0'; - if ((_res.options & RES_USE_INET6) && + 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 (_res.options & RES_USE_INET6) { + if (pvt->res->options & RES_USE_INET6) { map_v4v6_address((char*)pvt->host_addr, (char*)pvt->host_addr); af = AF_INET6; @@ -303,7 +360,7 @@ makehostent(struct irs_ho *this) { *cp++ = '\0'; } *q = NULL; - h_errno = NETDB_SUCCESS; + RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS); return (&pvt->host); } @@ -319,4 +376,15 @@ nisfree(struct pvt *pvt, enum do_what do_what) { } } +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/contrib/bind/lib/irs/nis_ng.c b/contrib/bind/lib/irs/nis_ng.c index 1667ca6..88d97ff 100644 --- a/contrib/bind/lib/irs/nis_ng.c +++ b/contrib/bind/lib/irs/nis_ng.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: nis_ng.c,v 1.10 1997/12/04 04:58:00 halley Exp $"; +static const char rcsid[] = "$Id: nis_ng.c,v 1.16 1999/01/18 07:46:58 vixie Exp $"; #endif /* Imports */ @@ -34,7 +34,7 @@ static int __bind_irs_nis_unneeded; #include <rpcsvc/yp_prot.h> #include <rpcsvc/ypclnt.h> -#include <assert.h> +#include <isc/assertions.h> #include <ctype.h> #include <errno.h> #include <netdb.h> @@ -42,6 +42,11 @@ static int __bind_irs_nis_unneeded; #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" @@ -91,13 +96,13 @@ irs_nis_ng(struct irs_acc *this) { struct irs_ng *ng; struct pvt *pvt; - if (!(ng = malloc(sizeof *ng))) { + if (!(ng = memget(sizeof *ng))) { errno = ENOMEM; return (NULL); } memset(ng, 0x5e, sizeof *ng); - if (!(pvt = (struct pvt *)malloc(sizeof *pvt))) { - free(ng); + if (!(pvt = memget(sizeof *pvt))) { + memput(ng, sizeof *ng); errno = ENOMEM; return (NULL); } @@ -119,14 +124,13 @@ ng_close(struct irs_ng *this) { struct pvt *pvt = (struct pvt *)this->private; tmpfree(pvt); - free(pvt); - free(this); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); } static int ng_next(struct irs_ng *this, char **host, char **user, char **domain) { struct pvt *pvt = (struct pvt *)this->private; - struct netgrp *rval; if (!pvt->cur) return (0); @@ -159,7 +163,6 @@ ng_test(struct irs_ng *this, const char *name, static void ng_rewind(struct irs_ng *this, const char *name) { struct pvt *pvt = (struct pvt *)this->private; - struct netgrp *rval; /* Either hand back or free the existing list. */ if (pvt->tmpgroup) { @@ -194,7 +197,10 @@ add_group_to_list(struct pvt *pvt, const char *name, int len) { r = yp_match(pvt->nis_domain, netgroup_map, (char *)name, len, &vdata, &vlen); if (r == 0) { - for (cp = vdata; cp; cp = np) { + 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'; @@ -212,7 +218,7 @@ add_tuple_to_list(struct pvt *pvt, const char *name, char *cp) { struct tmpgrp *tmp; char *tp, *np; - assert(*cp++ == '('); + INSIST(*cp++ == '('); tmp = malloc(sizeof *tmp + strlen(name) + sizeof '\0' + strlen(cp) - sizeof ')'); diff --git a/contrib/bind/lib/irs/nis_nw.c b/contrib/bind/lib/irs/nis_nw.c index b9e9e79..72ec391 100644 --- a/contrib/bind/lib/irs/nis_nw.c +++ b/contrib/bind/lib/irs/nis_nw.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: nis_nw.c,v 1.10 1997/12/04 04:58:00 halley Exp $"; +static const char rcsid[] = "$Id: nis_nw.c,v 1.15 1999/01/18 07:46:58 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ /* Imports */ @@ -28,20 +28,24 @@ static int __bind_irs_nis_unneeded; #else #include <sys/types.h> +#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> -#include <sys/socket.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" @@ -67,6 +71,9 @@ struct pvt { 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 }; @@ -82,9 +89,14 @@ 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 */ @@ -93,17 +105,17 @@ irs_nis_nw(struct irs_acc *this) { struct irs_nw *nw; struct pvt *pvt; - if (!(nw = (struct irs_nw *)malloc(sizeof *nw))) { + if (!(pvt = memget(sizeof *pvt))) { errno = ENOMEM; return (NULL); } - memset(nw, 0x5e, sizeof *nw); - if (!(pvt = (struct pvt *)malloc(sizeof *pvt))) { - free(nw); + memset(pvt, 0, sizeof *pvt); + if (!(nw = memget(sizeof *nw))) { + memput(pvt, sizeof *pvt); errno = ENOMEM; return (NULL); } - memset(pvt, 0, sizeof *pvt); + memset(nw, 0x5e, sizeof *nw); pvt->needrewind = 1; pvt->nis_domain = ((struct nis_p *)this->private)->domain; nw->private = pvt; @@ -113,6 +125,8 @@ irs_nis_nw(struct irs_acc *this) { 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); } @@ -122,10 +136,13 @@ 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); - free(pvt); - free(this); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); } static struct nwent * @@ -134,15 +151,18 @@ nw_byaddr(struct irs_nw *this, void *net, int length, int af) { char tmp[sizeof "255.255.255.255/32"], *t; int r; + if (init(this) == -1) + return (NULL); + if (af != AF_INET) { - h_errno = NETDB_INTERNAL; + 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) { - h_errno = NETDB_INTERNAL; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); return (NULL); } r = yp_match(pvt->nis_domain, networks_byaddr, tmp, strlen(tmp), @@ -156,7 +176,7 @@ nw_byaddr(struct irs_nw *this, void *net, int length, int af) { &pvt->curval_data, &pvt->curval_len); } if (r != 0) { - h_errno = HOST_NOT_FOUND; + RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); return (NULL); } } @@ -168,8 +188,11 @@ 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) { - h_errno = NETDB_INTERNAL; + RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); errno = EAFNOSUPPORT; return (NULL); } @@ -177,7 +200,7 @@ nw_byname(struct irs_nw *this, const char *name, int af) { r = yp_match(pvt->nis_domain, networks_byname, (char *)name, strlen(name), &pvt->curval_data, &pvt->curval_len); if (r != 0) { - h_errno = HOST_NOT_FOUND; + RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); return (NULL); } return (makenwent(this)); @@ -196,6 +219,9 @@ nw_next(struct irs_nw *this) { struct nwent *rval; int r; + if (init(this) == -1) + return (NULL); + do { if (pvt->needrewind) { nisfree(pvt, do_all); @@ -217,7 +243,7 @@ nw_next(struct irs_nw *this) { pvt->curkey_len = newkey_len; } if (r != 0) { - h_errno = HOST_NOT_FOUND; + RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); return (NULL); } rval = makenwent(this); @@ -227,15 +253,50 @@ nw_next(struct irs_nw *this) { static void nw_minimize(struct irs_nw *this) { - /* NOOP */ + 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) { - static const char spaces[] = " \t"; struct pvt *pvt = (struct pvt *)this->private; + static const char spaces[] = " \t"; char *t, *cp, **ap; if (pvt->nwbuf) @@ -243,7 +304,7 @@ makenwent(struct irs_nw *this) { pvt->nwbuf = pvt->curval_data; pvt->curval_data = NULL; - if ((cp = strchr(pvt->nwbuf, '#')) != NULL) + if ((cp = strpbrk(pvt->nwbuf, "#\n")) != NULL) *cp = '\0'; cp = pvt->nwbuf; @@ -303,4 +364,16 @@ nisfree(struct pvt *pvt, enum do_what do_what) { } } +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/contrib/bind/lib/irs/nis_p.h b/contrib/bind/lib/irs/nis_p.h index 92d2647..d3dc126 100644 --- a/contrib/bind/lib/irs/nis_p.h +++ b/contrib/bind/lib/irs/nis_p.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ /* - * $Id: nis_p.h,v 1.4 1996/10/25 07:23:24 vixie Exp $ + * $Id: nis_p.h,v 1.6 1999/01/08 19:25:03 vixie Exp $ */ /* @@ -27,7 +27,9 @@ * Object state. */ struct nis_p { - char * domain; + char * domain; + struct __res_state * res; + void (*free_res) __P((void *)); }; diff --git a/contrib/bind/lib/irs/nis_pr.c b/contrib/bind/lib/irs/nis_pr.c index 1653692..8dff084 100644 --- a/contrib/bind/lib/irs/nis_pr.c +++ b/contrib/bind/lib/irs/nis_pr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: nis_pr.c,v 1.9 1997/12/04 04:58:00 halley Exp $"; +static const char rcsid[] = "$Id: nis_pr.c,v 1.13 1999/01/18 07:46:59 vixie Exp $"; #endif /* Imports */ @@ -29,6 +29,8 @@ static int __bind_irs_nis_unneeded; #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> @@ -41,6 +43,7 @@ static int __bind_irs_nis_unneeded; #include <stdlib.h> #include <errno.h> +#include <isc/memcluster.h> #include <irs.h> #include "port_after.h" @@ -85,13 +88,13 @@ irs_nis_pr(struct irs_acc *this) { struct irs_pr *pr; struct pvt *pvt; - if (!(pr = malloc(sizeof *pr))) { + if (!(pr = memget(sizeof *pr))) { errno = ENOMEM; return (NULL); } memset(pr, 0x5e, sizeof *pr); - if (!(pvt = malloc(sizeof *pvt))) { - free(pr); + if (!(pvt = memget(sizeof *pvt))) { + memput(pr, sizeof *pr); errno = ENOMEM; return (NULL); } @@ -105,6 +108,8 @@ irs_nis_pr(struct irs_acc *this) { pr->rewind = pr_rewind; pr->close = pr_close; pr->minimize = pr_minimize; + pr->res_get = NULL; + pr->res_set = NULL; return (pr); } @@ -119,8 +124,8 @@ pr_close(struct irs_pr *this) { free(pvt->proto.p_aliases); if (pvt->prbuf) free(pvt->prbuf); - free(pvt); - free(this); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); } static struct protoent * @@ -182,7 +187,7 @@ pr_next(struct irs_pr *this) { pvt->curkey_len = newkey_len; } if (r != 0) { - h_errno = HOST_NOT_FOUND; + errno = ENOENT; return (NULL); } rval = makeprotoent(this); diff --git a/contrib/bind/lib/irs/nis_pw.c b/contrib/bind/lib/irs/nis_pw.c index f06f796..ce90f20 100644 --- a/contrib/bind/lib/irs/nis_pw.c +++ b/contrib/bind/lib/irs/nis_pw.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: nis_pw.c,v 1.10 1997/12/04 04:58:01 halley Exp $"; +static const char rcsid[] = "$Id: nis_pw.c,v 1.16 1999/01/30 00:53:16 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ /* Imports */ @@ -28,6 +28,11 @@ 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> @@ -41,6 +46,8 @@ static int __bind_irs_pw_unneeded; #include <string.h> #include <unistd.h> +#include <isc/memcluster.h> + #include <irs.h> #include "port_after.h" @@ -85,13 +92,13 @@ irs_nis_pw(struct irs_acc *this) { struct irs_pw *pw; struct pvt *pvt; - if (!(pw = malloc(sizeof *pw))) { + if (!(pw = memget(sizeof *pw))) { errno = ENOMEM; return (NULL); } memset(pw, 0x5e, sizeof *pw); - if (!(pvt = malloc(sizeof *pvt))) { - free(pw); + if (!(pvt = memget(sizeof *pvt))) { + memput(pw, sizeof *pw); errno = ENOMEM; return (NULL); } @@ -99,13 +106,15 @@ irs_nis_pw(struct irs_acc *this) { 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->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); + pw->res_get = NULL; + pw->res_set = NULL; + return (pw); } /* Methods */ @@ -117,8 +126,8 @@ pw_close(struct irs_pw *this) { if (pvt->pwbuf) free(pvt->pwbuf); nisfree(pvt, do_all); - free(pvt); - free(this); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); } static struct passwd * @@ -155,7 +164,7 @@ pw_next(struct irs_pw *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; @@ -170,7 +179,7 @@ pw_byname(struct irs_pw *this, const char *name) { } return (makepasswdent(this)); } - + static struct passwd * pw_byuid(struct irs_pw *this, uid_t uid) { struct pvt *pvt = (struct pvt *)this->private; @@ -246,6 +255,10 @@ makepasswdent(struct irs_pw *this) { *cp++ = '\0'; pvt->passwd.pw_shell = cp; + + if ((cp = strchr(cp, '\n')) != NULL) + *cp = '\0'; + return (&pvt->passwd); cleanup: diff --git a/contrib/bind/lib/irs/nis_sv.c b/contrib/bind/lib/irs/nis_sv.c index 1dacc2f..8810fd2 100644 --- a/contrib/bind/lib/irs/nis_sv.c +++ b/contrib/bind/lib/irs/nis_sv.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: nis_sv.c,v 1.10 1997/12/04 04:58:01 halley Exp $"; +static const char rcsid[] = "$Id: nis_sv.c,v 1.14 1999/01/18 07:46:59 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ /* Imports */ @@ -28,6 +28,9 @@ 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> @@ -40,6 +43,7 @@ static int __bind_irs_nis_unneeded; #include <stdlib.h> #include <string.h> +#include <isc/memcluster.h> #include <irs.h> #include "port_after.h" @@ -85,13 +89,13 @@ irs_nis_sv(struct irs_acc *this) { struct irs_sv *sv; struct pvt *pvt; - if (!(sv = (struct irs_sv *)malloc(sizeof *sv))) { + if (!(sv = memget(sizeof *sv))) { errno = ENOMEM; return (NULL); } memset(sv, 0x5e, sizeof *sv); - if (!(pvt = (struct pvt *)malloc(sizeof *pvt))) { - free(sv); + if (!(pvt = memget(sizeof *pvt))) { + memput(sv, sizeof *sv); errno = ENOMEM; return (NULL); } @@ -105,6 +109,8 @@ irs_nis_sv(struct irs_acc *this) { sv->byport = sv_byport; sv->rewind = sv_rewind; sv->minimize = sv_minimize; + sv->res_get = NULL; + sv->res_set = NULL; return (sv); } @@ -119,8 +125,8 @@ sv_close(struct irs_sv *this) { free(pvt->serv.s_aliases); if (pvt->svbuf) free(pvt->svbuf); - free(pvt); - free(this); + memput(pvt, sizeof *pvt); + memput(this, sizeof *this); } static struct servent * @@ -221,7 +227,7 @@ makeservent(struct irs_sv *this) { pvt->serv.s_aliases = NULL; } - if ((p = strchr(pvt->svbuf, '#'))) + if ((p = strpbrk(pvt->svbuf, "#\n"))) *p = '\0'; p = pvt->svbuf; diff --git a/contrib/bind/lib/irs/nul_ng.c b/contrib/bind/lib/irs/nul_ng.c index 0910d57..cc5c801 100644 --- a/contrib/bind/lib/irs/nul_ng.c +++ b/contrib/bind/lib/irs/nul_ng.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: nul_ng.c,v 1.7 1997/12/04 04:58:01 halley Exp $"; +static const char rcsid[] = "$Id: nul_ng.c,v 1.10 1999/01/18 07:46:59 vixie Exp $"; #endif /* @@ -27,6 +27,8 @@ static const char rcsid[] = "$Id: nul_ng.c,v 1.7 1997/12/04 04:58:01 halley Exp #include <sys/types.h> #include <netinet/in.h> +#include <arpa/nameser.h> +#include <resolv.h> #include <stdio.h> #include <string.h> @@ -36,6 +38,7 @@ static const char rcsid[] = "$Id: nul_ng.c,v 1.7 1997/12/04 04:58:01 halley Exp #include <errno.h> #include <irs.h> +#include <isc/memcluster.h> #include "port_after.h" @@ -59,7 +62,7 @@ struct irs_ng * irs_nul_ng(struct irs_acc *this) { struct irs_ng *ng; - if (!(ng = malloc(sizeof *ng))) { + if (!(ng = memget(sizeof *ng))) { errno = ENOMEM; return (NULL); } @@ -77,7 +80,7 @@ irs_nul_ng(struct irs_acc *this) { static void ng_close(struct irs_ng *this) { - free(this); + memput(this, sizeof *this); } /* ARGSUSED */ diff --git a/contrib/bind/lib/irs/pathnames.h b/contrib/bind/lib/irs/pathnames.h index 40a0472..1a225e5 100644 --- a/contrib/bind/lib/irs/pathnames.h +++ b/contrib/bind/lib/irs/pathnames.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ /* - * $Id: pathnames.h,v 1.5 1996/10/25 07:23:28 vixie Exp $ + * $Id: pathnames.h,v 1.7 1999/01/08 19:25:10 vixie Exp $ */ #ifndef _PATH_IRS_CONF @@ -39,6 +39,12 @@ #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/contrib/bind/lib/irs/util.c b/contrib/bind/lib/irs/util.c index f58f5ca2..8965af5 100644 --- a/contrib/bind/lib/irs/util.c +++ b/contrib/bind/lib/irs/util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: util.c,v 1.7 1997/12/04 04:58:02 halley Exp $"; +static const char rcsid[] = "$Id: util.c,v 1.10 1999/01/08 19:25:11 vixie Exp $"; #endif #include "port_before.h" @@ -25,8 +25,8 @@ static const char rcsid[] = "$Id: util.c,v 1.7 1997/12/04 04:58:02 halley Exp $" #include <sys/socket.h> #include <netinet/in.h> #include <arpa/nameser.h> +#include <resolv.h> -#include <assert.h> #include <ctype.h> #include <errno.h> #include <stdio.h> diff --git a/contrib/bind/lib/isc/Makefile b/contrib/bind/lib/isc/Makefile index cdcac69..87e20f2 100644 --- a/contrib/bind/lib/isc/Makefile +++ b/contrib/bind/lib/isc/Makefile @@ -1,4 +1,4 @@ -# Copyright (c) 1996 by Internet Software Consortium +# 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 @@ -13,7 +13,7 @@ # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS # SOFTWARE. -# $Id: Makefile,v 8.15 1997/12/03 22:36:08 halley Exp $ +# $Id: Makefile,v 8.22 1999/02/22 02:47:58 vixie Exp $ # these are only appropriate for BSD 4.4 or derivatives, and are used in # development. normal builds will be done in the top level directory and @@ -31,37 +31,55 @@ TOP= ../.. INCL = ${TOP}/include PORTINCL = ${TOP}/port/${SYSTYPE}/include LIBBIND = ${TOP}/lib/libbind.${A} +LIBBINDR = ../${TOP}/lib/libbind_r.${A} CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL} +# -Wimplicit LD_LIBFLAGS= -x -r -AR= ar cruv +AR= ar cru RANLIB= ranlib INSTALL= install +INSTALL_EXEC= +INSTALL_LIB=-o bin -g bin +THREADED= threaded SRCS= tree.c base64.c bitncmp.c assertions.c \ memcluster.c logging.c heap.c \ + ctl_p.c ctl_srvr.c ctl_clnt.c \ eventlib.c ev_connects.c ev_files.c \ ev_timers.c ev_streams.c ev_waits.c OBJS= tree.${O} base64.${O} bitncmp.${O} assertions.${O} \ memcluster.${O} logging.${O} heap.${O} \ + ctl_p.${O} ctl_srvr.${O} ctl_clnt.${O} \ eventlib.${O} ev_connects.${O} ev_files.${O} \ ev_timers.${O} ev_streams.${O} ev_waits.${O} all: ${LIBBIND} ${LIBBIND}: ${OBJS} + ( cd ${THREADED} ; \ + ${AR} ${LIBBINDR} ${ARPREF} ${OBJS} ${ARSUFF} ; \ + ${RANLIB} ${LIBBINDR} ) ${AR} ${LIBBIND} ${ARPREF} ${OBJS} ${ARSUFF} ${RANLIB} ${LIBBIND} .c.${O}: - ${CC} ${CPPFLAGS} ${CFLAGS} -c $*.c - -${LDS} ${LD} ${LD_LIBFLAGS} $*.${O} && ${LDS} mv a.out $*.${O} + if test ! -d ${THREADED} ; then mkdir ${THREADED} ; fi + ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} ${REENTRANT} -c $*.c \ + -o ${THREADED}/$*.${O} + -${LDS} ${LD} ${LD_LIBFLAGS} ${THREADED}/$*.${O} -o a.out && \ + ${LDS} mv a.out ${THREADED}/$*.${O} + ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c + -${LDS} ${LD} ${LD_LIBFLAGS} $*.${O} -o a.out && \ + ${LDS} mv a.out $*.${O} distclean: clean clean: FRC rm -f .depend a.out core ${LIB} tags rm -f *.${O} *.BAK *.CKP *~ + rm -f ${THREADED}/*.${O} + -rmdir ${THREADED} depend: FRC mkdep -I${INCL} -I${PORTINCL} ${CPPFLAGS} ${SRCS} diff --git a/contrib/bind/lib/isc/assertions.c b/contrib/bind/lib/isc/assertions.c index 949d4d2..b53cc0a 100644 --- a/contrib/bind/lib/isc/assertions.c +++ b/contrib/bind/lib/isc/assertions.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if !defined(LINT) && !defined(CODECENTER) -static const char rcsid[] = "$Id: assertions.c,v 8.2 1997/12/08 21:29:05 halley Exp $"; +static const char rcsid[] = "$Id: assertions.c,v 8.3 1999/01/08 19:25:14 vixie Exp $"; #endif #include "port_before.h" diff --git a/contrib/bind/lib/isc/assertions.mdoc b/contrib/bind/lib/isc/assertions.mdoc index e82d9f9..3d8d103 100644 --- a/contrib/bind/lib/isc/assertions.mdoc +++ b/contrib/bind/lib/isc/assertions.mdoc @@ -1,6 +1,6 @@ -.\" $Id: assertions.mdoc,v 8.1 1997/12/03 22:33:30 halley Exp $ +.\" $Id: assertions.mdoc,v 8.2 1999/01/08 19:25:15 vixie Exp $ .\" -.\"Copyright (c) 1997 by Internet Software Consortium. +.\"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 diff --git a/contrib/bind/lib/isc/base64.c b/contrib/bind/lib/isc/base64.c index 58e700e..c1eebe6 100644 --- a/contrib/bind/lib/isc/base64.c +++ b/contrib/bind/lib/isc/base64.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1998 by Internet Software Consortium. + * 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 @@ -41,7 +41,7 @@ */ #if !defined(LINT) && !defined(CODECENTER) -static char rcsid[] = "$Id: base64.c,v 8.5 1998/03/27 00:17:46 halley Exp $"; +static const char rcsid[] = "$Id: base64.c,v 8.7 1999/10/13 16:39:33 vixie Exp $"; #endif /* not lint */ #include "port_before.h" diff --git a/contrib/bind/lib/isc/bitncmp.c b/contrib/bind/lib/isc/bitncmp.c index 473f4f7..8dadca0 100644 --- a/contrib/bind/lib/isc/bitncmp.c +++ b/contrib/bind/lib/isc/bitncmp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: bitncmp.c,v 1.5 1996/11/18 09:09:48 vixie Exp $"; +static const char rcsid[] = "$Id: bitncmp.c,v 1.6 1999/01/08 19:25:20 vixie Exp $"; #endif #include "port_before.h" diff --git a/contrib/bind/lib/isc/bitncmp.mdoc b/contrib/bind/lib/isc/bitncmp.mdoc index 99c6c25..4fa12e8 100644 --- a/contrib/bind/lib/isc/bitncmp.mdoc +++ b/contrib/bind/lib/isc/bitncmp.mdoc @@ -1,6 +1,6 @@ -.\" $Id: bitncmp.mdoc,v 8.1 1997/01/30 20:27:23 vixie Exp $ +.\" $Id: bitncmp.mdoc,v 8.2 1999/01/08 19:25:21 vixie Exp $ .\" -.\"Copyright (c) 1996 by Internet Software Consortium. +.\"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 diff --git a/contrib/bind/lib/isc/ctl_clnt.c b/contrib/bind/lib/isc/ctl_clnt.c new file mode 100644 index 0000000..66f32f8 --- /dev/null +++ b/contrib/bind/lib/isc/ctl_clnt.c @@ -0,0 +1,581 @@ +#if !defined(lint) && !defined(SABER) +static const char rcsid[] = "$Id: ctl_clnt.c,v 8.14 1999/10/13 16:39:33 vixie 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, + (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, (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; + 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; + APPEND(ctx->tran, new, link); + if (w) + APPEND(ctx->wtran, new, wlink); + else + INIT_LINK(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; + + 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); + *iovp++ = evConsIovec("\r\n", 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; + + 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; + + 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; + + 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; + + 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/contrib/bind/lib/isc/ctl_p.c b/contrib/bind/lib/isc/ctl_p.c new file mode 100644 index 0000000..d70a05f --- /dev/null +++ b/contrib/bind/lib/isc/ctl_p.c @@ -0,0 +1,156 @@ +#if !defined(lint) && !defined(SABER) +static const char rcsid[] = "$Id: ctl_p.c,v 8.6 1999/10/13 16:39:34 vixie 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[sizeof "255.255.255.255"]; + + switch (sa->sa_family) { + case AF_INET: { + const struct sockaddr_in *in = (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); + } + case AF_UNIX: { + const struct sockaddr_un *un = (struct sockaddr_un *) sa; + int x = sizeof un->sun_path; + + if (x > size) + x = size; + strncpy(buf, un->sun_path, x - 1); + buf[x - 1] = '\0'; + return (buf); + } + default: + return (punt); + } +} + +void +ctl_sa_copy(const struct sockaddr *src, struct sockaddr *dst) { + switch (src->sa_family) { + case AF_INET: + *((struct sockaddr_in *)dst) = *((struct sockaddr_in *)src); + break; + case AF_UNIX: + *((struct sockaddr_un *)dst) = *((struct sockaddr_un *)src); + break; + default: + *dst = *src; + break; + } +} diff --git a/contrib/bind/lib/isc/ctl_p.h b/contrib/bind/lib/isc/ctl_p.h new file mode 100644 index 0000000..1ebb254 --- /dev/null +++ b/contrib/bind/lib/isc/ctl_p.h @@ -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/contrib/bind/lib/isc/ctl_srvr.c b/contrib/bind/lib/isc/ctl_srvr.c new file mode 100644 index 0000000..0bdc8c8 --- /dev/null +++ b/contrib/bind/lib/isc/ctl_srvr.c @@ -0,0 +1,744 @@ +#if !defined(lint) && !defined(SABER) +static const char rcsid[] = "$Id: ctl_srvr.c,v 8.21 1999/10/17 08:41:57 cyarnell 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; + struct sockaddr_un un; +}; + +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; + 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, 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 }; + +/* 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, + (char *)&on, sizeof on) != 0) { + (*ctx->logger)(ctl_warning, + "%s: setsockopt(REUSEADDR): %s", + me, strerror(errno)); + } + if (bind(ctx->sock, sap, sap_len) < 0) { + save_errno = errno; + (*ctx->logger)(ctl_error, "%s: bind: %s", me, strerror(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, 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 < sess->outbuf.used-2; pc++, n++) + if (!isascii(*pc) || !isprint(*pc)) + *pc = '\040'; + *iovp++ = evConsIovec(sess->outbuf.text, sess->outbuf.used); + if (body != NULL) { + *iovp++ = evConsIovec((char *)body, bodylen); + *iovp++ = evConsIovec(".\r\n", 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, (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]; + + 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((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++; + 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 (((struct sockaddr *)rav)->sa_family == AF_UNIX) + ctl_sa_copy((struct sockaddr *)lav, + (struct sockaddr *)&sess->sa); + else + ctl_sa_copy((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, + (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, 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]; + + 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]; + + 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; + + 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, void *respctx, void *uctx) +{ + struct ctl_verb *this = respctx, *next = this + 1; + + 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/contrib/bind/lib/isc/ev_connects.c b/contrib/bind/lib/isc/ev_connects.c index 1cf7291..237bcb1 100644 --- a/contrib/bind/lib/isc/ev_connects.c +++ b/contrib/bind/lib/isc/ev_connects.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 1996, 1997, 1998 by Internet Software Consortium + * 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 @@ -20,7 +20,7 @@ */ #if !defined(LINT) && !defined(CODECENTER) -static const char rcsid[] = "$Id: ev_connects.c,v 8.19 1998/03/20 23:26:22 halley Exp $"; +static const char rcsid[] = "$Id: ev_connects.c,v 8.25 1999/10/07 20:44:04 vixie Exp $"; #endif /* Import. */ @@ -39,6 +39,18 @@ static const char rcsid[] = "$Id: ev_connects.c,v 8.19 1998/03/20 23:26:22 halle #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); @@ -64,8 +76,8 @@ evListen(evContext opaqueCtx, int fd, int maxconn, * are not met, then we might restore the old nonblocking status * incorrectly. */ - if ((mode & O_NONBLOCK) == 0) { - OK(fcntl(fd, F_SETFL, mode | O_NONBLOCK)); + if ((mode & PORT_NONBLOCK) == 0) { + OK(fcntl(fd, F_SETFL, mode | PORT_NONBLOCK)); new->flags |= EV_CONN_BLOCK; } OK(listen(fd, maxconn)); @@ -149,7 +161,7 @@ evCancelConn(evContext opaqueCtx, evConnID id) { if (errno != EBADF) return (-1); } else - OK(fcntl(this->fd, F_SETFL, mode | O_NONBLOCK)); + OK(fcntl(this->fd, F_SETFL, mode | PORT_NONBLOCK)); } /* Unlink from ctx->conns. */ @@ -224,9 +236,14 @@ evTryAccept(evContext opaqueCtx, evConnID id, int *sys_errno) { new->conn = conn; new->ralen = sizeof new->ra; new->fd = accept(conn->fd, &new->ra, &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 (getsockname(new->fd, &new->la, &new->lalen) < 0) { + if (GETXXXNAME(getsockname, new->fd, new->la, new->lalen) < 0) { new->ioErrno = errno; (void) close(new->fd); new->fd = -1; @@ -256,9 +273,14 @@ listener(evContext opaqueCtx, void *uap, int fd, int evmask) { REQUIRE((evmask & EV_READ) != 0); ralen = sizeof ra; new = accept(fd, &ra, &ralen); + if (new > ctx->highestFD) { + close(new); + new = -1; + errno = ENOTSOCK; + } if (new >= 0) { lalen = sizeof la; - if (getsockname(new, &la, &lalen) < 0) { + if (GETXXXNAME(getsockname, new, la, lalen) < 0) { int save = errno; (void) close(new); @@ -272,7 +294,6 @@ listener(evContext opaqueCtx, void *uap, int fd, int evmask) { static void connector(evContext opaqueCtx, void *uap, int fd, int evmask) { - evContext_p *ctx = opaqueCtx.opaque; evConn *conn = uap; struct sockaddr la, ra; int lalen, ralen; @@ -304,8 +325,8 @@ connector(evContext opaqueCtx, void *uap, int fd, int evmask) { #else read(fd, buf, 0) < 0 || #endif - getsockname(fd, &la, &lalen) < 0 || - getpeername(fd, &ra, &ralen) < 0) { + GETXXXNAME(getsockname, fd, la, lalen) < 0 || + GETXXXNAME(getpeername, fd, ra, ralen) < 0) { int save = errno; (void) close(fd); /* XXX closing caller's fd */ diff --git a/contrib/bind/lib/isc/ev_files.c b/contrib/bind/lib/isc/ev_files.c index 6cd1d41..434385c 100644 --- a/contrib/bind/lib/isc/ev_files.c +++ b/contrib/bind/lib/isc/ev_files.c @@ -1,4 +1,5 @@ -/* Copyright (c) 1995, 1996, 1997, 1998 by Internet Software Consortium +/* + * 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 @@ -19,7 +20,7 @@ */ #if !defined(LINT) && !defined(CODECENTER) -static const char rcsid[] = "$Id: ev_files.c,v 1.15 1998/02/06 01:53:52 halley Exp $"; +static const char rcsid[] = "$Id: ev_files.c,v 1.19 1999/10/07 20:44:04 vixie Exp $"; #endif #include "port_before.h" @@ -56,7 +57,7 @@ evSelectFD(evContext opaqueCtx, ctx, fd, eventmask, func, uap); if (eventmask == 0 || (eventmask & ~EV_MASK_ALL) != 0) ERR(EINVAL); - if (fd >= FD_SETSIZE) + if (fd > ctx->highestFD) ERR(EINVAL); OK(mode = fcntl(fd, F_GETFL, NULL)); /* side effect: validate fd. */ @@ -68,10 +69,10 @@ evSelectFD(evContext opaqueCtx, */ id = FindFD(ctx, fd, EV_MASK_ALL); if (id == NULL) { - if (mode & O_NONBLOCK) + if (mode & PORT_NONBLOCK) FD_SET(fd, &ctx->nonblockBefore); else { - OK(fcntl(fd, F_SETFL, mode | O_NONBLOCK)); + OK(fcntl(fd, F_SETFL, mode | PORT_NONBLOCK)); FD_CLR(fd, &ctx->nonblockBefore); } } @@ -150,7 +151,7 @@ int evDeselectFD(evContext opaqueCtx, evFileID opaqueID) { evContext_p *ctx = opaqueCtx.opaque; evFile *del = opaqueID.opaque; - evFile *old, *cur; + evFile *cur; int mode, eventmask; if (!del) { @@ -196,7 +197,7 @@ evDeselectFD(evContext opaqueCtx, evFileID opaqueID) { * 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 & ~O_NONBLOCK); + (void) fcntl(del->fd, F_SETFL, mode & ~PORT_NONBLOCK); } /* diff --git a/contrib/bind/lib/isc/ev_streams.c b/contrib/bind/lib/isc/ev_streams.c index aa4270b..b25a666 100644 --- a/contrib/bind/lib/isc/ev_streams.c +++ b/contrib/bind/lib/isc/ev_streams.c @@ -1,4 +1,5 @@ -/* Copyright (c) 1996, 1997, 1998 by Internet Software Consortium +/* + * 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 @@ -19,7 +20,7 @@ */ #if !defined(LINT) && !defined(CODECENTER) -static const char rcsid[] = "$Id: ev_streams.c,v 8.18 1998/03/20 23:26:22 halley Exp $"; +static const char rcsid[] = "$Id: ev_streams.c,v 8.21 1999/10/07 20:44:04 vixie Exp $"; #endif #include "port_before.h" @@ -83,7 +84,6 @@ evWrite(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt, save = errno; FREE(new); errno = save; - err: return (-1); } @@ -118,13 +118,11 @@ evRead(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt, save = errno; FREE(new); errno = save; - err: return (-1); } int evTimeRW(evContext opaqueCtx, evStreamID id, evTimerID timer) /*ARGSUSED*/ { - evContext_p *ctx = opaqueCtx.opaque; evStream *str = id.opaque; str->timer = timer; @@ -134,7 +132,6 @@ evTimeRW(evContext opaqueCtx, evStreamID id, evTimerID timer) /*ARGSUSED*/ { int evUntimeRW(evContext opaqueCtx, evStreamID id) /*ARGSUSED*/ { - evContext_p *ctx = opaqueCtx.opaque; evStream *str = id.opaque; str->flags &= ~EV_STR_TIMEROK; diff --git a/contrib/bind/lib/isc/ev_timers.c b/contrib/bind/lib/isc/ev_timers.c index 198f27c..0db770c 100644 --- a/contrib/bind/lib/isc/ev_timers.c +++ b/contrib/bind/lib/isc/ev_timers.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 1996, 1997, 1998 by Internet Software Consortium + * 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 @@ -20,7 +20,7 @@ */ #if !defined(LINT) && !defined(CODECENTER) -static const char rcsid[] = "$Id: ev_timers.c,v 1.23 1998/03/20 23:26:23 halley Exp $"; +static const char rcsid[] = "$Id: ev_timers.c,v 1.25 1999/10/07 20:44:04 vixie Exp $"; #endif /* Import. */ @@ -107,7 +107,6 @@ evCmpTime(struct timespec a, struct timespec b) { struct timespec evNowTime() { struct timeval now; - struct timespec ret; if (gettimeofday(&now, NULL) < 0) return (evConsTime(0, 0)); @@ -288,7 +287,6 @@ evSetIdleTimer(evContext opaqueCtx, int evClearIdleTimer(evContext opaqueCtx, evTimerID id) { - evContext_p *ctx = opaqueCtx.opaque; evTimer *del = id.opaque; idle_timer *tt = del->uap; diff --git a/contrib/bind/lib/isc/ev_waits.c b/contrib/bind/lib/isc/ev_waits.c index a45adf1..c336dcb 100644 --- a/contrib/bind/lib/isc/ev_waits.c +++ b/contrib/bind/lib/isc/ev_waits.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1997, 1998 by Internet Software Consortium + * 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 @@ -20,7 +20,7 @@ */ #if !defined(LINT) && !defined(CODECENTER) -static const char rcsid[] = "$Id: ev_waits.c,v 8.6 1998/03/20 23:26:23 halley Exp $"; +static const char rcsid[] = "$Id: ev_waits.c,v 8.9 1999/10/13 17:11:20 vixie Exp $"; #endif #include "port_before.h" @@ -117,7 +117,7 @@ evUnwait(evContext opaqueCtx, evWaitID id) { for (prev = NULL, this = wl->first; this != NULL; prev = this, this = this->next) - if (this == id.opaque) { + if (this == (evWait *)id.opaque) { found = 1; if (prev != NULL) prev->next = this->next; @@ -136,7 +136,7 @@ evUnwait(evContext opaqueCtx, evWaitID id) { for (prev = NULL, this = ctx->waitDone.first; this != NULL; prev = this, this = this->next) - if (this == id.opaque) { + if (this == (evWait *)id.opaque) { found = 1; if (prev != NULL) prev->next = this->next; @@ -218,7 +218,6 @@ evNewWaitList(evContext_p *ctx) { static void evFreeWaitList(evContext_p *ctx, evWaitList *this) { - evWaitList *prev; INSIST(this != NULL); diff --git a/contrib/bind/lib/isc/eventlib.c b/contrib/bind/lib/isc/eventlib.c index afb9d9d..6cb227b 100644 --- a/contrib/bind/lib/isc/eventlib.c +++ b/contrib/bind/lib/isc/eventlib.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 1996, 1997, 1998 by Internet Software Consortium + * 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 @@ -20,7 +20,7 @@ */ #if !defined(LINT) && !defined(CODECENTER) -static const char rcsid[] = "$Id: eventlib.c,v 1.38 1998/03/20 23:26:24 halley Exp $"; +static const char rcsid[] = "$Id: eventlib.c,v 1.44 1999/10/13 17:11:20 vixie Exp $"; #endif #include "port_before.h" @@ -31,6 +31,7 @@ static const char rcsid[] = "$Id: eventlib.c,v 1.38 1998/03/20 23:26:24 halley E #include <sys/stat.h> #include <errno.h> +#include <signal.h> #include <stdarg.h> #include <stdlib.h> #include <unistd.h> @@ -44,7 +45,9 @@ static const char rcsid[] = "$Id: eventlib.c,v 1.38 1998/03/20 23:26:24 halley E /* Forward. */ #ifdef NEED_PSELECT -static int pselect(int, void *, void *, void *, struct timespec*); +static int pselect(int, void *, void *, void *, + struct timespec *, + const sigset_t *); #endif /* Public. */ @@ -52,7 +55,6 @@ static int pselect(int, void *, void *, void *, struct timespec*); int evCreate(evContext *opaqueCtx) { evContext_p *ctx; - int i; /* Make sure the memory heap is initialized. */ if (meminit(0, 0) < 0 && errno != EEXIST) @@ -76,14 +78,15 @@ evCreate(evContext *opaqueCtx) { 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 - for (i = 0; i < FD_SETSIZE; i++) - ctx->fdTable[i] = NULL; + memset(ctx->fdTable, 0, sizeof ctx->fdTable); /* Streams. */ ctx->streams = NULL; @@ -299,7 +302,7 @@ evGetNext(evContext opaqueCtx, evEvent *opaqueEv, int options) { /* XXX should predict system's earliness and adjust. */ x = pselect(ctx->fdMax+1, &ctx->rdLast, &ctx->wrLast, &ctx->exLast, - tp); + tp, NULL); pselect_errno = errno; evPrintf(ctx, 4, "select() returns %d (err: %s)\n", @@ -625,6 +628,13 @@ evMainLoop(evContext opaqueCtx) { 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; @@ -638,9 +648,14 @@ evPrintf(const evContext_p *ctx, int level, const char *fmt, ...) { } #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) { +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) { @@ -648,7 +663,11 @@ pselect(int nfds, void *rfds, void *wfds, void *efds, struct timespec *tsp) { 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); diff --git a/contrib/bind/lib/isc/eventlib.mdoc b/contrib/bind/lib/isc/eventlib.mdoc index f0e31e1..202b1cb 100644 --- a/contrib/bind/lib/isc/eventlib.mdoc +++ b/contrib/bind/lib/isc/eventlib.mdoc @@ -1,6 +1,6 @@ -.\" $Id: eventlib.mdoc,v 1.18 1998/01/26 23:00:56 halley Exp $ +.\" $Id: eventlib.mdoc,v 1.20 1999/08/18 22:09:04 vixie Exp $ .\" -.\"Copyright (c) 1995, 1996, 1997 by Internet Software Consortium +.\"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 @@ -63,7 +63,9 @@ .Nm evTryAccept , .Nm evConsIovec , .Nm evSetDebug , -.Nm evPrintf +.Nm evPrintf , +.Nm evInitID , +.Nm evTestID .Nd event handling library .Sh SYNOPSIS .Fd #include <isc/eventlib.h> @@ -171,6 +173,10 @@ .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 @@ -769,6 +775,25 @@ with the event context pointed to by 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 diff --git a/contrib/bind/lib/isc/eventlib_p.h b/contrib/bind/lib/isc/eventlib_p.h index 2606333..80dc160 100644 --- a/contrib/bind/lib/isc/eventlib_p.h +++ b/contrib/bind/lib/isc/eventlib_p.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 1996, 1997, 1998 by Internet Software Consortium + * 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 @@ -18,7 +18,7 @@ /* eventlib_p.h - private interfaces for eventlib * vix 09sep95 [initial] * - * $Id: eventlib_p.h,v 1.25 1998/02/06 01:53:54 halley Exp $ + * $Id: eventlib_p.h,v 1.27 1999/06/03 20:36:05 vixie Exp $ */ #ifndef _EVENTLIB_P_H @@ -165,7 +165,7 @@ typedef struct { fd_set wrLast, wrNext; fd_set exLast, exNext; fd_set nonblockBefore; - int fdMax, fdCount; + int fdMax, fdCount, highestFD; evFile *fdTable[FD_SETSIZE]; #ifdef EVENTLIB_TIME_CHECKS struct timespec lastSelectTime; diff --git a/contrib/bind/lib/isc/heap.c b/contrib/bind/lib/isc/heap.c index 821d323..ba9c503 100644 --- a/contrib/bind/lib/isc/heap.c +++ b/contrib/bind/lib/isc/heap.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 by Internet Software Consortium. + * 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 @@ -26,7 +26,7 @@ */ #if !defined(LINT) && !defined(CODECENTER) -static char rcsid[] = "$Id: heap.c,v 8.5 1998/03/27 00:17:47 halley Exp $"; +static const char rcsid[] = "$Id: heap.c,v 8.7 1999/10/13 16:39:34 vixie Exp $"; #endif /* not lint */ #include "port_before.h" diff --git a/contrib/bind/lib/isc/heap.mdoc b/contrib/bind/lib/isc/heap.mdoc index 2c22bc2..516490b 100644 --- a/contrib/bind/lib/isc/heap.mdoc +++ b/contrib/bind/lib/isc/heap.mdoc @@ -1,6 +1,6 @@ -.\" $Id: heap.mdoc,v 8.4 1997/04/26 04:00:55 vixie Exp $ +.\" $Id: heap.mdoc,v 8.5 1999/01/08 19:25:38 vixie Exp $ .\" -.\"Copyright (c) 1997 by Internet Software Consortium. +.\"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 diff --git a/contrib/bind/lib/isc/logging.c b/contrib/bind/lib/isc/logging.c index e5264ff..a3988e4 100644 --- a/contrib/bind/lib/isc/logging.c +++ b/contrib/bind/lib/isc/logging.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1997, 1998 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #if !defined(LINT) && !defined(CODECENTER) -static char rcsid[] = "$Id: logging.c,v 8.18 1998/03/27 00:17:47 halley Exp $"; +static const char rcsid[] = "$Id: logging.c,v 8.24 1999/10/13 16:39:34 vixie Exp $"; #endif /* not lint */ #include "port_before.h" @@ -115,9 +115,7 @@ log_open_stream(log_channel chan) { regular = (sb.st_mode & S_IFREG); if (chan->out.file.versions) { - if (regular) - version_rename(chan); - else { + if (!regular) { syslog(LOG_ERR, "log_open_stream: want versions but %s isn't a regular file", chan->out.file.name); @@ -265,7 +263,6 @@ log_vwrite(log_context lc, int category, int level, const char *format, int pri, debugging, did_vsprintf = 0; int original_category; FILE *stream; - int chan_level; log_channel chan; struct timeval tv; struct tm *local_tm; @@ -300,7 +297,11 @@ log_vwrite(log_context lc, int category, int level, const char *format, 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], @@ -378,8 +379,19 @@ log_vwrite(log_context lc, int category, int level, const char *format, pos = ftell(stream); if (pos >= 0 && (unsigned long)pos > - chan->out.file.max_size) - break; + 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 : "", diff --git a/contrib/bind/lib/isc/logging.mdoc b/contrib/bind/lib/isc/logging.mdoc index 6fdb618..6b48943 100644 --- a/contrib/bind/lib/isc/logging.mdoc +++ b/contrib/bind/lib/isc/logging.mdoc @@ -1,6 +1,6 @@ -.\" $Id: logging.mdoc,v 8.2 1998/02/06 01:54:34 halley Exp $ +.\" $Id: logging.mdoc,v 8.3 1999/01/08 19:25:41 vixie Exp $ .\" -.\"Copyright (c) 1995, 1996, 1997, 1998 by Internet Software Consortium +.\"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 diff --git a/contrib/bind/lib/isc/logging_p.h b/contrib/bind/lib/isc/logging_p.h index 317582d..e94102e 100644 --- a/contrib/bind/lib/isc/logging_p.h +++ b/contrib/bind/lib/isc/logging_p.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1997 by Internet Software Consortium. + * 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 diff --git a/contrib/bind/lib/isc/memcluster.c b/contrib/bind/lib/isc/memcluster.c index 761fe98..b775fa7 100644 --- a/contrib/bind/lib/isc/memcluster.c +++ b/contrib/bind/lib/isc/memcluster.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 by Internet Software Consortium. + * 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 @@ -15,8 +15,15 @@ * 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 */ + + #if !defined(LINT) && !defined(CODECENTER) -static char rcsid[] = "$Id: memcluster.c,v 8.10 1998/05/05 19:00:52 halley Exp $"; +static const char rcsid[] = "$Id: memcluster.c,v 8.19 1999/10/13 17:11:22 vixie Exp $"; #endif /* not lint */ #include "port_before.h" @@ -41,15 +48,34 @@ static char rcsid[] = "$Id: memcluster.c,v 8.10 1998/05/05 19:00:52 halley Exp $ #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 @@ -70,6 +96,9 @@ 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 @@ -78,13 +107,18 @@ 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) { - int i; +#if defined(DEBUGGING_MEMCLUSTER) + INSIST(sizeof(fence_t) == FENCEPOST_SIZE); +#endif if (freelists != NULL) { errno = EEXIST; return (-1); @@ -108,6 +142,15 @@ meminit(size_t init_max_size, size_t target_size) { 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 @@ -116,7 +159,17 @@ meminit(size_t init_max_size, size_t target_size) { 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 (freelists == NULL) @@ -130,7 +183,27 @@ __memget(size_t 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 } /* @@ -186,18 +259,50 @@ __memget(size_t 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": */ + /* 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 @@ -208,7 +313,11 @@ __memget(size_t size) { stats[size].gets++; stats[size].totalgets++; stats[new_size].freefrags--; +#if defined(DEBUGGING_MEMCLUSTER) + return ((char *)e + sizeof *e); +#else return (ret); +#endif } /* @@ -217,25 +326,83 @@ __memget(size_t size) { */ void __memput(void *mem, size_t size) { - size_t new_size = quantize(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 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 + e->next = freelists[new_size]; + freelists[new_size] = (void *)e; +#else ((memcluster_element *)mem)->next = freelists[new_size]; freelists[new_size] = (memcluster_element *)mem; +#endif /* * The stats[] uses the _actual_ "size" requested by the @@ -251,7 +418,7 @@ __memput(void *mem, size_t size) { void * __memget_debug(size_t size, const char *file, int line) { void *ptr; - ptr = __memget(size); + ptr = __memget_record(size, file, line); fprintf(stderr, "%s:%d: memget(%lu) -> %p\n", file, line, (u_long)size, ptr); return (ptr); @@ -261,7 +428,7 @@ 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(ptr, size); + __memput_record(ptr, size, file, line); } /* @@ -270,6 +437,9 @@ __memput_debug(void *ptr, size_t size, const char *file, int line) { void memstats(FILE *out) { size_t i; +#ifdef MEMCLUSTER_RECORD + memcluster_element *e; +#endif if (freelists == NULL) return; @@ -286,6 +456,19 @@ memstats(FILE *out) { 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. */ @@ -295,7 +478,7 @@ memstats(FILE *out) { * 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 +static size_t quantize(size_t size) { int remainder; /* @@ -309,7 +492,19 @@ quantize(size_t size) { */ remainder = size % P_SIZE; if (remainder != 0) - size += P_SIZE - remainder; + 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/contrib/bind/lib/isc/memcluster.mdoc b/contrib/bind/lib/isc/memcluster.mdoc index c076972..82bfd71 100644 --- a/contrib/bind/lib/isc/memcluster.mdoc +++ b/contrib/bind/lib/isc/memcluster.mdoc @@ -1,6 +1,6 @@ -.\" $Id: memcluster.mdoc,v 8.1 1997/09/26 17:56:10 halley Exp $ +.\" $Id: memcluster.mdoc,v 8.2 1999/01/08 19:25:46 vixie Exp $ .\" -.\"Copyright (c) 1995, 1996 by Internet Software Consortium +.\"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 diff --git a/contrib/bind/lib/isc/tree.c b/contrib/bind/lib/isc/tree.c index ce500ec..90ba146 100644 --- a/contrib/bind/lib/isc/tree.c +++ b/contrib/bind/lib/isc/tree.c @@ -1,5 +1,5 @@ #ifndef LINT -static char RCSid[] = "$Id: tree.c,v 8.6 1997/09/26 17:56:11 halley Exp $"; +static const char rcsid[] = "$Id: tree.c,v 8.9 1999/01/08 19:25:47 vixie Exp $"; #endif /* @@ -22,7 +22,7 @@ static char RCSid[] = "$Id: tree.c,v 8.6 1997/09/26 17:56:11 halley Exp $"; */ /* - * Portions Copyright (c) 1996,1997 by Internet Software Consortium. + * 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 @@ -56,7 +56,7 @@ static char *debugFuncs[256]; # define ENTER(proc) { \ debugFuncs[debugDepth] = proc; \ fprintf(stderr, "ENTER(%d:%s.%s)\n", \ - debugDepth, DEBUG, + debugDepth, DEBUG, \ debugFuncs[debugDepth]); \ debugDepth++; \ } diff --git a/contrib/bind/lib/isc/tree.mdoc b/contrib/bind/lib/isc/tree.mdoc index 2406219..422344e 100644 --- a/contrib/bind/lib/isc/tree.mdoc +++ b/contrib/bind/lib/isc/tree.mdoc @@ -1,6 +1,6 @@ -.\" $Id: tree.mdoc,v 8.1 1997/01/30 20:27:25 vixie Exp $ +.\" $Id: tree.mdoc,v 8.2 1999/01/08 19:25:48 vixie Exp $ .\" -.\"Copyright (c) 1995, 1996 by Internet Software Consortium +.\"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 diff --git a/contrib/bind/lib/nameser/Makefile b/contrib/bind/lib/nameser/Makefile index d86dc74..52a102f 100644 --- a/contrib/bind/lib/nameser/Makefile +++ b/contrib/bind/lib/nameser/Makefile @@ -1,5 +1,5 @@ # -# Copyright (c) 1996 by Internet Software Consortium +# 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 @@ -15,7 +15,7 @@ # SOFTWARE. # -# $Id: Makefile,v 8.7 1997/05/21 19:32:08 halley Exp $ +# $Id: Makefile,v 8.16 1999/09/07 08:47:28 vixie Exp $ # these are only appropriate for BSD 4.4 or derivatives, and are used in # development. normal builds will be done in the top level directory and @@ -33,31 +33,48 @@ TOP= ../.. INCL = ${TOP}/include PORTINCL = ${TOP}/port/${SYSTYPE}/include LIBBIND = ${TOP}/lib/libbind.${A} +LIBBINDR = ../${TOP}/lib/libbind_r.${A} CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL} LD_LIBFLAGS= -x -r -AR= ar cruv +AR= ar cru RANLIB= ranlib INSTALL= install +INSTALL_EXEC= +INSTALL_LIB=-o bin -g bin +THREADED= threaded -SRCS= ns_parse.c ns_print.c ns_netint.c ns_ttl.c ns_name.c +SRCS= ns_parse.c ns_print.c ns_netint.c ns_ttl.c ns_name.c \ + ns_sign.c ns_verify.c ns_date.c ns_samedomain.c -OBJS= ns_parse.${O} ns_print.${O} ns_netint.${O} ns_ttl.${O} ns_name.${O} +OBJS= ns_parse.${O} ns_print.${O} ns_netint.${O} ns_ttl.${O} ns_name.${O} \ + ns_sign.${O} ns_verify.${O} ns_date.${O} ns_samedomain.${O} -all: ${LIBBIND} +all: ${LIBBIND} ${LIBBIND}: ${OBJS} + ( cd ${THREADED} ; \ + ${AR} ${LIBBINDR} ${ARPREF} ${OBJS} ${ARSUFF} ; \ + ${RANLIB} ${LIBBINDR} ) ${AR} ${LIBBIND} ${ARPREF} ${OBJS} ${ARSUFF} ${RANLIB} ${LIBBIND} .c.${O}: - ${CC} ${CPPFLAGS} ${CFLAGS} -c $*.c - -${LDS} ${LD} ${LD_LIBFLAGS} $*.${O} && ${LDS} mv a.out $*.${O} + if test ! -d ${THREADED} ; then mkdir ${THREADED} ; fi + ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} ${REENTRANT} -c $*.c \ + -o ${THREADED}/$*.${O} + -${LDS} ${LD} ${LD_LIBFLAGS} ${THREADED}/$*.${O} -o a.out && \ + ${LDS} mv a.out ${THREADED}/$*.${O} + ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c + -${LDS} ${LD} ${LD_LIBFLAGS} $*.${O} -o a.out && \ + ${LDS} mv a.out $*.${O} distclean: clean clean: FRC rm -f .depend a.out core ${LIB} tags rm -f *.${O} *.BAK *.CKP *~ + rm -f ${THREADED}/*.${O} + -rmdir ${THREADED} depend: FRC mkdep -I${INCL} -I${PORTINCL} ${CPPFLAGS} ${SRCS} diff --git a/contrib/bind/lib/nameser/ns_date.c b/contrib/bind/lib/nameser/ns_date.c new file mode 100644 index 0000000..da593a5 --- /dev/null +++ b/contrib/bind/lib/nameser/ns_date.c @@ -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.2 1999/10/13 16:39:35 vixie 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/contrib/bind/lib/nameser/ns_name.c b/contrib/bind/lib/nameser/ns_name.c index 86c0bbb..6bd668d 100644 --- a/contrib/bind/lib/nameser/ns_name.c +++ b/contrib/bind/lib/nameser/ns_name.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #ifndef lint -static char rcsid[] = "$Id: ns_name.c,v 8.3 1997/04/24 22:10:54 vixie Exp $"; +static const char rcsid[] = "$Id: ns_name.c,v 8.12 1999/10/13 17:11:23 vixie Exp $"; #endif #include "port_before.h" @@ -29,12 +29,13 @@ static char rcsid[] = "$Id: ns_name.c,v 8.3 1997/04/24 22:10:54 vixie Exp $"; #include <errno.h> #include <resolv.h> #include <string.h> +#include <ctype.h> #include "port_after.h" /* Data. */ -static char digits[] = "0123456789"; +static const char digits[] = "0123456789"; /* Forward. */ @@ -199,7 +200,7 @@ ns_name_pton(const char *src, u_char *dst, size_t dstsiz) { } return (1); } - if (c == 0) { + if (c == 0 || *src == '.') { errno = EMSGSIZE; return (-1); } @@ -237,6 +238,49 @@ ns_name_pton(const char *src, u_char *dst, size_t dstsiz) { } /* + * ns_name_ntol(src, dst, dstsiz) + * Convert a network strings labels into all lowercase. + * return: + * Number of bytes written to buffer, or -1 (with errno set) + * notes: + * Enforces label and domain length limits. + */ + +int +ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz) { + const u_char *cp; + u_char *dn, *eom; + u_char c; + u_int n; + + cp = src; + dn = dst; + eom = dst + dstsiz; + + while ((n = *cp++) != 0) { + if ((n & NS_CMPRSFLGS) != 0) { + /* Some kind of compression pointer. */ + errno = EMSGSIZE; + return (-1); + } + *dn++ = n; + if (dn + n >= eom) { + errno = EMSGSIZE; + return (-1); + } + for ((void)NULL; n > 0; n--) { + c = *cp++; + if (isupper(c)) + *dn++ = tolower(c); + else + *dn++ = c; + } + } + *dn++ = '\0'; + return (dn - dst); +} + +/* * ns_name_unpack(msg, eom, src, dst, dstsiz) * Unpack a domain name from a message, source may be compressed. * return: @@ -248,7 +292,7 @@ ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src, { const u_char *srcp, *dstlim; u_char *dstp; - int n, c, len, checked; + int n, len, checked; len = -1; checked = 0; @@ -366,6 +410,7 @@ ns_name_pack(const u_char *src, u_char *dst, int dstsiz, srcp += n + 1; } while (n != 0); + /* from here on we need to reset compression pointer array on error */ srcp = src; do { /* Look to see if we can use pointers. */ @@ -375,8 +420,7 @@ ns_name_pack(const u_char *src, u_char *dst, int dstsiz, (const u_char * const *)lpp); if (l >= 0) { if (dstp + 1 >= eob) { - errno = EMSGSIZE; - return (-1); + goto cleanup; } *dstp++ = (l >> 8) | NS_CMPRSFLGS; *dstp++ = l % 256; @@ -391,12 +435,10 @@ ns_name_pack(const u_char *src, u_char *dst, int dstsiz, } /* copy label to buffer */ if (n & NS_CMPRSFLGS) { /* Should not happen. */ - errno = EMSGSIZE; - return (-1); + goto cleanup; } if (dstp + 1 + n >= eob) { - errno = EMSGSIZE; - return (-1); + goto cleanup; } memcpy(dstp, srcp, n + 1); srcp += n + 1; @@ -404,6 +446,7 @@ ns_name_pack(const u_char *src, u_char *dst, int dstsiz, } while (n != 0); if (dstp > eob) { +cleanup: if (msg != NULL) *lpp = NULL; errno = EMSGSIZE; diff --git a/contrib/bind/lib/nameser/ns_netint.c b/contrib/bind/lib/nameser/ns_netint.c index 1f640a5..030a2d0 100644 --- a/contrib/bind/lib/nameser/ns_netint.c +++ b/contrib/bind/lib/nameser/ns_netint.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,21 +16,19 @@ */ #ifndef lint -static char rcsid[] = "$Id: ns_netint.c,v 8.1 1996/11/18 09:09:57 vixie Exp $"; +static const char rcsid[] = "$Id: ns_netint.c,v 8.4 1999/10/13 16:39:35 vixie Exp $"; #endif /* Import. */ #include "port_before.h" -/*#include <sys/types.h>*/ -/*#include <sys/socket.h>*/ - -/*#include <netinet/in.h>*/ #include <arpa/nameser.h> #include "port_after.h" +/* Public. */ + u_int ns_get16(const u_char *src) { u_int dst; diff --git a/contrib/bind/lib/nameser/ns_parse.c b/contrib/bind/lib/nameser/ns_parse.c index 800ea19..35f7f40 100644 --- a/contrib/bind/lib/nameser/ns_parse.c +++ b/contrib/bind/lib/nameser/ns_parse.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,9 +16,11 @@ */ #ifndef lint -static char rcsid[] = "$Id: ns_parse.c,v 8.8 1998/02/17 17:20:33 vixie Exp $"; +static const char rcsid[] = "$Id: ns_parse.c,v 8.13 1999/10/13 16:39:35 vixie Exp $"; #endif +/* Import. */ + #include "port_before.h" #include <sys/types.h> @@ -32,6 +34,16 @@ static char rcsid[] = "$Id: ns_parse.c,v 8.8 1998/02/17 17:20:33 vixie Exp $"; #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. */ @@ -52,8 +64,8 @@ struct _ns_flagdata _ns_flagdata[16] = { { 0x0000, 0 }, /* expansion (6/6). */ }; -static int -skiprr(const u_char *ptr, const u_char *eom, ns_sect section, int count) { +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--) { @@ -61,24 +73,19 @@ skiprr(const u_char *ptr, const u_char *eom, ns_sect section, int count) { b = dn_skipname(ptr, eom); if (b < 0) - goto emsgsize; + RETERR(EMSGSIZE); ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/; if (section != ns_s_qd) { - if (ptr + NS_INT32SZ > eom) - goto emsgsize; + if (ptr + NS_INT32SZ + NS_INT16SZ > eom) + RETERR(EMSGSIZE); ptr += NS_INT32SZ/*TTL*/; - if (ptr + NS_INT16SZ > eom) - goto emsgsize; NS_GET16(rdlength, ptr); ptr += rdlength/*RData*/; } } if (ptr > eom) - goto emsgsize; + RETERR(EMSGSIZE); return (ptr - optr); - emsgsize: - errno = EMSGSIZE; - return (-1); } int @@ -90,22 +97,22 @@ ns_initparse(const u_char *msg, int msglen, ns_msg *handle) { handle->_msg = msg; handle->_eom = eom; if (msg + NS_INT16SZ > eom) - goto emsgsize; + RETERR(EMSGSIZE); NS_GET16(handle->_id, msg); if (msg + NS_INT16SZ > eom) - goto emsgsize; + RETERR(EMSGSIZE); NS_GET16(handle->_flags, msg); for (i = 0; i < ns_s_max; i++) { if (msg + NS_INT16SZ > eom) - goto emsgsize; + 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 = skiprr(msg, eom, (ns_sect)i, - handle->_counts[i]); + int b = ns_skiprr(msg, eom, (ns_sect)i, + handle->_counts[i]); if (b < 0) return (-1); @@ -113,14 +120,9 @@ ns_initparse(const u_char *msg, int msglen, ns_msg *handle) { msg += b; } if (msg != eom) - goto emsgsize; - handle->_sect = ns_s_max; - handle->_rrnum = -1; - handle->_ptr = NULL; + RETERR(EMSGSIZE); + setsection(handle, ns_s_max); return (0); - emsgsize: - errno = EMSGSIZE; - return (-1); } int @@ -129,29 +131,26 @@ ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) { /* Make section right. */ if (section < 0 || section >= ns_s_max) - goto enodev; - if ((int)section != (int)handle->_sect) { - handle->_sect = section; - handle->_rrnum = 0; - handle->_ptr = handle->_sections[(int)section]; - } + 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]) - goto enodev; - if (rrnum < handle->_rrnum) { - handle->_rrnum = 0; - handle->_ptr = handle->_sections[(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; } - - b = skiprr(handle->_msg, 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, @@ -159,36 +158,41 @@ ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) { if (b < 0) return (-1); handle->_ptr += b; - if (handle->_ptr + NS_INT16SZ > handle->_eom) - goto emsgsize; + if (handle->_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom) + RETERR(EMSGSIZE); NS_GET16(rr->type, handle->_ptr); - if (handle->_ptr + NS_INT16SZ > handle->_eom) - goto emsgsize; - NS_GET16(rr->class, 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 > handle->_eom) - goto emsgsize; + if (handle->_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom) + RETERR(EMSGSIZE); NS_GET32(rr->ttl, handle->_ptr); - if (handle->_ptr + NS_INT16SZ > handle->_eom) - goto emsgsize; NS_GET16(rr->rdlength, handle->_ptr); if (handle->_ptr + rr->rdlength > handle->_eom) - goto emsgsize; + RETERR(EMSGSIZE); rr->rdata = handle->_ptr; handle->_ptr += rr->rdlength; } - handle->_rrnum++; + if (++handle->_rrnum > handle->_counts[(int)section]) + setsection(handle, (ns_sect)((int)section + 1)); /* All done. */ return (0); - enodev: - errno = ENODEV; - return (-1); - emsgsize: - errno = EMSGSIZE; - return (-1); +} + +/* Private. */ + +static void +setsection(ns_msg *msg, ns_sect sect) { + msg->_sect = sect; + if (sect == ns_s_max) { + msg->_rrnum = -1; + msg->_ptr = NULL; + } else { + msg->_rrnum = 0; + msg->_ptr = msg->_sections[(int)sect]; + } } diff --git a/contrib/bind/lib/nameser/ns_print.c b/contrib/bind/lib/nameser/ns_print.c index 8ab4766..93f1e91 100644 --- a/contrib/bind/lib/nameser/ns_print.c +++ b/contrib/bind/lib/nameser/ns_print.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1998 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #ifndef lint -static char rcsid[] = "$Id: ns_print.c,v 8.4 1998/02/13 01:16:37 halley Exp $"; +static const char rcsid[] = "$Id: ns_print.c,v 8.17 1999/10/19 02:06:54 gson Exp $"; #endif /* Import. */ @@ -30,7 +30,7 @@ static char rcsid[] = "$Id: ns_print.c,v 8.4 1998/02/13 01:16:37 halley Exp $"; #include <arpa/nameser.h> #include <arpa/inet.h> -#include <assert.h> +#include <isc/assertions.h> #include <errno.h> #include <resolv.h> #include <string.h> @@ -58,6 +58,10 @@ static int addstr(const char *src, size_t len, 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) \ @@ -115,7 +119,7 @@ ns_sprintrrf(const u_char *msg, size_t msglen, /* * Owner. */ - if (name_ctx != NULL && strcasecmp(name_ctx, name) == 0) { + if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) { T(addstr("\t\t\t", 3, &buf, &buflen)); } else { len = prune_origin(name, origin); @@ -171,7 +175,11 @@ ns_sprintrrf(const u_char *msg, size_t msglen, rdata += len; T(addstr(" ", 1, &buf, &buflen)); - /* Second word. */ + + /* 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; @@ -439,7 +447,7 @@ ns_sprintrrf(const u_char *msg, size_t msglen, case ns_t_key: { char base64_key[NS_MD5RSA_MAX_BASE64]; - u_int keyflags, protocol, algorithm; + u_int keyflags, protocol, algorithm, key_id; const char *leader; int n; @@ -447,6 +455,7 @@ ns_sprintrrf(const u_char *msg, size_t msglen, 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++; @@ -472,6 +481,8 @@ ns_sprintrrf(const u_char *msg, size_t msglen, } if (len > 15) T(addstr(" )", 2, &buf, &buflen)); + n = SPRINTF((tmp, " ; key_tag= %u", key_id)); + T(addstr(tmp, n, &buf, &buflen)); break; } @@ -491,10 +502,10 @@ ns_sprintrrf(const u_char *msg, size_t msglen, algorithm = *rdata++; labels = *rdata++; t = ns_get32(rdata); rdata += NS_INT32SZ; - len = SPRINTF((tmp, " %s %d %lu ", - p_type(type), algorithm, t)); + 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)) + if (labels > (u_int)dn_count_labels(name)) goto formerr; /* Signature expiry. */ @@ -533,7 +544,6 @@ ns_sprintrrf(const u_char *msg, size_t msglen, } if (len > 15) T(addstr(" )", 2, &buf, &buflen)); - break; } @@ -553,6 +563,63 @@ ns_sprintrrf(const u_char *msg, size_t msglen, break; } + case ns_t_cert: { + u_int c_type, key_tag, alg; + int n, siz; + char base64_cert[8192], *leader, tmp[40]; + + 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) { + 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_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; + } + default: comment = "unknown RR type"; goto hexify; @@ -608,7 +675,7 @@ prune_origin(const char *name, const char *origin) { const char *oname = name; while (*name != '\0') { - if (origin != NULL && strcasecmp(name, origin) == 0) + if (origin != NULL && ns_samename(name, origin) == 1) return (name - oname - (name > oname)); while (*name != '\0') { if (*name == '\\') { @@ -712,14 +779,14 @@ addname(const u_char *msg, size_t msglen, static void addlen(size_t len, char **buf, size_t *buflen) { - assert(len <= *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) { + if (len >= *buflen) { errno = ENOSPC; return (-1); } diff --git a/contrib/bind/lib/nameser/ns_samedomain.c b/contrib/bind/lib/nameser/ns_samedomain.c new file mode 100644 index 0000000..c847924 --- /dev/null +++ b/contrib/bind/lib/nameser/ns_samedomain.c @@ -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 8.9 1999/10/15 21:06:51 vixie 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/contrib/bind/lib/nameser/ns_sign.c b/contrib/bind/lib/nameser/ns_sign.c new file mode 100644 index 0000000..75af894 --- /dev/null +++ b/contrib/bind/lib/nameser/ns_sign.c @@ -0,0 +1,348 @@ +/* + * 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 8.8 1999/10/13 16:39:36 vixie 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 <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 > 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/contrib/bind/lib/nameser/ns_ttl.c b/contrib/bind/lib/nameser/ns_ttl.c index a71d3c7..67cd976 100644 --- a/contrib/bind/lib/nameser/ns_ttl.c +++ b/contrib/bind/lib/nameser/ns_ttl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -16,7 +16,7 @@ */ #ifndef lint -static char rcsid[] = "$Id: ns_ttl.c,v 8.5 1998/02/13 01:16:38 halley Exp $"; +static const char rcsid[] = "$Id: ns_ttl.c,v 8.8 1999/10/13 16:39:36 vixie Exp $"; #endif /* Import. */ @@ -52,7 +52,7 @@ int ns_format_ttl(u_long src, char *dst, size_t dstlen) { char *odst = dst; int secs, mins, hours, days, weeks, x; - char tmp[50], *p; + char *p; secs = src % 60; src /= 60; mins = src % 60; src /= 60; diff --git a/contrib/bind/lib/nameser/ns_verify.c b/contrib/bind/lib/nameser/ns_verify.c new file mode 100644 index 0000000..316da13 --- /dev/null +++ b/contrib/bind/lib/nameser/ns_verify.c @@ -0,0 +1,471 @@ +/* + * 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 8.11 1999/10/15 21:06:51 vixie 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 <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]; + + /* 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_ntol(recstart, buf, sizeof(buf)); + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); + + /* Digest the class and TTL. */ + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, + recstart + dn_skipname(recstart, eom) + INT16SZ, + INT16SZ + INT32SZ, NULL, 0); + + /* Digest the algorithm. */ + n = ns_name_ntol(rdatastart, buf, sizeof(buf)); + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); + + /* Digest the time signed and fudge. */ + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, + rdatastart + dn_skipname(rdatastart, eom), + INT16SZ + INT32SZ + INT16SZ, NULL, 0); + + /* Digest the error and other data. */ + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, + otherstart - INT16SZ - INT16SZ, + 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 > 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; + 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, ×igned, 0)); + + if (state->siglen > 0) { + u_int16_t siglen_n = htons(state->siglen); + + dst_verify_data(SIG_MODE_INIT, state->key, &state->ctx, + NULL, 0, NULL, 0); + dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, + (u_char *)&siglen_n, INT16SZ, NULL, 0); + dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, + state->sig, state->siglen, NULL, 0); + state->siglen = 0; + } + + cp = recstart = ns_find_tsig(msg, eom); + + if (recstart == NULL) { + if (required) + return (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_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/contrib/bind/lib/resolv/Makefile b/contrib/bind/lib/resolv/Makefile index 5be600d..243e69b 100644 --- a/contrib/bind/lib/resolv/Makefile +++ b/contrib/bind/lib/resolv/Makefile @@ -1,4 +1,4 @@ -# Copyright (c) 1996 by Internet Software Consortium +# 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 @@ -13,7 +13,7 @@ # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS # SOFTWARE. -# $Id: Makefile,v 8.17 1997/05/21 19:32:09 halley Exp $ +# $Id: Makefile,v 8.30 1999/10/07 08:24:15 vixie Exp $ # these are only appropriate for BSD 4.4 or derivatives, and are used in # development. normal builds will be done in the top level directory and @@ -31,35 +31,53 @@ TOP= ../.. INCL = ${TOP}/include PORTINCL = ${TOP}/port/${SYSTYPE}/include LIBBIND = ${TOP}/lib/libbind.${A} +LIBBINDR = ../${TOP}/lib/libbind_r.${A} CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL} +# -D__BIND_NOSTATIC LD_LIBFLAGS= -x -r -AR= ar cruv +AR= ar cru RANLIB= ranlib INSTALL= install +INSTALL_EXEC= +INSTALL_LIB=-o bin -g bin +THREADED= threaded SRCS= herror.c res_debug.c res_data.c res_comp.c res_init.c \ - res_mkquery.c res_query.c res_send.c res_mkupdate.c \ - res_update.c + res_mkquery.c res_query.c res_send.c res_sendsigned.c \ + res_mkupdate.c res_update.c \ + res_findzonecut.c OBJS= herror.${O} res_debug.${O} res_data.${O} res_comp.${O} res_init.${O} \ - res_mkquery.${O} res_query.${O} res_send.${O} res_mkupdate.${O} \ - res_update.${O} + res_mkquery.${O} res_query.${O} res_send.${O} res_sendsigned.${O} \ + res_mkupdate.${O} res_update.${O} \ + res_findzonecut.${O} all: ${LIBBIND} ${LIBBIND}: ${OBJS} + ( cd ${THREADED} ; \ + ${AR} ${LIBBINDR} ${ARPREF} ${OBJS} ${ARSUFF} ; \ + ${RANLIB} ${LIBBINDR} ) ${AR} ${LIBBIND} ${ARPREF} ${OBJS} ${ARSUFF} ${RANLIB} ${LIBBIND} .c.${O}: - ${CC} ${CPPFLAGS} ${CFLAGS} -c $*.c - -${LDS} ${LD} ${LD_LIBFLAGS} $*.${O} && ${LDS} mv a.out $*.${O} + if test ! -d ${THREADED} ; then mkdir ${THREADED} ; fi + ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} ${REENTRANT} -c $*.c \ + -o ${THREADED}/$*.${O} + -${LDS} ${LD} ${LD_LIBFLAGS} ${THREADED}/$*.${O} -o a.out && \ + ${LDS} mv a.out ${THREADED}/$*.${O} + ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c + -${LDS} ${LD} ${LD_LIBFLAGS} $*.${O} -o a.out && \ + ${LDS} mv a.out $*.${O} distclean: clean clean: FRC rm -f .depend a.out core ${LIB} tags rm -f *.${O} *.BAK *.CKP *~ + rm -f ${THREADED}/*.${O} + -rmdir ${THREADED} depend: FRC mkdep -I${INCL} -I${PORTINCL} ${CPPFLAGS} ${SRCS} diff --git a/contrib/bind/lib/resolv/herror.c b/contrib/bind/lib/resolv/herror.c index 38217db..bf4cce6 100644 --- a/contrib/bind/lib/resolv/herror.c +++ b/contrib/bind/lib/resolv/herror.c @@ -32,7 +32,7 @@ */ /* - * Portions Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -49,18 +49,27 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)herror.c 8.1 (Berkeley) 6/4/93"; -static char rcsid[] = "$Id: herror.c,v 8.7 1996/11/18 09:10:00 vixie Exp $"; +static const char sccsid[] = "@(#)herror.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: herror.c,v 8.11 1999/10/13 16:39:39 vixie 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)", @@ -78,21 +87,19 @@ int h_errno; * print the error indicated by the h_errno value. */ void -herror(s) - const char *s; -{ - struct iovec iov[4]; - register struct iovec *v = iov; +herror(const char *s) { + struct iovec iov[4], *v = iov; + extern int * __h_errno(); - if (s && *s) { - v->iov_base = (char *)s; + if (s != NULL && *s != '\0') { + v->iov_base = (/*noconst*/ char *)s; v->iov_len = strlen(s); v++; v->iov_base = ": "; v->iov_len = 2; v++; } - v->iov_base = (char *)hstrerror(h_errno); + v->iov_base = (char *)hstrerror(*__h_errno()); v->iov_len = strlen(v->iov_base); v++; v->iov_base = "\n"; @@ -100,10 +107,12 @@ herror(s) writev(STDERR_FILENO, iov, (v - iov) + 1); } +/* + * hstrerror -- + * return the string associated with a given "host" errno value. + */ const char * -hstrerror(err) - int err; -{ +hstrerror(int err) { if (err < 0) return ("Resolver internal error"); else if (err < h_nerr) diff --git a/contrib/bind/lib/resolv/res_comp.c b/contrib/bind/lib/resolv/res_comp.c index c1f946e..d972848 100644 --- a/contrib/bind/lib/resolv/res_comp.c +++ b/contrib/bind/lib/resolv/res_comp.c @@ -52,7 +52,7 @@ */ /* - * Portions Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -69,8 +69,8 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)res_comp.c 8.1 (Berkeley) 6/4/93"; -static char rcsid[] = "$Id: res_comp.c,v 8.11 1997/05/21 19:31:04 halley Exp $"; +static const char sccsid[] = "@(#)res_comp.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: res_comp.c,v 8.15 1999/10/13 16:39:39 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ #include "port_before.h" @@ -244,6 +244,8 @@ res_dnok(const char *dn) { */ 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/contrib/bind/lib/resolv/res_data.c b/contrib/bind/lib/resolv/res_data.c index ca06d64..7688637 100644 --- a/contrib/bind/lib/resolv/res_data.c +++ b/contrib/bind/lib/resolv/res_data.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995,1996 by Internet Software Consortium. + * 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 @@ -16,24 +16,31 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char rcsid[] = "$Id: res_data.c,v 8.5 1996/11/18 09:10:02 vixie Exp $"; +static const char rcsid[] = "$Id: res_data.c,v 8.17 1999/10/13 17:11:31 vixie 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", @@ -54,25 +61,6 @@ const char *_res_opcodes[] = { "ZONEREF", }; -const char *_res_resultcodes[] = { - "NOERROR", - "FORMERR", - "SERVFAIL", - "NXDOMAIN", - "NOTIMP", - "REFUSED", - "YXDOMAIN", - "YXRRSET", - "NXRRSET", - "NOTAUTH", - "ZONEERR", - "11", - "12", - "13", - "14", - "NOCHANGE", -}; - #ifdef BIND_UPDATE const char *_res_sectioncodes[] = { "ZONE", @@ -81,3 +69,224 @@ const char *_res_sectioncodes[] = { "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 *); +void res_pquery(const res_state, const u_char *, int, FILE *); + +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/contrib/bind/lib/resolv/res_debug.c b/contrib/bind/lib/resolv/res_debug.c index 80d1477..39f5e9f 100644 --- a/contrib/bind/lib/resolv/res_debug.c +++ b/contrib/bind/lib/resolv/res_debug.c @@ -77,7 +77,7 @@ */ /* - * Portions Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -94,8 +94,8 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)res_debug.c 8.1 (Berkeley) 6/4/93"; -static char rcsid[] = "$Id: res_debug.c,v 8.20 1998/02/13 01:11:34 halley Exp $"; +static const char sccsid[] = "@(#)res_debug.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: res_debug.c,v 8.32 1999/10/13 16:39:39 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ #include "port_before.h" @@ -127,19 +127,16 @@ static char rcsid[] = "$Id: res_debug.c,v 8.20 1998/02/13 01:11:34 halley Exp $" #endif extern const char *_res_opcodes[]; -extern const char *_res_resultcodes[]; extern const char *_res_sectioncodes[]; /* * Print the current options. */ void -fp_resstat(struct __res_state *statp, FILE *file) { +fp_resstat(const res_state statp, FILE *file) { u_long mask; fprintf(file, ";; res options:"); - if (!statp) - statp = &_res; for (mask = 1; mask != 0; mask <<= 1) if (statp->options & mask) fprintf(file, " %s", p_option(mask)); @@ -147,7 +144,10 @@ fp_resstat(struct __res_state *statp, FILE *file) { } static void -do_section(ns_msg *handle, ns_sect section, int pflag, FILE *file) { +do_section(const res_state statp, + ns_msg *handle, ns_sect section, + int pflag, FILE *file) +{ int n, sflag, rrnum; char buf[2048]; /* XXX need to malloc */ ns_opcode opcode; @@ -156,11 +156,11 @@ do_section(ns_msg *handle, ns_sect section, int pflag, FILE *file) { /* * Print answer records. */ - sflag = (_res.pfcode & pflag); - if (_res.pfcode && !sflag) + sflag = (statp->pfcode & pflag); + if (statp->pfcode && !sflag) return; - opcode = ns_msg_getflag(*handle, ns_f_opcode); + opcode = (ns_opcode) ns_msg_getflag(*handle, ns_f_opcode); rrnum = 0; for (;;) { if (ns_parserr(handle, section, rrnum, &rr)) { @@ -168,11 +168,11 @@ do_section(ns_msg *handle, ns_sect section, int pflag, FILE *file) { fprintf(file, ";; ns_parserr: %s\n", strerror(errno)); else if (rrnum > 0 && sflag != 0 && - (_res.pfcode & RES_PRF_HEAD1)) + (statp->pfcode & RES_PRF_HEAD1)) putc('\n', file); return; } - if (rrnum == 0 && sflag != 0 && (_res.pfcode & RES_PRF_HEAD1)) + if (rrnum == 0 && sflag != 0 && (statp->pfcode & RES_PRF_HEAD1)) fprintf(file, ";; %s SECTION:\n", p_section(section, opcode)); if (section == ns_s_qd) @@ -195,29 +195,16 @@ do_section(ns_msg *handle, ns_sect section, int pflag, FILE *file) { } } -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); -} - /* * Print the contents of a query. * This is intended to be primarily a debugging routine. */ void -fp_nquery(const u_char *msg, int len, FILE *file) { +res_pquery(const res_state statp, const u_char *msg, int len, FILE *file) { ns_msg handle; - int n, qdcount, ancount, nscount, arcount; + int qdcount, ancount, nscount, arcount; u_int opcode, rcode, id; - if ((_res.options & RES_INIT) == 0 && res_init() == -1) - return; - if (ns_initparse(msg, len, &handle) < 0) { fprintf(file, ";; ns_initparse: %s\n", strerror(errno)); return; @@ -233,13 +220,13 @@ fp_nquery(const u_char *msg, int len, FILE *file) { /* * Print header fields. */ - if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEADX) || rcode) + if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEADX) || rcode) fprintf(file, ";; ->>HEADER<<- opcode: %s, status: %s, id: %d\n", - _res_opcodes[opcode], _res_resultcodes[rcode], id); - if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEADX)) + _res_opcodes[opcode], p_rcode(rcode), id); + if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEADX)) putc(';', file); - if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD2)) { + if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEAD2)) { fprintf(file, "; flags:"); if (ns_msg_getflag(handle, ns_f_qr)) fprintf(file, " qr"); @@ -258,7 +245,7 @@ fp_nquery(const u_char *msg, int len, FILE *file) { if (ns_msg_getflag(handle, ns_f_cd)) fprintf(file, " cd"); } - if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD1)) { + if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEAD1)) { fprintf(file, "; %s: %d", p_section(ns_s_qd, opcode), qdcount); fprintf(file, ", %s: %d", @@ -268,17 +255,17 @@ fp_nquery(const u_char *msg, int len, FILE *file) { fprintf(file, ", %s: %d", p_section(ns_s_ar, opcode), arcount); } - if ((!_res.pfcode) || (_res.pfcode & + if ((!statp->pfcode) || (statp->pfcode & (RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) { putc('\n',file); } /* * Print the various sections. */ - do_section(&handle, ns_s_qd, RES_PRF_QUES, file); - do_section(&handle, ns_s_an, RES_PRF_ANS, file); - do_section(&handle, ns_s_ns, RES_PRF_AUTH, file); - do_section(&handle, ns_s_ar, RES_PRF_ADD, file); + 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); @@ -375,55 +362,99 @@ const struct res_sym __p_update_section_syms[] = { {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[] = { - {T_A, "A", "address"}, - {T_NS, "NS", "name server"}, - {T_MD, "MD", "mail destination (deprecated)"}, - {T_MF, "MF", "mail forwarder (deprecated)"}, - {T_CNAME, "CNAME", "canonical name"}, - {T_SOA, "SOA", "start of authority"}, - {T_MB, "MB", "mailbox"}, - {T_MG, "MG", "mail group member"}, - {T_MR, "MR", "mail rename"}, - {T_NULL, "NULL", "null"}, - {T_WKS, "WKS", "well-known service (deprecated)"}, - {T_PTR, "PTR", "domain name pointer"}, - {T_HINFO, "HINFO", "host information"}, - {T_MINFO, "MINFO", "mailbox information"}, - {T_MX, "MX", "mail exchanger"}, - {T_TXT, "TXT", "text"}, - {T_RP, "RP", "responsible person"}, - {T_AFSDB, "AFSDB", "DCE or AFS server"}, - {T_X25, "X25", "X25 address"}, - {T_ISDN, "ISDN", "ISDN address"}, - {T_RT, "RT", "router"}, - {T_NSAP, "NSAP", "nsap address"}, - {T_NSAP_PTR, "NSAP_PTR", "domain name pointer"}, - {T_SIG, "SIG", "signature"}, - {T_KEY, "KEY", "key"}, - {T_PX, "PX", "mapping information"}, - {T_GPOS, "GPOS", "geographical position (withdrawn)"}, - {T_AAAA, "AAAA", "IPv6 address"}, - {T_LOC, "LOC", "location"}, - {T_NXT, "NXT", "next valid name (unimplemented)"}, - {T_EID, "EID", "endpoint identifier (unimplemented)"}, - {T_NIMLOC, "NIMLOC", "NIMROD locator (unimplemented)"}, - {T_SRV, "SRV", "server selection"}, - {T_ATMA, "ATMA", "ATM address (unimplemented)"}, - {T_IXFR, "IXFR", "incremental zone transfer"}, - {T_AXFR, "AXFR", "zone transfer"}, - {T_MAILB, "MAILB", "mailbox-related data (deprecated)"}, - {T_MAILA, "MAILA", "mail agent (deprecated)"}, - {T_NAPTR, "NAPTR", "URN Naming Authority"}, - {T_ANY, "ANY", "\"any\""}, + {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_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_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++) { @@ -450,7 +481,7 @@ sym_ntos(const struct res_sym *syms, int number, int *success) { } } - sprintf(unname, "%d", number); + sprintf(unname, "%d", number); /* XXX nonreentrant */ if (success) *success = 0; return (unname); @@ -467,7 +498,7 @@ sym_ntop(const struct res_sym *syms, int number, int *success) { return (syms->humanname); } } - sprintf(unname, "%d", number); + sprintf(unname, "%d", number); /* XXX nonreentrant */ if (success) *success = 0; return (unname); @@ -527,6 +558,7 @@ p_option(u_long option) { case RES_DNSRCH: return "dnsrch"; case RES_INSECURE1: return "insecure1"; case RES_INSECURE2: return "insecure2"; + /* XXX nonreentrant */ default: sprintf(nbuf, "?0x%lx?", (u_long)option); return (nbuf); } @@ -537,13 +569,20 @@ p_option(u_long option) { */ const char * p_time(u_int32_t value) { - static char nbuf[40]; + 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. @@ -559,7 +598,7 @@ static const char * precsize_ntoa(prec) u_int8_t prec; { - static char retbuf[sizeof "90000000.00"]; + static char retbuf[sizeof "90000000.00"]; /* XXX nonreentrant */ unsigned long val; int mantissa, exponent; @@ -831,6 +870,8 @@ loc_ntoa(binary, ascii) char *ascii; { static 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; @@ -848,6 +889,9 @@ loc_ntoa(binary, ascii) versionval = *cp++; + if (ascii == NULL) + ascii = tmpbuf; + if (versionval) { (void) sprintf(ascii, "; error: unknown LOC RR version"); return (ascii); @@ -960,11 +1004,16 @@ dn_count_labels(const char *name) { */ 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", diff --git a/contrib/bind/lib/resolv/res_debug.h b/contrib/bind/lib/resolv/res_debug.h new file mode 100644 index 0000000..1150551 --- /dev/null +++ b/contrib/bind/lib/resolv/res_debug.h @@ -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(file, string, error, address) /*empty*/ +# define Perror(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/contrib/bind/lib/resolv/res_findzonecut.c b/contrib/bind/lib/resolv/res_findzonecut.c new file mode 100644 index 0000000..73a42a2 --- /dev/null +++ b/contrib/bind/lib/resolv/res_findzonecut.c @@ -0,0 +1,596 @@ +#if !defined(lint) && !defined(SABER) +static const char rcsid[] = "$Id: res_findzonecut.c,v 8.8 1999/10/15 19:49:11 vixie 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. + * + * we cannot fail to find an SOA in this way. ultimately we'll return + * a zname indicating the root zone if that's the closest enclosing zone. + * however, since authority section SOA's were once optional, it's + * possible that we'll have to go hunting for the enclosing SOA by + * ripping labels off the front of our dname -- this is known as "doing + * it the hard way." + * + * ultimately we want some server addresses, which are ideally the ones + * pertaining to the SOA.MNAME, but only if there is a matching NS RR. + * so the second phase (after we find an SOA) is to go looking for the + * NS RRset for that SOA's zone. + * + * no answer section processed by this code is allowed to contain CNAME + * or DNAME RR's. for the SOA query this means we strip a label and + * keep going. for the NS and A queries this means we just give up. + */ + +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('zname', %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), n)); + return (-1); + } + 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_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); + } + 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; + + while ((arr = HEAD(nsrr->addrs)) != NULL) { + UNLINK(nsrr->addrs, arr, link); + free(arr); + } + free((char *)nsrr->name); + 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/contrib/bind/lib/resolv/res_init.c b/contrib/bind/lib/resolv/res_init.c index f374d51..85dc7e3 100644 --- a/contrib/bind/lib/resolv/res_init.c +++ b/contrib/bind/lib/resolv/res_init.c @@ -52,7 +52,7 @@ */ /* - * Portions Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -69,24 +69,28 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)res_init.c 8.1 (Berkeley) 6/7/93"; -static char rcsid[] = "$Id: res_init.c,v 8.7 1996/11/18 09:10:04 vixie Exp $"; +static const char sccsid[] = "@(#)res_init.c 8.1 (Berkeley) 6/7/93"; +static const char rcsid[] = "$Id: res_init.c,v 8.13 1999/10/13 16:39:40 vixie 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 "port_after.h" /* Options. Should all be left alone. */ @@ -94,7 +98,7 @@ static char rcsid[] = "$Id: res_init.c,v 8.7 1996/11/18 09:10:04 vixie Exp $"; #define RFC1535 #define DEBUG -static void res_setoptions __P((char *, char *)); +static void res_setoptions __P((res_state, const char *, const char *)); #ifdef RESOLVSORT static const char sort_mask[] = "/&"; @@ -110,13 +114,6 @@ static u_int32_t net_mask __P((struct in_addr)); * Resolver state default settings. */ -struct __res_state _res -# if defined(__BIND_RES_TEXT) - = { RES_TIMEOUT, } /* Motorola, et al. */ -# endif - ; - - /* * Set up default settings. If the configuration file exist, the values * there will have precedence. Otherwise, the server address is set to @@ -139,7 +136,15 @@ struct __res_state _res * Return 0 if completes successfully, -1 on error */ int -res_init() { +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; @@ -155,53 +160,32 @@ res_init() { int dots; #endif - /* - * 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(); + if (!preinit) { + statp->retrans = RES_TIMEOUT; + statp->retry = RES_DFLRETRY; + statp->options = RES_DEFAULT; + statp->id = res_randomid(); + } #ifdef USELOOPBACK - _res.nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1); + statp->nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1); #else - _res.nsaddr.sin_addr.s_addr = INADDR_ANY; + statp->nsaddr.sin_addr.s_addr = INADDR_ANY; #endif - _res.nsaddr.sin_family = AF_INET; - _res.nsaddr.sin_port = htons(NAMESERVER_PORT); - _res.nscount = 1; - _res.ndots = 1; - _res.pfcode = 0; + statp->nsaddr.sin_family = AF_INET; + statp->nsaddr.sin_port = htons(NAMESERVER_PORT); + statp->nscount = 1; + statp->ndots = 1; + statp->pfcode = 0; + statp->_sock = -1; + statp->_flags = 0; + statp->qhook = NULL; + statp->rhook = NULL; /* Allow user to override the local domain definition */ if ((cp = getenv("LOCALDOMAIN")) != NULL) { - (void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1); + (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); + statp->defdname[sizeof(statp->defdname) - 1] = '\0'; haveenv++; /* @@ -211,10 +195,10 @@ res_init() { * one that they want to use as an individual (even more * important now that the rfc1535 stuff restricts searches) */ - cp = _res.defdname; - pp = _res.dnsrch; + cp = statp->defdname; + pp = statp->dnsrch; *pp++ = cp; - for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) { + for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { if (*cp == '\n') /* silly backwards compat */ break; else if (*cp == ' ' || *cp == '\t') { @@ -253,8 +237,9 @@ res_init() { cp++; if ((*cp == '\0') || (*cp == '\n')) continue; - strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1); - if ((cp = strpbrk(_res.defdname, " \t\n")) != NULL) + 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; @@ -268,17 +253,18 @@ res_init() { cp++; if ((*cp == '\0') || (*cp == '\n')) continue; - strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1); - if ((cp = strchr(_res.defdname, '\n')) != NULL) + 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 = _res.defdname; - pp = _res.dnsrch; + cp = statp->defdname; + pp = statp->dnsrch; *pp++ = cp; - for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) { + for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { if (*cp == ' ' || *cp == '\t') { *cp = 0; n = 1; @@ -303,9 +289,9 @@ res_init() { while (*cp == ' ' || *cp == '\t') cp++; if ((*cp != '\0') && (*cp != '\n') && inet_aton(cp, &a)) { - _res.nsaddr_list[nserv].sin_addr = a; - _res.nsaddr_list[nserv].sin_family = AF_INET; - _res.nsaddr_list[nserv].sin_port = + statp->nsaddr_list[nserv].sin_addr = a; + statp->nsaddr_list[nserv].sin_family = AF_INET; + statp->nsaddr_list[nserv].sin_port = htons(NAMESERVER_PORT); nserv++; } @@ -328,7 +314,7 @@ res_init() { n = *cp; *cp = 0; if (inet_aton(net, &a)) { - _res.sort_list[nsort].addr = a; + statp->sort_list[nsort].addr = a; if (ISSORTMASK(n)) { *cp++ = n; net = cp; @@ -338,14 +324,14 @@ res_init() { n = *cp; *cp = 0; if (inet_aton(net, &a)) { - _res.sort_list[nsort].mask = a.s_addr; + statp->sort_list[nsort].mask = a.s_addr; } else { - _res.sort_list[nsort].mask = - net_mask(_res.sort_list[nsort].addr); + statp->sort_list[nsort].mask = + net_mask(statp->sort_list[nsort].addr); } } else { - _res.sort_list[nsort].mask = - net_mask(_res.sort_list[nsort].addr); + statp->sort_list[nsort].mask = + net_mask(statp->sort_list[nsort].addr); } nsort++; } @@ -355,35 +341,35 @@ res_init() { } #endif if (MATCH(buf, "options")) { - res_setoptions(buf + sizeof("options") - 1, "conf"); + res_setoptions(statp, buf + sizeof("options") - 1, "conf"); continue; } } if (nserv > 1) - _res.nscount = nserv; + statp->nscount = nserv; #ifdef RESOLVSORT - _res.nsort = nsort; + statp->nsort = nsort; #endif (void) fclose(fp); } - if (_res.defdname[0] == 0 && - gethostname(buf, sizeof(_res.defdname) - 1) == 0 && + if (statp->defdname[0] == 0 && + gethostname(buf, sizeof(statp->defdname) - 1) == 0 && (cp = strchr(buf, '.')) != NULL) - strcpy(_res.defdname, cp + 1); + strcpy(statp->defdname, cp + 1); /* find components of local domain that might be searched */ if (havesearch == 0) { - pp = _res.dnsrch; - *pp++ = _res.defdname; + pp = statp->dnsrch; + *pp++ = statp->defdname; *pp = NULL; #ifndef RFC1535 dots = 0; - for (cp = _res.defdname; *cp; cp++) + for (cp = statp->defdname; *cp; cp++) dots += (*cp == '.'); - cp = _res.defdname; - while (pp < _res.dnsrch + MAXDFLSRCH) { + cp = statp->defdname; + while (pp < statp->dnsrch + MAXDFLSRCH) { if (dots < LOCALDOMAINPARTS) break; cp = strchr(cp, '.') + 1; /* we know there is one */ @@ -392,9 +378,9 @@ res_init() { } *pp = NULL; #ifdef DEBUG - if (_res.options & RES_DEBUG) { + if (statp->options & RES_DEBUG) { printf(";; res_init()... default dnsrch list:\n"); - for (pp = _res.dnsrch; *pp; pp++) + for (pp = statp->dnsrch; *pp; pp++) printf(";;\t%s\n", *pp); printf(";;\t..END..\n"); } @@ -403,20 +389,18 @@ res_init() { } if ((cp = getenv("RES_OPTIONS")) != NULL) - res_setoptions(cp, "env"); - _res.options |= RES_INIT; + res_setoptions(statp, cp, "env"); + statp->options |= RES_INIT; return (0); } static void -res_setoptions(options, source) - char *options, *source; -{ - char *cp = options; +res_setoptions(res_state statp, const char *options, const char *source) { + const char *cp = options; int i; #ifdef DEBUG - if (_res.options & RES_DEBUG) + if (statp->options & RES_DEBUG) printf(";; res_setoptions(\"%s\", \"%s\")...\n", options, source); #endif @@ -428,24 +412,41 @@ res_setoptions(options, source) if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) { i = atoi(cp + sizeof("ndots:") - 1); if (i <= RES_MAXNDOTS) - _res.ndots = i; + statp->ndots = i; else - _res.ndots = RES_MAXNDOTS; + statp->ndots = RES_MAXNDOTS; #ifdef DEBUG - if (_res.options & RES_DEBUG) - printf(";;\tndots=%d\n", _res.ndots); + 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 (!(_res.options & RES_DEBUG)) { + if (!(statp->options & RES_DEBUG)) { printf(";; res_setoptions(\"%s\", \"%s\")..\n", options, source); - _res.options |= RES_DEBUG; + statp->options |= RES_DEBUG; } printf(";;\tdebug\n"); #endif } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) { - _res.options |= RES_USE_INET6; + statp->options |= RES_USE_INET6; + } else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) { + statp->options |= RES_ROTATE; + } else if (!strncmp(cp, "no-check-names", + sizeof("no-check-names") - 1)) { + statp->options |= RES_NOCHECKNAME; } else { /* XXX - print a warning here? */ } @@ -472,8 +473,7 @@ net_mask(in) /* XXX - should really use system's version of this */ #endif u_int -res_randomid() -{ +res_randomid(void) { struct timeval now; gettimeofday(&now, NULL); diff --git a/contrib/bind/lib/resolv/res_mkquery.c b/contrib/bind/lib/resolv/res_mkquery.c index 74be28b..17b1ccf 100644 --- a/contrib/bind/lib/resolv/res_mkquery.c +++ b/contrib/bind/lib/resolv/res_mkquery.c @@ -52,7 +52,7 @@ */ /* - * Portions Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -69,8 +69,8 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)res_mkquery.c 8.1 (Berkeley) 6/4/93"; -static char rcsid[] = "$Id: res_mkquery.c,v 8.9 1997/04/24 22:22:36 vixie Exp $"; +static const char sccsid[] = "@(#)res_mkquery.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: res_mkquery.c,v 8.12 1999/10/13 16:39:40 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ #include "port_before.h" @@ -87,34 +87,32 @@ static char rcsid[] = "$Id: res_mkquery.c,v 8.9 1997/04/24 22:22:36 vixie Exp $" /* 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_mkquery(op, dname, class, type, data, datalen, newrr_in, buf, buflen) - int op; /* opcode of query */ - const char *dname; /* domain name */ - int class, 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 */ +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; - if ((_res.options & RES_INIT) == 0 && res_init() == -1) { - h_errno = NETDB_INTERNAL; - return (-1); - } #ifdef DEBUG - if (_res.options & RES_DEBUG) - printf(";; res_mkquery(%d, %s, %d, %d)\n", - op, dname, class, type); + 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. @@ -123,9 +121,9 @@ res_mkquery(op, dname, class, type, data, datalen, newrr_in, buf, buflen) return (-1); memset(buf, 0, HFIXEDSZ); hp = (HEADER *) buf; - hp->id = htons(++_res.id); + hp->id = htons(++statp->id); hp->opcode = op; - hp->rd = (_res.options & RES_RECURSE) != 0; + hp->rd = (statp->options & RES_RECURSE) != 0; hp->rcode = NOERROR; cp = buf + HFIXEDSZ; buflen -= HFIXEDSZ; diff --git a/contrib/bind/lib/resolv/res_mkupdate.c b/contrib/bind/lib/resolv/res_mkupdate.c index c6e7f4a1..14e1a60 100644 --- a/contrib/bind/lib/resolv/res_mkupdate.c +++ b/contrib/bind/lib/resolv/res_mkupdate.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -21,7 +21,7 @@ */ #if !defined(lint) && !defined(SABER) -static char rcsid[] = "$Id: res_mkupdate.c,v 1.11 1998/01/26 23:08:45 halley Exp $"; +static const char rcsid[] = "$Id: res_mkupdate.c,v 1.24 1999/10/13 17:11:32 vixie Exp $"; #endif /* not lint */ #include "port_before.h" @@ -37,6 +37,7 @@ static char rcsid[] = "$Id: res_mkupdate.c,v 1.11 1998/01/26 23:08:45 halley Exp #include <limits.h> #include <netdb.h> #include <resolv.h> +#include <res_update.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -47,12 +48,20 @@ static char rcsid[] = "$Id: res_mkupdate.c,v 1.11 1998/01/26 23:08:45 halley Exp /* 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 @@ -66,23 +75,21 @@ static int getword_str(char *, int, u_char **, u_char *); * -5 unknown operation or no records */ int -res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) { +res_nmkupdate(res_state statp, ns_updrec *rrecp_in, u_char *buf, int buflen) { ns_updrec *rrecp_start = rrecp_in; HEADER *hp; - u_char c, *cp, *cp1, *sp1, *sp2, *startp, *endp; - int n, i, j, found, soanum, multiline; - ns_updrec *rrecp, *tmprrecp, *recptr = NULL; + 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; - - if ((_res.options & RES_INIT) == 0 && res_init() == -1) { - h_errno = NETDB_INTERNAL; - return (-1); - } + int siglen, keylen, certlen; /* * Initialize header fields. @@ -91,7 +98,7 @@ res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) { return (-1); memset(buf, 0, HFIXEDSZ); hp = (HEADER *) buf; - hp->id = htons(++_res.id); + hp->id = htons(++statp->id); hp->opcode = ns_o_update; hp->rcode = NOERROR; sp1 = buf + 2*INT16SZ; /* save pointer to zocount */ @@ -108,7 +115,7 @@ res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) { return (-3); memset(counts, 0, sizeof counts); - for (rrecp = rrecp_start; rrecp; rrecp = rrecp->r_grpnext) { + for (rrecp = rrecp_start; rrecp; rrecp = NEXT(rrecp, r_glink)) { numrrs++; section = rrecp->r_section; if (section < 0 || section >= ns_s_max) @@ -264,8 +271,35 @@ res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) { 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); @@ -292,17 +326,315 @@ res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) { ShrinkBuffer(n); } break; - case T_WKS: + case T_WKS: { + char bm[MAXPORT/8]; + 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: - /* XXX - more fine tuning needed here */ - ShrinkBuffer(rrecp->r_size); - memcpy(cp, rrecp->r_data, rrecp->r_size); - cp += rrecp->r_size; + 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); @@ -348,14 +680,140 @@ getword_str(char *buf, int size, u_char **startpp, u_char *endp) { } /* - * Get a whitespace delimited number from a string (not file) into 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 seendecimal = 0; int m = 0; for (n = 0; *startpp <= endp; ) { @@ -398,8 +856,11 @@ 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 || !(rrecp->r_dname = strdup(dname))) { + if (rrecp) + free((char *)rrecp); return (NULL); + } rrecp->r_class = class; rrecp->r_type = type; rrecp->r_ttl = ttl; @@ -417,3 +878,221 @@ res_freeupdrec(ns_updrec *rrecp) { 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; + +void +res_buildservicelist() { + struct servent *sp; + struct valuelist *slp; + +#ifdef MAYBE_HESIOD + setservent(0); +#else + setservent(1); +#endif + while ((sp = getservent()) != NULL) { + slp = (struct valuelist *)malloc(sizeof(struct valuelist)); + if (!slp) + break; + slp->name = strdup(sp->s_name); + slp->proto = strdup(sp->s_proto); + if ((slp->name == NULL) || (slp->proto == NULL)) { + if (slp->name) free(slp->name); + if (slp->proto) free(slp->proto); + free(slp); + break; + } + slp->port = ntohs((u_int16_t)sp->s_port); /* host byt order */ + slp->next = servicelist; + slp->prev = NULL; + if (servicelist) + servicelist->prev = slp; + servicelist = slp; + } + endservent(); +} + +void +res_destroyservicelist() { + struct valuelist *slp, *slp_next; + + for (slp = servicelist; slp != NULL; slp = slp_next) { + slp_next = slp->next; + free(slp->name); + free(slp->proto); + free(slp); + } + servicelist = (struct valuelist *)0; +} + +void +res_buildprotolist() { + struct protoent *pp; + struct valuelist *slp; + +#ifdef MAYBE_HESIOD + setprotoent(0); +#else + setprotoent(1); +#endif + while ((pp = getprotoent()) != NULL) { + slp = (struct valuelist *)malloc(sizeof(struct valuelist)); + if (!slp) + break; + slp->name = strdup(pp->p_name); + if (slp->name == NULL) { + free(slp); + break; + } + slp->port = pp->p_proto; /* host byte order */ + slp->next = protolist; + slp->prev = NULL; + if (protolist) + protolist->prev = slp; + protolist = slp; + } + endprotoent(); +} + +void +res_destroyprotolist() { + struct valuelist *plp, *plp_next; + + for (plp = protolist; plp != NULL; plp = plp_next) { + plp_next = plp->next; + free(plp->name); + free(plp); + } + protolist = (struct valuelist *)0; +} + +static int +findservice(const char *s, struct valuelist **list) { + struct valuelist *lp = *list; + int n; + + for (; lp != NULL; lp = lp->next) + if (strcasecmp(lp->name, s) == 0) { + if (lp != *list) { + lp->prev->next = lp->next; + if (lp->next) + lp->next->prev = lp->prev; + (*list)->prev = lp; + lp->next = *list; + *list = lp; + } + return (lp->port); /* host byte order */ + } + if (sscanf(s, "%d", &n) != 1 || n <= 0) + n = -1; + return (n); +} + +/* + * Convert service name or (ascii) number to int. + */ +int +res_servicenumber(const char *p) { + if (servicelist == (struct valuelist *)0) + res_buildservicelist(); + return (findservice(p, &servicelist)); +} + +/* + * Convert protocol name or (ascii) number to int. + */ +int +res_protocolnumber(const char *p) { + if (protolist == (struct valuelist *)0) + res_buildprotolist(); + return (findservice(p, &protolist)); +} + +static struct servent * +cgetservbyport(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/contrib/bind/lib/resolv/res_mkupdate.h b/contrib/bind/lib/resolv/res_mkupdate.h index eb2be3f..48edf63 100644 --- a/contrib/bind/lib/resolv/res_mkupdate.h +++ b/contrib/bind/lib/resolv/res_mkupdate.h @@ -1,3 +1,20 @@ +/* + * 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_ diff --git a/contrib/bind/lib/resolv/res_query.c b/contrib/bind/lib/resolv/res_query.c index aeef49d..26c1a60 100644 --- a/contrib/bind/lib/resolv/res_query.c +++ b/contrib/bind/lib/resolv/res_query.c @@ -52,7 +52,7 @@ */ /* - * Portions Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -69,8 +69,8 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)res_query.c 8.1 (Berkeley) 6/4/93"; -static char rcsid[] = "$Id: res_query.c,v 8.14 1997/06/09 17:47:05 halley Exp $"; +static const char sccsid[] = "@(#)res_query.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: res_query.c,v 8.19 1999/10/15 19:49:11 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ #include "port_before.h" @@ -103,16 +103,16 @@ static char rcsid[] = "$Id: res_query.c,v 8.14 1997/06/09 17:47:05 halley Exp $" * 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. + * Error number is left in H_ERRNO. * * Caller must parse answer and determine whether it answers the question. */ int -res_query(name, class, type, answer, anslen) - const char *name; /* domain name */ - int class, type; /* class and type of query */ - u_char *answer; /* buffer to put answer */ - int anslen; /* size of answer buffer */ +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; @@ -120,56 +120,52 @@ res_query(name, class, type, answer, anslen) hp->rcode = NOERROR; /* default */ - if ((_res.options & RES_INIT) == 0 && res_init() == -1) { - h_errno = NETDB_INTERNAL; - return (-1); - } #ifdef DEBUG - if (_res.options & RES_DEBUG) + if (statp->options & RES_DEBUG) printf(";; res_query(%s, %d, %d)\n", name, class, type); #endif - n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL, - buf, sizeof(buf)); + n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL, + buf, sizeof(buf)); if (n <= 0) { #ifdef DEBUG - if (_res.options & RES_DEBUG) + if (statp->options & RES_DEBUG) printf(";; res_query: mkquery failed\n"); #endif - h_errno = NO_RECOVERY; + RES_SET_H_ERRNO(statp, NO_RECOVERY); return (n); } - n = res_send(buf, n, answer, anslen); + n = res_nsend(statp, buf, n, answer, anslen); if (n < 0) { #ifdef DEBUG - if (_res.options & RES_DEBUG) + if (statp->options & RES_DEBUG) printf(";; res_query: send error\n"); #endif - h_errno = TRY_AGAIN; + RES_SET_H_ERRNO(statp, TRY_AGAIN); return (n); } if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { #ifdef DEBUG - if (_res.options & RES_DEBUG) + if (statp->options & RES_DEBUG) printf(";; rcode = %d, ancount=%d\n", hp->rcode, ntohs(hp->ancount)); #endif switch (hp->rcode) { case NXDOMAIN: - h_errno = HOST_NOT_FOUND; + RES_SET_H_ERRNO(statp, HOST_NOT_FOUND); break; case SERVFAIL: - h_errno = TRY_AGAIN; + RES_SET_H_ERRNO(statp, TRY_AGAIN); break; case NOERROR: - h_errno = NO_DATA; + RES_SET_H_ERRNO(statp, NO_DATA); break; case FORMERR: case NOTIMP: case REFUSED: default: - h_errno = NO_RECOVERY; + RES_SET_H_ERRNO(statp, NO_RECOVERY); break; } return (-1); @@ -181,50 +177,43 @@ res_query(name, class, type, answer, anslen) * 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. + * is detected. Error code, if any, is left in H_ERRNO. */ int -res_search(name, class, type, answer, anslen) - const char *name; /* domain name */ - int class, type; /* class and type of query */ - u_char *answer; /* buffer to put answer */ - int anslen; /* size of answer */ +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, tried_as_is = 0; + int trailing_dot, ret; + int got_nodata = 0, got_servfail = 0, root_on_list = 0; - if ((_res.options & RES_INIT) == 0 && res_init() == -1) { - h_errno = NETDB_INTERNAL; - return (-1); - } errno = 0; - h_errno = HOST_NOT_FOUND; /* default, if we never query */ + RES_SET_H_ERRNO(statp, HOST_NOT_FOUND); /* True if we never query. */ + dots = 0; - for (cp = name; *cp; cp++) + 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 = hostalias(name)) != NULL) - return (res_query(cp, class, type, answer, anslen)); + if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL) + return (res_nquery(statp, cp, class, type, answer, anslen)); /* - * If there are dots in the name already, let's just give it a try - * 'as is'. The threshold can be set with the "ndots" option. + * If there are enough dots in the name, do no searching. + * (The threshold can be set with the "ndots" option.) */ - saved_herrno = -1; - if (dots >= _res.ndots) { - ret = res_querydomain(name, NULL, class, type, answer, anslen); - if (ret > 0) - return (ret); - saved_herrno = h_errno; - tried_as_is++; - } + if (dots >= statp->ndots || trailing_dot) + return (res_nquerydomain(statp, name, NULL, class, type, + answer, anslen)); /* * We do at least one level of search if @@ -232,16 +221,21 @@ res_search(name, class, type, answer, anslen) * - there is at least one dot, there is no trailing dot, * and RES_DNSRCH is set. */ - if ((!dots && (_res.options & RES_DEFNAMES)) || - (dots && !trailing_dot && (_res.options & RES_DNSRCH))) { + if ((!dots && (statp->options & RES_DEFNAMES) != 0) || + (dots && !trailing_dot && (statp->options & RES_DNSRCH) != 0)) { int done = 0; - for (domain = (const char * const *)_res.dnsrch; + for (domain = (const char * const *)statp->dnsrch; *domain && !done; domain++) { - ret = res_querydomain(name, *domain, class, type, - answer, anslen); + 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); @@ -259,11 +253,11 @@ res_search(name, class, type, answer, anslen) * fully-qualified. */ if (errno == ECONNREFUSED) { - h_errno = TRY_AGAIN; + RES_SET_H_ERRNO(statp, TRY_AGAIN); return (-1); } - switch (h_errno) { + switch (statp->res_h_errno) { case NO_DATA: got_nodata++; /* FALLTHROUGH */ @@ -285,35 +279,33 @@ res_search(name, class, type, answer, anslen) /* if we got here for some reason other than DNSRCH, * we only wanted one iteration of the loop, so stop. */ - if (!(_res.options & RES_DNSRCH)) + if ((statp->options & RES_DNSRCH) == 0) done++; } } /* - * If we have not already tried the name "as is", do that now. - * note that we do this regardless of how many dots were in the - * name or whether it ends with a dot. + * If the name has any dots at all, and "." is not on the search + * list, then try an as-is query now. */ - if (!tried_as_is) { - ret = res_querydomain(name, NULL, class, type, answer, anslen); + if (statp->ndots) { + 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 + * 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 + * else send back meaningless H_ERRNO, that being the one from * the last DNSRCH we did. */ - if (saved_herrno != -1) - h_errno = saved_herrno; - else if (got_nodata) - h_errno = NO_DATA; + if (got_nodata) + RES_SET_H_ERRNO(statp, NO_DATA); else if (got_servfail) - h_errno = TRY_AGAIN; + RES_SET_H_ERRNO(statp, TRY_AGAIN); return (-1); } @@ -322,23 +314,20 @@ res_search(name, class, type, answer, anslen) * removing a trailing dot from name if domain is NULL. */ int -res_querydomain(name, domain, class, type, answer, anslen) - const char *name, *domain; - int class, type; /* class and type of query */ - u_char *answer; /* buffer to put answer */ - int anslen; /* size of answer */ +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; - if ((_res.options & RES_INIT) == 0 && res_init() == -1) { - h_errno = NETDB_INTERNAL; - return (-1); - } #ifdef DEBUG - if (_res.options & RES_DEBUG) - printf(";; res_querydomain(%s, %s, %d, %d)\n", + if (statp->options & RES_DEBUG) + printf(";; res_nquerydomain(%s, %s, %d, %d)\n", name, domain?domain:"<Nil>", class, type); #endif if (domain == NULL) { @@ -348,7 +337,7 @@ res_querydomain(name, domain, class, type, answer, anslen) */ n = strlen(name); if (n >= MAXDNAME) { - h_errno = NO_RECOVERY; + RES_SET_H_ERRNO(statp, NO_RECOVERY); return (-1); } n--; @@ -361,23 +350,21 @@ res_querydomain(name, domain, class, type, answer, anslen) n = strlen(name); d = strlen(domain); if (n + d + 1 >= MAXDNAME) { - h_errno = NO_RECOVERY; + RES_SET_H_ERRNO(statp, NO_RECOVERY); return (-1); } sprintf(nbuf, "%s.%s", name, domain); } - return (res_query(longname, class, type, answer, anslen)); + return (res_nquery(statp, longname, class, type, answer, anslen)); } const char * -hostalias(const char *name) { - char *cp1, *cp2; - FILE *fp; - char *file; +res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) { + char *file, *cp1, *cp2; char buf[BUFSIZ]; - static char abuf[MAXDNAME]; + FILE *fp; - if (_res.options & RES_NOALIASES) + if (statp->options & RES_NOALIASES) return (NULL); file = getenv("HOSTALIASES"); if (file == NULL || (fp = fopen(file, "r")) == NULL) @@ -390,17 +377,18 @@ hostalias(const char *name) { if (!*cp1) break; *cp1 = '\0'; - if (!strcasecmp(buf, name)) { + if (ns_samename(buf, name) == 1) { while (isspace(*++cp1)) ; if (!*cp1) break; for (cp2 = cp1 + 1; *cp2 && !isspace(*cp2); ++cp2) ; - abuf[sizeof(abuf) - 1] = *cp2 = '\0'; - strncpy(abuf, cp1, sizeof(abuf) - 1); + *cp2 = '\0'; + strncpy(dst, cp1, siz - 1); + dst[siz - 1] = '\0'; fclose(fp); - return (abuf); + return (dst); } } fclose(fp); diff --git a/contrib/bind/lib/resolv/res_send.c b/contrib/bind/lib/resolv/res_send.c index f8ac77b..80c9e44 100644 --- a/contrib/bind/lib/resolv/res_send.c +++ b/contrib/bind/lib/resolv/res_send.c @@ -52,7 +52,7 @@ */ /* - * Portions Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -69,8 +69,8 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93"; -static char rcsid[] = "$Id: res_send.c,v 8.20 1998/04/06 23:27:51 halley Exp $"; +static const char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: res_send.c,v 8.36 1999/10/15 19:49:11 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ /* @@ -93,78 +93,60 @@ static char rcsid[] = "$Id: res_send.c,v 8.20 1998/04/06 23:27:51 halley Exp $"; #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 -#define CHECK_SRVR_ADDR - -static int s = -1; /* socket used for communications */ -static int connected = 0; /* is the socket connected */ -static int vc = 0; /* is the socket a virtual circuit? */ -static res_send_qhook Qhook = NULL; -static res_send_rhook Rhook = NULL; +#include "res_debug.h" +#ifdef NEED_PSELECT +static int pselect(int, void *, void *, void *, + struct timespec *, + const sigset_t *); +#endif -#ifndef DEBUG -# define Dprint(cond, args) /*empty*/ -# define DprintQ(cond, args, query, size) /*empty*/ -# define Aerror(file, string, error, address) /*empty*/ -# define Perror(file, string, error) /*empty*/ -#else -# define Dprint(cond, args) if (cond) {fprintf args;} else {} -# define DprintQ(cond, args, query, size) if (cond) {\ - fprintf args;\ - __fp_nquery(query, size, stdout);\ - } else {} +#define CHECK_SRVR_ADDR + +#ifdef DEBUG static void - Aerror(file, string, error, address) - FILE *file; - char *string; - int error; - struct sockaddr_in address; + Aerror(const res_state statp, FILE *file, const char *string, int error, + struct sockaddr_in address) { int save = errno; - if (_res.options & RES_DEBUG) { + if ((statp->options & RES_DEBUG) != 0) { + char tmp[sizeof "255.255.255.255"]; + fprintf(file, "res_send: %s ([%s].%u): %s\n", string, - inet_ntoa(address.sin_addr), + inet_ntop(address.sin_family, &address.sin_addr, + tmp, sizeof tmp), ntohs(address.sin_port), strerror(error)); } errno = save; } static void - Perror(file, string, error) - FILE *file; - char *string; - int error; - { + Perror(const res_state statp, FILE *file, const char *string, int error) { int save = errno; - if (_res.options & RES_DEBUG) { + if ((statp->options & RES_DEBUG) != 0) fprintf(file, "res_send: %s: %s\n", string, strerror(error)); - } errno = save; } #endif -void -res_send_setqhook(res_send_qhook hook) { - Qhook = hook; -} - -void -res_send_setrhook(res_send_rhook hook) { - Rhook = hook; -} +static int cmpsock(struct sockaddr_in *a1, struct sockaddr_in *a2); +void res_pquery(const res_state, const u_char *, int, FILE *); /* int * res_isourserver(ina) @@ -176,24 +158,21 @@ res_send_setrhook(res_send_rhook hook) { * paul vixie, 29may94 */ int -res_isourserver(const struct sockaddr_in *inp) { +res_ourserver_p(const res_state statp, const struct sockaddr_in *inp) { struct sockaddr_in ina; - int ns, ret; + int ns; ina = *inp; - ret = 0; - for (ns = 0; ns < _res.nscount; ns++) { - const struct sockaddr_in *srv = &_res.nsaddr_list[ns]; + for (ns = 0; ns < statp->nscount; ns++) { + const struct sockaddr_in *srv = &statp->nsaddr_list[ns]; if (srv->sin_family == ina.sin_family && srv->sin_port == ina.sin_port && (srv->sin_addr.s_addr == INADDR_ANY || - srv->sin_addr.s_addr == ina.sin_addr.s_addr)) { - ret++; - break; - } + srv->sin_addr.s_addr == ina.sin_addr.s_addr)) + return (1); } - return (ret); + return (0); } /* int @@ -227,9 +206,8 @@ res_nameinquery(const char *name, int type, int class, return (-1); ttype = ns_get16(cp); cp += INT16SZ; tclass = ns_get16(cp); cp += INT16SZ; - if (ttype == type && - tclass == class && - strcasecmp(tname, name) == 0) + if (ttype == type && tclass == class && + ns_samename(tname, name) == 1) return (1); } return (0); @@ -285,54 +263,66 @@ res_queriesmatch(const u_char *buf1, const u_char *eom1, } int -res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { +res_nsend(res_state statp, + const u_char *buf, int buflen, u_char *ans, int anssiz) +{ HEADER *hp = (HEADER *) buf; HEADER *anhp = (HEADER *) ans; int gotsomewhere, connreset, terrno, try, v_circuit, resplen, ns, n; u_int badns; /* XXX NSMAX can't exceed #/bits in this variable */ + static int highestFD = FD_SETSIZE - 1; - if ((_res.options & RES_INIT) == 0 && res_init() == -1) { - /* errno should have been set by res_init() in this case. */ - return (-1); - } if (anssiz < HFIXEDSZ) { errno = EINVAL; return (-1); } - DprintQ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY), + DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY), (stdout, ";; res_send()\n"), buf, buflen); - v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; + v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ; gotsomewhere = 0; connreset = 0; terrno = ETIMEDOUT; badns = 0; /* + * Some callers want to even out the load on their resolver list. + */ + if (statp->nscount > 0 && (statp->options & RES_ROTATE) != 0) { + struct sockaddr_in ina; + int lastns = statp->nscount - 1; + + ina = statp->nsaddr_list[0]; + for (ns = 0; ns < lastns; ns++) + statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1]; + statp->nsaddr_list[lastns] = ina; + } + + /* * Send request, RETRY times, or until successful */ - for (try = 0; try < _res.retry; try++) { - for (ns = 0; ns < _res.nscount; ns++) { - struct sockaddr_in *nsap = &_res.nsaddr_list[ns]; + for (try = 0; try < statp->retry; try++) { + for (ns = 0; ns < statp->nscount; ns++) { + struct sockaddr_in *nsap = &statp->nsaddr_list[ns]; same_ns: if (badns & (1 << ns)) { - res_close(); + res_nclose(statp); goto next_ns; } - if (Qhook) { + if (statp->qhook) { int done = 0, loops = 0; do { res_sendhookact act; - act = (*Qhook)(&nsap, &buf, &buflen, - ans, anssiz, &resplen); + act = (*statp->qhook)(&nsap, &buf, &buflen, + ans, anssiz, &resplen); switch (act) { case res_goahead: done = 1; break; case res_nextns: - res_close(); + res_nclose(statp); goto next_ns; case res_done: return (resplen); @@ -349,7 +339,7 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { } while (!done); } - Dprint(_res.options & RES_DEBUG, + Dprint(statp->options & RES_DEBUG, (stdout, ";; Querying server (# %d) address = %s\n", ns + 1, inet_ntoa(nsap->sin_addr))); @@ -359,33 +349,53 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { u_short len; u_char *cp; - /* - * Use virtual circuit; - * at most one attempt per server. - */ - try = _res.retry; + /* Use VC; at most one attempt per server. */ + try = statp->retry; truncated = 0; - if (s < 0 || !vc || hp->opcode == ns_o_update) { - if (s >= 0) - res_close(); - s = socket(PF_INET, SOCK_STREAM, 0); - if (s < 0) { + /* Are we still talking to whom we want to talk to? */ + if (statp->_sock >= 0 && + (statp->_flags & RES_F_VC) != 0) { + struct sockaddr_in peer; + int size = sizeof(peer); + + if (getpeername(statp->_sock, + (struct sockaddr *)&peer, + &size) < 0) { + res_nclose(statp); + statp->_flags &= ~RES_F_VC; + } else if (!cmpsock(&peer, nsap)) { + res_nclose(statp); + statp->_flags &= ~RES_F_VC; + } + } + + if (statp->_sock < 0 || + (statp->_flags & RES_F_VC) == 0) { + if (statp->_sock >= 0) + res_nclose(statp); + + statp->_sock = socket(PF_INET, + SOCK_STREAM, 0); + if (statp->_sock < 0 || + statp->_sock > highestFD) { terrno = errno; - Perror(stderr, "socket(vc)", errno); + Perror(statp, stderr, + "socket(vc)", errno); return (-1); } errno = 0; - if (connect(s, (struct sockaddr *)nsap, + if (connect(statp->_sock, + (struct sockaddr *)nsap, sizeof *nsap) < 0) { terrno = errno; - Aerror(stderr, "connect/vc", + Aerror(statp, stderr, "connect/vc", errno, *nsap); badns |= (1 << ns); - res_close(); + res_nclose(statp); goto next_ns; } - vc = 1; + statp->_flags |= RES_F_VC; } /* * Send length & message @@ -395,11 +405,12 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { iov[0].iov_len = INT16SZ; iov[1].iov_base = (caddr_t)buf; iov[1].iov_len = buflen; - if (writev(s, iov, 2) != (INT16SZ + buflen)) { + if (writev(statp->_sock, iov, 2) != + (INT16SZ + buflen)) { terrno = errno; - Perror(stderr, "write failed", errno); + Perror(statp, stderr, "write failed", errno); badns |= (1 << ns); - res_close(); + res_nclose(statp); goto next_ns; } /* @@ -408,15 +419,16 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { read_len: cp = ans; len = INT16SZ; - while ((n = read(s, (char *)cp, (int)len)) > 0) { + while ((n = read(statp->_sock, + (char *)cp, (int)len)) > 0) { cp += n; if ((len -= n) <= 0) break; } if (n <= 0) { terrno = errno; - Perror(stderr, "read failed", errno); - res_close(); + Perror(statp, stderr, "read failed", errno); + res_nclose(statp); /* * A long running process might get its TCP * connection reset if the remote server was @@ -428,15 +440,15 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { */ if (terrno == ECONNRESET && !connreset) { connreset = 1; - res_close(); + res_nclose(statp); goto same_ns; } - res_close(); + res_nclose(statp); goto next_ns; } resplen = ns_get16(ans); if (resplen > anssiz) { - Dprint(_res.options & RES_DEBUG, + Dprint(statp->options & RES_DEBUG, (stdout, ";; response truncated\n") ); truncated = 1; @@ -447,23 +459,24 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { /* * Undersized message. */ - Dprint(_res.options & RES_DEBUG, + Dprint(statp->options & RES_DEBUG, (stdout, ";; undersized: %d\n", len)); terrno = EMSGSIZE; badns |= (1 << ns); - res_close(); + res_nclose(statp); goto next_ns; } cp = ans; while (len != 0 && - (n = read(s, (char *)cp, (int)len)) > 0) { + (n = read(statp->_sock, (char *)cp, (int)len)) + > 0) { cp += n; len -= n; } if (n <= 0) { terrno = errno; - Perror(stderr, "read(vc)", errno); - res_close(); + Perror(statp, stderr, "read(vc)", errno); + res_nclose(statp); goto next_ns; } if (truncated) { @@ -479,7 +492,8 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { n = (len > sizeof(junk) ? sizeof(junk) : len); - if ((n = read(s, junk, n)) > 0) + n = read(statp->_sock, junk, n); + if (n > 0) len -= n; else break; @@ -493,8 +507,8 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { * wait for the correct one. */ if (hp->id != anhp->id) { - DprintQ((_res.options & RES_DEBUG) || - (_res.pfcode & RES_PRF_REPLY), + DprintQ((statp->options & RES_DEBUG) || + (statp->pfcode & RES_PRF_REPLY), (stdout, ";; old answer (unexpected):\n"), ans, (resplen>anssiz)?anssiz:resplen); goto read_len; @@ -503,24 +517,27 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { /* * Use datagrams. */ - struct timeval timeout; + struct timespec start, timeout, finish; fd_set dsmask; struct sockaddr_in from; - int fromlen; - - if ((s < 0) || vc) { - if (vc) - res_close(); - s = socket(PF_INET, SOCK_DGRAM, 0); - if (s < 0) { + int fromlen, seconds; + + if (statp->_sock < 0 || + (statp->_flags & RES_F_VC) != 0) { + if ((statp->_flags & RES_F_VC) != 0) + res_nclose(statp); + statp->_sock = socket(PF_INET, SOCK_DGRAM, 0); + if (statp->_sock < 0 || + statp->_sock > highestFD) { #ifndef CAN_RECONNECT bad_dg_sock: #endif terrno = errno; - Perror(stderr, "socket(dg)", errno); + Perror(statp, stderr, + "socket(dg)", errno); return (-1); } - connected = 0; + statp->_flags &= ~RES_F_CONN; } #ifndef CANNOT_CONNECT_DGRAM /* @@ -538,28 +555,29 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { * as we wish to receive answers from the first * server to respond. */ - if (_res.nscount == 1 || (try == 0 && ns == 0)) { + if (statp->nscount == 1 || (try == 0 && ns == 0)) { /* * Connect only if we are sure we won't * receive a response from another server. */ - if (!connected) { - if (connect(s, (struct sockaddr *)nsap, - sizeof *nsap - ) < 0) { - Aerror(stderr, + if ((statp->_flags & RES_F_CONN) == 0) { + if (connect(statp->_sock, + (struct sockaddr *)nsap, + sizeof *nsap) < 0) { + Aerror(statp, stderr, "connect(dg)", errno, *nsap); badns |= (1 << ns); - res_close(); + res_nclose(statp); goto next_ns; } - connected = 1; + statp->_flags |= RES_F_CONN; } - if (send(s, (char*)buf, buflen, 0) != buflen) { - Perror(stderr, "send", errno); + if (send(statp->_sock, (char*)buf, buflen, 0) + != buflen) { + Perror(statp, stderr, "send", errno); badns |= (1 << ns); - res_close(); + res_nclose(statp); goto next_ns; } } else { @@ -567,86 +585,115 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { * Disconnect if we want to listen * for responses from more than one server. */ - if (connected) { + if ((statp->_flags & RES_F_CONN) != 0) { #ifdef CAN_RECONNECT struct sockaddr_in no_addr; no_addr.sin_family = AF_INET; no_addr.sin_addr.s_addr = INADDR_ANY; no_addr.sin_port = 0; - (void) connect(s, + (void) connect(statp->_sock, (struct sockaddr *) &no_addr, sizeof no_addr); #else - int s1 = socket(PF_INET, SOCK_DGRAM,0); + struct sockaddr_in local_addr; + int len, result, s1; + + len = sizeof(local_addr); + s1 = socket(PF_INET, SOCK_DGRAM, 0); + result = getsockname(statp->_sock, + (struct sockaddr *)&local_addr, + &len); if (s1 < 0) goto bad_dg_sock; - (void) dup2(s1, s); + (void) dup2(s1, statp->_sock); (void) close(s1); - Dprint(_res.options & RES_DEBUG, + if (result == 0) { + /* + * Attempt to rebind to old + * port. Note connected socket + * has an sin_addr set. + */ + local_addr.sin_addr.s_addr = + htonl(0); + (void)bind(statp->_sock, + (struct sockaddr *) + &local_addr, len); + } + Dprint(statp->options & RES_DEBUG, (stdout, ";; new DG socket\n")) #endif /* CAN_RECONNECT */ - connected = 0; + statp->_flags &= ~RES_F_CONN; errno = 0; } #endif /* !CANNOT_CONNECT_DGRAM */ - if (sendto(s, (char*)buf, buflen, 0, + if (sendto(statp->_sock, + (char*)buf, buflen, 0, (struct sockaddr *)nsap, sizeof *nsap) != buflen) { - Aerror(stderr, "sendto", errno, *nsap); + Aerror(statp, stderr, "sendto", errno, *nsap); badns |= (1 << ns); - res_close(); + res_nclose(statp); goto next_ns; } #ifndef CANNOT_CONNECT_DGRAM } #endif /* !CANNOT_CONNECT_DGRAM */ + if (statp->_sock < 0 || statp->_sock > highestFD) { + Perror(statp, stderr, + "fd out-of-bounds", EMFILE); + res_nclose(statp); + goto next_ns; + } + /* * Wait for reply */ - timeout.tv_sec = (_res.retrans << try); + seconds = (statp->retrans << try); if (try > 0) - timeout.tv_sec /= _res.nscount; - if ((long) timeout.tv_sec <= 0) - timeout.tv_sec = 1; - timeout.tv_usec = 0; + seconds /= statp->nscount; + if (seconds <= 0) + seconds = 1; + start = evNowTime(); + timeout = evConsTime(seconds, 0); + finish = evAddTime(start, timeout); wait: - if (s < 0 || s >= FD_SETSIZE) { - Perror(stderr, "s out-of-bounds", EMFILE); - res_close(); - goto next_ns; - } FD_ZERO(&dsmask); - FD_SET(s, &dsmask); - n = select(s+1, &dsmask, (fd_set *)NULL, - (fd_set *)NULL, &timeout); - if (n < 0) { - if (errno == EINTR) - goto wait; - Perror(stderr, "select", errno); - res_close(); - goto next_ns; - } + FD_SET(statp->_sock, &dsmask); + n = pselect(statp->_sock + 1, + &dsmask, NULL, NULL, + &timeout, NULL); if (n == 0) { - /* - * timeout - */ - Dprint(_res.options & RES_DEBUG, + Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n")); gotsomewhere = 1; - res_close(); + goto next_ns; + } + if (n < 0) { + if (errno == EINTR) { + struct timespec now; + + now = evNowTime(); + if (evCmpTime(finish, now) >= 0) { + timeout = evSubTime(finish, + now); + goto wait; + } + } + Perror(statp, stderr, "select", errno); + res_nclose(statp); goto next_ns; } errno = 0; fromlen = sizeof(struct sockaddr_in); - resplen = recvfrom(s, (char*)ans, anssiz, 0, + resplen = recvfrom(statp->_sock, (char*)ans, anssiz,0, (struct sockaddr *)&from, &fromlen); if (resplen <= 0) { - Perror(stderr, "recvfrom", errno); - res_close(); + Perror(statp, stderr, "recvfrom", errno); + res_nclose(statp); goto next_ns; } gotsomewhere = 1; @@ -654,12 +701,12 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { /* * Undersized message. */ - Dprint(_res.options & RES_DEBUG, + Dprint(statp->options & RES_DEBUG, (stdout, ";; undersized: %d\n", resplen)); terrno = EMSGSIZE; badns |= (1 << ns); - res_close(); + res_nclose(statp); goto next_ns; } if (hp->id != anhp->id) { @@ -668,28 +715,28 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { * XXX - potential security hazard could * be detected here. */ - DprintQ((_res.options & RES_DEBUG) || - (_res.pfcode & RES_PRF_REPLY), + DprintQ((statp->options & RES_DEBUG) || + (statp->pfcode & RES_PRF_REPLY), (stdout, ";; old answer:\n"), ans, (resplen>anssiz)?anssiz:resplen); goto wait; } #ifdef CHECK_SRVR_ADDR - if (!(_res.options & RES_INSECURE1) && - !res_isourserver(&from)) { + if (!(statp->options & RES_INSECURE1) && + !res_ourserver_p(statp, &from)) { /* * response from wrong server? ignore it. * XXX - potential security hazard could * be detected here. */ - DprintQ((_res.options & RES_DEBUG) || - (_res.pfcode & RES_PRF_REPLY), + DprintQ((statp->options & RES_DEBUG) || + (statp->pfcode & RES_PRF_REPLY), (stdout, ";; not our server:\n"), ans, (resplen>anssiz)?anssiz:resplen); goto wait; } #endif - if (!(_res.options & RES_INSECURE2) && + if (!(statp->options & RES_INSECURE2) && !res_queriesmatch(buf, buf + buflen, ans, ans + anssiz)) { /* @@ -697,8 +744,8 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { * XXX - potential security hazard could * be detected here. */ - DprintQ((_res.options & RES_DEBUG) || - (_res.pfcode & RES_PRF_REPLY), + DprintQ((statp->options & RES_DEBUG) || + (statp->pfcode & RES_PRF_REPLY), (stdout, ";; wrong query name:\n"), ans, (resplen>anssiz)?anssiz:resplen); goto wait; @@ -706,33 +753,33 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { if (anhp->rcode == SERVFAIL || anhp->rcode == NOTIMP || anhp->rcode == REFUSED) { - DprintQ(_res.options & RES_DEBUG, + DprintQ(statp->options & RES_DEBUG, (stdout, "server rejected query:\n"), ans, (resplen>anssiz)?anssiz:resplen); badns |= (1 << ns); - res_close(); + res_nclose(statp); /* don't retry if called from dig */ - if (!_res.pfcode) + if (!statp->pfcode) goto next_ns; } - if (!(_res.options & RES_IGNTC) && anhp->tc) { + if (!(statp->options & RES_IGNTC) && anhp->tc) { /* * get rest of answer; * use TCP with same server. */ - Dprint(_res.options & RES_DEBUG, + Dprint(statp->options & RES_DEBUG, (stdout, ";; truncated answer\n")); v_circuit = 1; - res_close(); + res_nclose(statp); goto same_ns; } } /*if vc/dg*/ - Dprint((_res.options & RES_DEBUG) || - ((_res.pfcode & RES_PRF_REPLY) && - (_res.pfcode & RES_PRF_HEAD1)), + Dprint((statp->options & RES_DEBUG) || + ((statp->pfcode & RES_PRF_REPLY) && + (statp->pfcode & RES_PRF_HEAD1)), (stdout, ";; got answer:\n")); - DprintQ((_res.options & RES_DEBUG) || - (_res.pfcode & RES_PRF_REPLY), + DprintQ((statp->options & RES_DEBUG) || + (statp->pfcode & RES_PRF_REPLY), (stdout, ""), ans, (resplen>anssiz)?anssiz:resplen); /* @@ -743,25 +790,25 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { * or if we haven't been asked to keep a socket open, * close the socket. */ - if ((v_circuit && (!(_res.options & RES_USEVC) || ns != 0)) || - !(_res.options & RES_STAYOPEN)) { - res_close(); + if ((v_circuit && (!(statp->options & RES_USEVC) || ns != 0)) || + !(statp->options & RES_STAYOPEN)) { + res_nclose(statp); } - if (Rhook) { + if (statp->rhook) { int done = 0, loops = 0; do { res_sendhookact act; - act = (*Rhook)(nsap, buf, buflen, - ans, anssiz, &resplen); + act = (*statp->rhook)(nsap, buf, buflen, + ans, anssiz, &resplen); switch (act) { case res_goahead: case res_done: done = 1; break; case res_nextns: - res_close(); + res_nclose(statp); goto next_ns; case res_modified: /* give the hook another try */ @@ -780,7 +827,7 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { next_ns: ; } /*foreach ns*/ } /*foreach retry*/ - res_close(); + res_nclose(statp); if (!v_circuit) { if (!gotsomewhere) errno = ECONNREFUSED; /* no nameservers found */ @@ -799,11 +846,45 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { * This routine is not expected to be user visible. */ void -res_close() { - if (s >= 0) { - (void) close(s); - s = -1; - connected = 0; - vc = 0; +res_nclose(res_state statp) { + if (statp->_sock >= 0) { + (void) close(statp->_sock); + statp->_sock = -1; + statp->_flags &= ~(RES_F_VC | RES_F_CONN); } } + +/* Private */ +static int +cmpsock(struct sockaddr_in *a1, struct sockaddr_in *a2) { + return ((a1->sin_family == a2->sin_family) && + (a1->sin_port == a2->sin_port) && + (a1->sin_addr.s_addr == a2->sin_addr.s_addr)); +} + +#ifdef NEED_PSELECT +/* XXX needs to move to the porting library. */ +static int +pselect(int nfds, void *rfds, void *wfds, void *efds, + struct timespec *tsp, + const sigset_t *sigmask) +{ + struct timeval tv, *tvp; + sigset_t sigs; + int n; + + if (tsp) { + tvp = &tv; + tv = evTimeVal(*tsp); + } else + tvp = NULL; + if (sigmask) + sigprocmask(SIG_SETMASK, sigmask, &sigs); + n = select(nfds, rfds, wfds, efds, tvp); + if (sigmask) + sigprocmask(SIG_SETMASK, &sigs, NULL); + if (tsp) + *tsp = evTimeSpec(tv); + return (n); +} +#endif diff --git a/contrib/bind/lib/resolv/res_sendsigned.c b/contrib/bind/lib/resolv/res_sendsigned.c new file mode 100644 index 0000000..efa463c --- /dev/null +++ b/contrib/bind/lib/resolv/res_sendsigned.c @@ -0,0 +1,130 @@ +#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); + 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); + 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); + 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); + return (anslen); +} diff --git a/contrib/bind/lib/resolv/res_update.c b/contrib/bind/lib/resolv/res_update.c index 8e6c448..bb2456e 100644 --- a/contrib/bind/lib/resolv/res_update.c +++ b/contrib/bind/lib/resolv/res_update.c @@ -1,9 +1,9 @@ #if !defined(lint) && !defined(SABER) -static char rcsid[] = "$Id: res_update.c,v 1.14 1998/03/10 22:04:48 halley Exp $"; +static const char rcsid[] = "$Id: res_update.c,v 1.24 1999/10/15 19:49:12 vixie Exp $"; #endif /* not lint */ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 @@ -25,19 +25,27 @@ static char rcsid[] = "$Id: res_update.c,v 1.14 1998/03/10 22:04:48 halley Exp $ */ #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" /* @@ -54,465 +62,166 @@ static char rcsid[] = "$Id: res_update.c,v 1.14 1998/03/10 22:04:48 halley Exp $ * was encountered while updating the reverse zone. */ -#define NSMAX 16 - -struct ns1 { - char nsname[MAXDNAME]; - struct in_addr nsaddr1; -}; - struct zonegrp { - char z_origin[MAXDNAME]; - int16_t z_class; - char z_soardata[MAXDNAME + 5 * INT32SZ]; - struct ns1 z_ns[NSMAX]; - int z_nscount; - ns_updrec * z_rr; - struct zonegrp *z_next; + char z_origin[MAXDNAME]; + ns_class z_class; + struct in_addr z_nsaddrs[MAXNS]; + int z_nscount; + int z_flags; + LIST(ns_updrec) z_rrlist; + LINK(struct zonegrp) z_link; }; +#define ZG_F_ZONESECTADDED 0x0001 -int -res_update(ns_updrec *rrecp_in) { - ns_updrec *rrecp, *tmprrecp; - u_char buf[PACKETSZ], answer[PACKETSZ], packet[2*PACKETSZ]; - char name[MAXDNAME], zname[MAXDNAME], primary[MAXDNAME], - mailaddr[MAXDNAME]; - u_char soardata[2*MAXCDNAME+5*INT32SZ]; - char *dname, *svdname, *cp1, *target; - u_char *cp, *eom; - HEADER *hp = (HEADER *) answer; - struct zonegrp *zptr = NULL, *tmpzptr, *prevzptr, *zgrp_start = NULL; - int i, j, k = 0, n, ancount, nscount, arcount, rcode, rdatasize, - newgroup, done, myzone, seen_before, numzones = 0; - u_int16_t dlen, class, qclass, type, qtype; - u_int32_t ttl; +/* Forward. */ - if ((_res.options & RES_INIT) == 0 && res_init() == -1) { - h_errno = NETDB_INTERNAL; - return (-1); - } +static int nscopy(struct sockaddr_in *, const struct sockaddr_in *, int); +static int nsprom(struct sockaddr_in *, const struct in_addr *, int); +static void dprintf(const char *, ...); - for (rrecp = rrecp_in; rrecp; rrecp = rrecp->r_next) { - dname = rrecp->r_dname; - n = strlen(dname); - if (dname[n-1] == '.') - dname[n-1] = '\0'; - qtype = T_SOA; - qclass = rrecp->r_class; - done = 0; - seen_before = 0; +/* Macros. */ - while (!done && dname) { - if (qtype == T_SOA) { - for (tmpzptr = zgrp_start; - tmpzptr && !seen_before; - tmpzptr = tmpzptr->z_next) { - if (strcasecmp(dname, - tmpzptr->z_origin) == 0 && - tmpzptr->z_class == qclass) - seen_before++; - for (tmprrecp = tmpzptr->z_rr; - tmprrecp && !seen_before; - tmprrecp = tmprrecp->r_grpnext) - if (strcasecmp(dname, tmprrecp->r_dname) == 0 - && tmprrecp->r_class == qclass) { - seen_before++; - break; - } - if (seen_before) { - /* - * Append to the end of - * current group. - */ - for (tmprrecp = tmpzptr->z_rr; - tmprrecp->r_grpnext; - tmprrecp = tmprrecp->r_grpnext) - (void)NULL; - tmprrecp->r_grpnext = rrecp; - rrecp->r_grpnext = NULL; - done = 1; - break; - } - } - } else if (qtype == T_A) { - for (tmpzptr = zgrp_start; - tmpzptr && !done; - tmpzptr = tmpzptr->z_next) - for (i = 0; i < tmpzptr->z_nscount; i++) - if (tmpzptr->z_class == qclass && - strcasecmp(tmpzptr->z_ns[i].nsname, - dname) == 0 && - tmpzptr->z_ns[i].nsaddr1.s_addr != 0) { - zptr->z_ns[k].nsaddr1.s_addr = - tmpzptr->z_ns[i].nsaddr1.s_addr; - done = 1; - break; - } - } - if (done) - break; - n = res_mkquery(QUERY, dname, qclass, qtype, NULL, - 0, NULL, buf, sizeof buf); - if (n <= 0) { - fprintf(stderr, "res_update: mkquery failed\n"); - return (n); - } - n = res_send(buf, n, answer, sizeof answer); - if (n < 0) { - fprintf(stderr, "res_update: send error for %s\n", - rrecp->r_dname); - return (n); - } - if (n < HFIXEDSZ) - return (-1); - ancount = ntohs(hp->ancount); - nscount = ntohs(hp->nscount); - arcount = ntohs(hp->arcount); - rcode = hp->rcode; - cp = answer + HFIXEDSZ; - eom = answer + n; - /* skip the question section */ - n = dn_skipname(cp, eom); - if (n < 0 || cp + n + 2 * INT16SZ > eom) - return (-1); - cp += n + 2 * INT16SZ; +#define DPRINTF(x) do {\ + int save_errno = errno; \ + if ((statp->options & RES_DEBUG) != 0) dprintf x; \ + errno = save_errno; \ + } while (0) - if (qtype == T_SOA) { - if (ancount == 0 && nscount == 0 && arcount == 0) { - /* - * if (rcode == NOERROR) then the dname exists but - * has no soa record associated with it. - * if (rcode == NXDOMAIN) then the dname does not - * exist and the server is replying out of NCACHE. - * in either case, proceed with the next try - */ - dname = strchr(dname, '.'); - if (dname != NULL) - dname++; - continue; - } else if ((rcode == NOERROR || rcode == NXDOMAIN) && - ancount == 0 && - nscount == 1 && arcount == 0) { - /* - * name/data does not exist, soa record supplied in the - * authority section - */ - /* authority section must contain the soa record */ - if ((n = dn_expand(answer, eom, cp, zname, - sizeof zname)) < 0) - return (n); - cp += n; - if (cp + 2 * INT16SZ > eom) - return (-1); - GETSHORT(type, cp); - GETSHORT(class, cp); - if (type != T_SOA || class != qclass) { - fprintf(stderr, "unknown answer\n"); - return (-1); - } - myzone = 0; - svdname = dname; - while (dname) - if (strcasecmp(dname, zname) == 0) { - myzone = 1; - break; - } else if ((dname = strchr(dname, '.')) != NULL) - dname++; - if (!myzone) { - dname = strchr(svdname, '.'); - if (dname != NULL) - dname++; - continue; - } - nscount = 0; - /* fallthrough */ - } else if (rcode == NOERROR && ancount == 1) { - /* - * found the zone name - * new servers will supply NS records for the zone - * in authority section and A records for those - * nameservers in the additional section - * older servers have to be explicitly queried for - * NS records for the zone - */ - /* answer section must contain the soa record */ - if ((n = dn_expand(answer, eom, cp, zname, - sizeof zname)) < 0) - return (n); - else - cp += n; - if (cp + 2 * INT16SZ > eom) - return (-1); - GETSHORT(type, cp); - GETSHORT(class, cp); - if (type == T_CNAME) { - dname = strchr(dname, '.'); - if (dname != NULL) - dname++; - continue; - } - if (strcasecmp(dname, zname) != 0 || - type != T_SOA || - class != rrecp->r_class) { - fprintf(stderr, "unknown answer\n"); - return (-1); - } - /* FALLTHROUGH */ - } else { - fprintf(stderr, - "unknown response: ans=%d, auth=%d, add=%d, rcode=%d\n", - ancount, nscount, arcount, hp->rcode); - return (-1); - } - if (cp + INT32SZ + INT16SZ > eom) - return (-1); - /* continue processing the soa record */ - GETLONG(ttl, cp); - GETSHORT(dlen, cp); - if (cp + dlen > eom) - return (-1); - newgroup = 1; - zptr = zgrp_start; - prevzptr = NULL; - while (zptr) { - if (strcasecmp(zname, zptr->z_origin) == 0 && - type == T_SOA && class == qclass) { - newgroup = 0; - break; - } - prevzptr = zptr; - zptr = zptr->z_next; - } - if (!newgroup) { - for (tmprrecp = zptr->z_rr; - tmprrecp->r_grpnext; - tmprrecp = tmprrecp->r_grpnext) - ; - tmprrecp->r_grpnext = rrecp; - rrecp->r_grpnext = NULL; - done = 1; - cp += dlen; - break; - } else { - if ((n = dn_expand(answer, eom, cp, primary, - sizeof primary)) < 0) - return (n); - cp += n; - /* - * We don't have to bounds check here because the - * next use of 'cp' is in dn_expand(). - */ - cp1 = (char *)soardata; - strcpy(cp1, primary); - cp1 += strlen(cp1) + 1; - if ((n = dn_expand(answer, eom, cp, mailaddr, - sizeof mailaddr)) < 0) - return (n); - cp += n; - strcpy(cp1, mailaddr); - cp1 += strlen(cp1) + 1; - if (cp + 5*INT32SZ > eom) - return (-1); - memcpy(cp1, cp, 5*INT32SZ); - cp += 5*INT32SZ; - cp1 += 5*INT32SZ; - rdatasize = (u_char *)cp1 - soardata; - zptr = calloc(1, sizeof(struct zonegrp)); - if (zptr == NULL) - return (-1); - if (zgrp_start == NULL) - zgrp_start = zptr; - else - prevzptr->z_next = zptr; - zptr->z_rr = rrecp; - rrecp->r_grpnext = NULL; - strcpy(zptr->z_origin, zname); - zptr->z_class = class; - memcpy(zptr->z_soardata, soardata, rdatasize); - /* fallthrough to process NS and A records */ - } - } else if (qtype == T_NS) { - if (rcode == NOERROR && ancount > 0) { - strcpy(zname, dname); - for (zptr = zgrp_start; zptr; zptr = zptr->z_next) { - if (strcasecmp(zname, zptr->z_origin) == 0) - break; - } - if (zptr == NULL) - /* should not happen */ - return (-1); - if (nscount > 0) { - /* - * answer and authority sections contain - * the same information, skip answer section - */ - for (j = 0; j < ancount; j++) { - n = dn_skipname(cp, eom); - if (n < 0) - return (-1); - n += 2*INT16SZ + INT32SZ; - if (cp + n + INT16SZ > eom) - return (-1); - cp += n; - GETSHORT(dlen, cp); - cp += dlen; - } - } else - nscount = ancount; - /* fallthrough to process NS and A records */ - } else { - fprintf(stderr, "cannot determine nameservers for %s:\ -ans=%d, auth=%d, add=%d, rcode=%d\n", - dname, ancount, nscount, arcount, hp->rcode); - return (-1); - } - } else if (qtype == T_A) { - if (rcode == NOERROR && ancount > 0) { - arcount = ancount; - ancount = nscount = 0; - /* fallthrough to process A records */ - } else { - fprintf(stderr, "cannot determine address for %s:\ -ans=%d, auth=%d, add=%d, rcode=%d\n", - dname, ancount, nscount, arcount, hp->rcode); - return (-1); - } - } - /* process NS records for the zone */ - j = 0; - for (i = 0; i < nscount; i++) { - if ((n = dn_expand(answer, eom, cp, name, - sizeof name)) < 0) - return (n); - cp += n; - if (cp + 3 * INT16SZ + INT32SZ > eom) - return (-1); - GETSHORT(type, cp); - GETSHORT(class, cp); - GETLONG(ttl, cp); - GETSHORT(dlen, cp); - if (cp + dlen > eom) - return (-1); - if (strcasecmp(name, zname) == 0 && - type == T_NS && class == qclass) { - if ((n = dn_expand(answer, eom, cp, - name, sizeof name)) < 0) - return (n); - target = zptr->z_ns[j++].nsname; - strcpy(target, name); - } - cp += dlen; +/* 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; + struct sockaddr_in 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)) { + /* 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, + tgrp.z_nsaddrs, MAXNS); + if (tgrp.z_nscount <= 0) { + DPRINTF(("res_findzonecut failed (%d)", + tgrp.z_nscount)); + goto done; } - if (zptr->z_nscount == 0) - zptr->z_nscount = j; - /* get addresses for the nameservers */ - for (i = 0; i < arcount; i++) { - if ((n = dn_expand(answer, eom, cp, name, - sizeof name)) < 0) - return (n); - cp += n; - if (cp + 3 * INT16SZ + INT32SZ > eom) - return (-1); - GETSHORT(type, cp); - GETSHORT(class, cp); - GETLONG(ttl, cp); - GETSHORT(dlen, cp); - if (cp + dlen > eom) - return (-1); - if (type == T_A && dlen == INT32SZ && class == qclass) { - for (j = 0; j < zptr->z_nscount; j++) - if (strcasecmp(name, zptr->z_ns[j].nsname) == 0) { - memcpy(&zptr->z_ns[j].nsaddr1.s_addr, cp, - INT32SZ); + /* 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; - } - } - cp += dlen; - } - if (zptr->z_nscount == 0) { - dname = zname; - qtype = T_NS; - continue; + /* 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_LIST(zptr->z_rrlist); + APPEND(zgrps, zptr, z_link); } - done = 1; - for (k = 0; k < zptr->z_nscount; k++) - if (zptr->z_ns[k].nsaddr1.s_addr == 0) { - done = 0; - dname = zptr->z_ns[k].nsname; - qtype = T_A; - } - - } /* while */ + /* Thread this rrecp onto the right group. */ + APPEND(zptr->z_rrlist, rrecp, r_glink); } - _res.options |= RES_DEBUG; - for (zptr = zgrp_start; zptr; zptr = zptr->z_next) { - - /* append zone section */ + 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) { - fprintf(stderr, "saverrec error\n"); - fflush(stderr); - return (-1); + DPRINTF(("res_mkupdrec failed")); + goto done; } - rrecp->r_grpnext = zptr->z_rr; - zptr->z_rr = rrecp; - - n = res_mkupdate(zptr->z_rr, packet, sizeof packet); + 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->nsaddr_list, statp->nscount); + statp->nscount = nsprom(statp->nsaddr_list, + 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) { - fprintf(stderr, "res_mkupdate error\n"); - fflush(stderr); - return (-1); - } else - fprintf(stdout, "res_mkupdate: packet size = %d\n", n); - - /* - * Override the list of NS records from res_init() with - * the authoritative nameservers for the zone being updated. - * Sort primary to be the first in the list of nameservers. - */ - for (i = 0; i < zptr->z_nscount; i++) { - if (strcasecmp(zptr->z_ns[i].nsname, - zptr->z_soardata) == 0) { - struct in_addr tmpaddr; - - if (i != 0) { - strcpy(zptr->z_ns[i].nsname, - zptr->z_ns[0].nsname); - strcpy(zptr->z_ns[0].nsname, - zptr->z_soardata); - tmpaddr = zptr->z_ns[i].nsaddr1; - zptr->z_ns[i].nsaddr1 = - zptr->z_ns[0].nsaddr1; - zptr->z_ns[0].nsaddr1 = tmpaddr; - } - break; - } - } - for (i = 0; i < MAXNS; i++) { - _res.nsaddr_list[i].sin_addr = zptr->z_ns[i].nsaddr1; - _res.nsaddr_list[i].sin_family = AF_INET; - _res.nsaddr_list[i].sin_port = htons(NAMESERVER_PORT); + DPRINTF(("res_nsend: send error, n=%d (%s)\n", + n, strerror(errno))); + goto done; } - _res.nscount = (zptr->z_nscount < MAXNS) ? - zptr->z_nscount : MAXNS; - n = res_send(packet, n, answer, sizeof(answer)); - if (n < 0) { - fprintf(stderr, "res_send: send error, n=%d\n", n); - break; - } else - numzones++; + if (((HEADER *)answer)->rcode == NOERROR) + nzones++; + + /* Restore resolver's nameserver set. */ + statp->nscount = nscopy(statp->nsaddr_list, 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->nsaddr_list, nsaddrs, nscount); + + return (nzones); +} + +/* Private. */ - /* free malloc'ed memory */ - while(zgrp_start) { - zptr = zgrp_start; - zgrp_start = zgrp_start->z_next; - res_freeupdrec(zptr->z_rr); /* Zone section we allocated. */ - free((char *)zptr); +static int +nscopy(struct sockaddr_in *dst, const struct sockaddr_in *src, int n) { + int i; + + for (i = 0; i < n; i++) + dst[i] = src[i]; + return (n); +} + +static int +nsprom(struct sockaddr_in *dst, const struct in_addr *src, int n) { + int i; + + for (i = 0; i < n; i++) { + memset(&dst[i], 0, sizeof dst[i]); + dst[i].sin_family = AF_INET; + dst[i].sin_port = htons(NS_DEFAULTPORT); + dst[i].sin_addr = src[i]; } + return (n); +} + +static void +dprintf(const char *fmt, ...) { + va_list ap; - return (numzones); + va_start(ap, fmt); + fputs(";; res_nupdate: ", stderr); + vfprintf(stderr, fmt, ap); + fputc('\n', stderr); + va_end(ap); } diff --git a/contrib/bind/port/Makefile b/contrib/bind/port/Makefile index 803ba0d..af7f797 100644 --- a/contrib/bind/port/Makefile +++ b/contrib/bind/port/Makefile @@ -1,4 +1,4 @@ -# Copyright (c) 1996 by Internet Software Consortium +# 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 @@ -13,7 +13,7 @@ # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS # SOFTWARE. -# $Id: Makefile,v 8.12 1997/06/19 03:22:17 halley Exp $ +# $Id: Makefile,v 8.15 1999/08/08 17:13:24 vixie Exp $ # these are only appropriate for BSD 4.4 or derivatives, and are used in # development. normal builds will be done in the top level directory and @@ -30,7 +30,7 @@ INCL= ${TOP}/include PORTINCL= ${TOP}/port/${SYSTYPE}/include LIBBIND= ${TOP}/lib/libbind.${A} RANLIB= ranlib -AR= ar cruv +AR= ar cru INSTALL= install CDEBUG= -g @@ -39,7 +39,7 @@ SUBDIRS = bsdos decunix linux netbsd sunos ultrix MARGS = "SYSTYPE=${SYSTYPE}" "SHELL=${SHELL}" "A=${A}" "O=${O}" \ "CC=${CC}" "LEX=${LEX}" "CDEBUG=${CDEBUG}" \ "SYSLIBS=${SYSLIBS}" "LDFLAGS=${LDFLAGS}" \ - "DESTDIR=${DESTDIR}" "PIDDIR=${PIDDIR}" "DESTMAN=${DESTMAN}" \ + "DESTDIR=${DESTDIR}" "DESTMAN=${DESTMAN}" \ "DESTBIN=${DESTBIN}" "DESTSBIN=${DESTSBIN}" "DESTEXEC=${DESTEXEC}" \ "DESTLIB=${DESTLIB}" "DESTINC=${DESTINC}" "DESTHELP=${DESTHELP}" \ "RANLIB=${RANLIB}" "AR=${AR}" "ARPREF=${ARPREF}" "ARSUFF=${ARSUFF}" \ diff --git a/contrib/bind/port/freebsd/Makefile b/contrib/bind/port/freebsd/Makefile index 966cd56..2f5b121 100644 --- a/contrib/bind/port/freebsd/Makefile +++ b/contrib/bind/port/freebsd/Makefile @@ -1,4 +1,4 @@ -# Copyright (c) 1996 by Internet Software Consortium +# 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 @@ -13,7 +13,7 @@ # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS # SOFTWARE. -# $Id: Makefile,v 1.6 1997/06/19 03:22:25 halley Exp $ +# $Id: Makefile,v 1.8 1999/02/22 02:48:01 vixie Exp $ # these are only appropriate for BSD 4.4 or derivatives, and are used in # development. normal builds will be done in the top level directory and @@ -33,7 +33,7 @@ PORTINCL = ${TOP}/port/${SYSTYPE}/include LIBBIND = ${TOP}/lib/libbind.${A} CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL} LD_LIBFLAGS= -x -r -AR= ar cruv +AR= ar cru RANLIB= ranlib INSTALL= install diff --git a/contrib/bind/port/freebsd/bin/probe_ipv6 b/contrib/bind/port/freebsd/bin/probe_ipv6 new file mode 100755 index 0000000..ba7135d --- /dev/null +++ b/contrib/bind/port/freebsd/bin/probe_ipv6 @@ -0,0 +1,55 @@ +#!/bin/sh + +set -e +PATH=/bin:/usr/bin:$PATH; export PATH +trap "rm -f tmp$$a.c tmp$$b.c tmp$$a.o tmp$$b.o" 0 +target=port_ipv6 +new=new_${target}.h +old=${target}.h + +cat > tmp$$a.c <<EOF +#include <sys/types.h> +#include <netinet/in.h> +struct sockaddr_in6 xx; +EOF + +cat > tmp$$b.c <<EOF +#include <sys/types.h> +#include <netinet/in.h> +struct in6_addr xx; +EOF + +cat > ${new} <<EOF + +/* This file is automatically generated. Do Not Edit. */ + +#ifndef ${target}_h +#define ${target}_h + +EOF + +if ${CC} -c tmp$$a.c > /dev/null 2>&1 +then + echo "#define HAS_INET6_STRUCTS" >> ${new} + if ${CC} -c tmp$$b.c > /dev/null 2>&1 + then + : + else + echo "#define in6_addr in_addr6" >> ${new} + fi +else + echo "#undef HAS_INET6_STRUCTS" >> ${new} +fi +echo >> ${new} +echo "#endif" >> ${new} +if [ -f ${old} ]; then + if cmp -s ${new} ${old} ; then + rm -f ${new} + else + rm -f ${old} + mv ${new} ${old} + fi +else + mv ${new} ${old} +fi +exit 0 diff --git a/contrib/bind/port/freebsd/include/Makefile b/contrib/bind/port/freebsd/include/Makefile index dd8b4e9..40fe3f8 100644 --- a/contrib/bind/port/freebsd/include/Makefile +++ b/contrib/bind/port/freebsd/include/Makefile @@ -65,10 +65,14 @@ all depend clean distclean install:: (cd $$x; pwd; ${MAKE} ${MARGS} $@); \ done +all depend:: + probe_ipv6 + distclean:: clean clean:: rm -f *~ *.BAK *.CKP *.orig + rm -f port_ipv6.h new_port_ipv6.h links: FRC @set -e; ln -s SRC/*.h . diff --git a/contrib/bind/port/freebsd/include/port_after.h b/contrib/bind/port/freebsd/include/port_after.h index 20c92b5..a496ac5 100644 --- a/contrib/bind/port/freebsd/include/port_after.h +++ b/contrib/bind/port/freebsd/include/port_after.h @@ -1,3 +1,5 @@ +#ifndef PORT_AFTER_H +#define PORT_AFTER_H #define CAN_RECONNECT #define USE_POSIX #define POSIX_SIGNALS @@ -11,6 +13,7 @@ #define USE_LOG_CONS #define HAVE_CHROOT #define CAN_CHANGE_ID +#define MISSING_IN6ADDR_ANY #define _TIMEZONE timezone @@ -21,6 +24,13 @@ #define KMEM "/dev/kmem" #define UDPSUM "udpcksum" +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/param.h> +#if (!defined(BSD)) || (BSD < 199306) +#include <sys/bitypes.h> +#endif + /* * We need to know the IPv6 address family number even on IPv4-only systems. * Note that this is NOT a protocol constant, and that if the system has its @@ -31,4 +41,35 @@ */ #ifndef AF_INET6 #define AF_INET6 24 +#else +#define HAS_INET6_STRUCTS +#define HAVE_SA_LEN +#endif + +#ifndef PF_INET6 +#define PF_INET6 AF_INET6 +#endif + +#include <port_ipv6.h> + +#ifndef HAS_INET6_STRUCTS +/* Replace with structure from later rev of O/S if known. */ +struct in6_addr { + u_int8_t s6_addr[16]; +}; + +/* Replace with structure from later rev of O/S if known. */ +struct sockaddr_in6 { +#ifdef HAVE_SA_LEN + u_int8_t sin6_len; /* length of this struct */ + u_int8_t sin6_family; /* AF_INET6 */ +#else + u_int16_t sin6_family; /* AF_INET6 */ #endif + u_int16_t sin6_port; /* transport layer port # */ + u_int32_t sin6_flowinfo; /* IPv6 flow information */ + struct in6_addr sin6_addr; /* IPv6 address */ + u_int32_t sin6_scope_id; /* set of interfaces for a scope */ +}; +#endif /* HAS_INET6_STRUCTS */ +#endif /* ! PORT_AFTER_H */ diff --git a/contrib/bind/port/freebsd/include/port_before.h b/contrib/bind/port/freebsd/include/port_before.h index bc6b89c..d713050 100644 --- a/contrib/bind/port/freebsd/include/port_before.h +++ b/contrib/bind/port/freebsd/include/port_before.h @@ -4,3 +4,11 @@ #define SIG_FN void #define ts_sec tv_sec #define ts_nsec tv_nsec + +#if defined(HAS_PTHREADS) && defined(_REENTRANT) +#define DO_PTHREADS +#endif + +#if defined (__FreeBSD__) && __FreeBSD__>=3 +#define SETPWENT_VOID +#endif diff --git a/contrib/bind/port/freebsd/include/prand_conf.h b/contrib/bind/port/freebsd/include/prand_conf.h new file mode 100644 index 0000000..7244282 --- /dev/null +++ b/contrib/bind/port/freebsd/include/prand_conf.h @@ -0,0 +1,43 @@ +#ifndef _PRAND_CMD_H_ +#define _PRAND_CMD_H_ + + +#ifndef HAVE_DEV_RANDOM + # define HAVE_DEV_RANDOM 1 + #endif /* HAVE_DEV_RANDOM */ + +const char *cmds[] = { + "/bin/ps -axlw 2>&1", + "/usr/sbin/arp -an 2>&1", + "/usr/bin/netstat -an 2>&1", + "/bin/df 2>&1", + "/usr/bin/dig com. soa +ti=1 +retry=0 2>&1", + "/usr/bin/netstat -an 2>&1", + "/usr/bin/dig . soa +ti=1 +retry=0 2>&1", + "/usr/sbin/iostat 2>&1", + "/usr/bin/vmstat 2>&1", + "/usr/bin/w 2>&1", + NULL +}; + +const char *dirs[] = { + "/tmp", + "/usr/tmp", + ".", + "/", + "/var/spool", + "/dev", + "/var/mail", + "/home", + "/usr/home", + NULL +}; + +const char *files[] = { + "/var/log/messages", + "/var/log/wtmp", + "/var/log/lastlog", + NULL +}; + +#endif /* _PRAND_CMD_H_ */ diff --git a/contrib/bind/port/freebsd/include/sys/bitypes.h b/contrib/bind/port/freebsd/include/sys/bitypes.h index ad0dfcb..361156a 100644 --- a/contrib/bind/port/freebsd/include/sys/bitypes.h +++ b/contrib/bind/port/freebsd/include/sys/bitypes.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * 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 diff --git a/contrib/bind/port/prand_conf/Makefile b/contrib/bind/port/prand_conf/Makefile new file mode 100644 index 0000000..d8a1fdc --- /dev/null +++ b/contrib/bind/port/prand_conf/Makefile @@ -0,0 +1,100 @@ +# ++Copyright++ +# - +# Copyright (c) +# 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-- + +SUBDIRS = +# Ensure that HFILES isn't empty to keep bash happy +HFILES = + +DESTDIR= +DESTINC= /usr/local/bind/include +INSTALL= install +SYSTYPE= unknown + +MARGS= DESTDIR="${DESTDIR}" DESTINC="${DESTINC}" INSTALL="${INSTALL}" + +all depend clean distclean install:: + @for x in ${SUBDIRS}; do \ + (cd $$x; pwd; ${MAKE} ${MARGS} $@); \ + done + +prand_conf.h: prand_conf.c + $(CC) prand_conf.c -o prand_conf + ./prand_conf + rm -f prand_conf + cp prand_conf.h prand_conf.h.${SYSTYPE} +distclean:: clean + +clean:: + rm -f *~ *.BAK *.CKP *.orig *.h a.out + +links: FRC + @set -e; ln -s SRC/*.h . + @set -e; for x in ${SUBDIRS}; do \ + ( mkdir $$x; cd $$x; pwd; ln -s ../SRC/$$x SRC; \ + cp SRC/Makefile Makefile; chmod +w Makefile; \ + ${MAKE} ${MARGS} links ); \ + done + +install:: ${DESTDIR}${DESTINC} + -for x in ${HFILES}; do \ + if [ -f "$$x" ]; then \ + ${INSTALL} -c -m 444 $$x ${DESTDIR}${DESTINC}/$$x; \ + fi; \ + done + +${DESTDIR}${DESTINC}: + mkdir -p ${DESTDIR}${DESTINC} + +FRC: + + diff --git a/contrib/bind/port/prand_conf/README b/contrib/bind/port/prand_conf/README new file mode 100644 index 0000000..5f7728d --- /dev/null +++ b/contrib/bind/port/prand_conf/README @@ -0,0 +1,8 @@ +this is a utility used to build prand_conf.h on new ports. + +To run you can either compile the program prand_conf.c with +cc prand_conf.c -o prand_conf # add -posix on NeXTstep systems +./prand_conf + +both programs create a file prand_conf.h, +copy this file to the appropriate port/<os>/include directory diff --git a/contrib/bind/port/prand_conf/prand_conf.c b/contrib/bind/port/prand_conf/prand_conf.c new file mode 100644 index 0000000..5f9bf29 --- /dev/null +++ b/contrib/bind/port/prand_conf/prand_conf.c @@ -0,0 +1,217 @@ +/* $Id: prand_conf.c,v 1.5 1999/07/31 16:44:13 cyarnell 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 + +int +my_find(char *cmd, char **dir) +{ + 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 + */ +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 + */ +int +ex(FILE *fd, char *path, char *cmd, 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 + */ + char *arp_path[] = {"/usr/sbin", "/sbin", "/usr/etc/", "/etc/", + "/usr/bin/", NULL}; + char *ps_path[] = {"/usr/bin", "/bin/", NULL}; + char *net_path[] = {"/usr/ucb/", "/usr/bin/", "/usr/etc/", + "/usr/sbin/", "/bin/", NULL}; + char *dig_path[] = {"/usr/bin/", "/usr/local/bin/", NULL}; + char **df_path = ps_path; + char *uptime_path[] = {"/usr/ucb/", "/usr/bin/", "/usr/bsd/", NULL}; + char *iostat_path[] = { "/usr/bin/", "/bin/", "/usr/sbin/", NULL}; + char *vmstat_path[] = {"/usr/ucb/", "/usr/bin/", "/usr/sbin/", NULL}; + char *vm_stat_path[] = {"/usr/ucb/", "/usr/bin/", NULL}; + char **w_path = uptime_path; + +/* find which directories exist */ + 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}; + + char *files[] = {"/proc/stat", "/proc/rtc", "/proc/meminfo", + "/proc/interrupts", "/proc/self/status", + "/proc/self/maps", + "/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, "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, "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, "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/contrib/bind/port/settings b/contrib/bind/port/settings index 942236e..539faf2 100755 --- a/contrib/bind/port/settings +++ b/contrib/bind/port/settings @@ -18,6 +18,10 @@ case $cachefile in *) echo "Making $cachefile" >&2 ;; esac +# expr is sensitive to LC_COLLATE settings. We want 'C'. +LC_COLLATE=C +export LC_COLLATE + result='' while read setting; do var=`expr "$setting" : "'\([A-Z0-9_]*\)="` diff --git a/contrib/bind/port/systype b/contrib/bind/port/systype index b022651..56d5e26 100755 --- a/contrib/bind/port/systype +++ b/contrib/bind/port/systype @@ -12,7 +12,7 @@ case $cachefile in *) cachefile=`pwd`/$cachefile ;; esac -cd `dirname $0` +cd `dirname $0` > /dev/null for systype in [a-z]*; do if [ -f $systype/probe ]; then if sh $systype/probe; then diff --git a/contrib/bind/tests/irs_testclient.c b/contrib/bind/tests/irs_testclient.c new file mode 100644 index 0000000..419f137 --- /dev/null +++ b/contrib/bind/tests/irs_testclient.c @@ -0,0 +1,8 @@ +#include <isc/ctl.h> +#include <isc/eventlib.h> + +main (int argc, char **argv) { + evContext ctx ; + + +} diff --git a/contrib/bind/tests/irs_testirpd.c b/contrib/bind/tests/irs_testirpd.c new file mode 100644 index 0000000..2b5a3c4 --- /dev/null +++ b/contrib/bind/tests/irs_testirpd.c @@ -0,0 +1,366 @@ +#include <stdio.h> +#include <unistd.h> +#include <pwd.h> +#include <irp.h> +#include <grp.h> +#include <netdb.h> +#include <arpa/inet.h> +#include <sys/socket.h> + +#include <irp.h> +#include <irs.h> +#include <isc/irpmarshall.h> + +void print_passwd(const char *name, struct passwd *pw, FILE *fp); +void print_group(const char *name, struct group *gr, FILE *fp); +void print_servent(const char *name, struct servent *sv, FILE *fp); +void print_host(const char *name, struct hostent *ho, FILE *fp); +void print_netent(const char *name, struct netent *ne, FILE *fp); +void print_proto(const char *name, struct protoent *pr, FILE *fp); + +int +main(int argc, char **argv) { + struct passwd *pw; + struct group *gr; + struct servent *sv; + struct hostent *ho; + struct netent *ne; + struct protoent *pr; + int ch ; + char *groupname = NULL; + + while ((ch = getopt(argc, argv, "u:s:p:g:h:n:g:a:z:")) != -1) { + switch (ch) { + case 'u': + if (strlen (optarg) == 0) { + do { + pw = getpwent(); + print_passwd(optarg, pw, stdout); + printf("\n\n"); + } while (pw != NULL); + sleep(1); + setpwent(); + do { + pw = getpwent(); + print_passwd(optarg, pw, stdout); + printf("\n\n"); + } while (pw != NULL); + sleep(1); + } else { + if (strspn(optarg, "0123456789") == + strlen(optarg)) + pw = getpwuid(atoi(optarg)); + else + pw = getpwnam(optarg); + print_passwd(optarg, pw, stdout); + } + + break; + + case 'g': + if (strlen (optarg) == 0) { + do { + gr = getgrent(); + print_group(optarg, gr, stdout); + printf("\n\n"); + } while (gr != NULL); + sleep(1); + setgrent(); + do { + gr = getgrent(); + print_group(optarg, gr, stdout); + printf("\n\n"); + } while (gr != NULL); + sleep(1); + } else { + if (strspn(optarg, "0123456789") == + strlen(optarg)) + gr = getgrgid(atoi(optarg)); + else + gr = getgrnam(optarg); + print_group(optarg, gr, stdout); + } + break; + + case 's': + if (strlen (optarg) == 0) { + do { + sv = getservent(); + print_servent(optarg, sv, stdout); + printf("\n\n"); + } while (sv != NULL); + sleep(1); + setservent(1); + do { + sv = getservent(); + print_servent(optarg, sv, stdout); + printf("\n\n"); + } while (sv != NULL); + sleep(1); + } else { + if (strspn(optarg, "0123456789") == + strlen(optarg)) + sv = getservbyport(htons(atoi(optarg)), + "tcp"); + else + sv = getservbyname(optarg,"tcp"); + print_servent(optarg, sv, stdout); + } + break; + + case 'h': + if (strlen (optarg) == 0) { + do { + ho = gethostent(); + print_host(optarg, ho, stdout); + printf("\n\n"); + } while (ho != NULL); + sleep(1); + sethostent(1); + do { + ho = gethostent(); + print_host(optarg, ho, stdout); + printf("\n\n"); + } while (ho != NULL); + sleep(1); + } else { + if (strspn(optarg, "0123456789.") == + strlen(optarg)) { + long naddr; + inet_pton(AF_INET, optarg, &naddr); + ho = gethostbyaddr((const char *) + &naddr, + sizeof naddr, + AF_INET); + } else + ho = gethostbyname(optarg); + print_host(optarg, ho, stdout); + } + break; + + case 'n': + if (strlen (optarg) == 0) { + do { + ne = getnetent(); + print_netent(optarg, ne, stdout); + printf("\n\n"); + } while (ne != NULL); + sleep(1); + setnetent(1); + do { + ne = getnetent(); + print_netent(optarg, ne, stdout); + printf("\n\n"); + } while (ne != NULL); + sleep(1); + } else { + if (strspn(optarg, "0123456789./") == + strlen(optarg)) { + long naddr; + inet_pton(AF_INET, optarg, &naddr); + ne = getnetbyaddr(naddr, AF_INET); + } else + ne = getnetbyname(optarg); + print_netent(optarg, ne, stdout); + } + break; + + case 'p': + if (strlen (optarg) == 0) { + do { + pr = getprotoent(); + print_proto(optarg, pr, stdout); + printf("\n\n"); + } while (pr != NULL); + sleep(1); + setprotoent(1); + do { + pr = getprotoent(); + print_proto(optarg, pr, stdout); + printf("\n\n"); + } while (pr != NULL); + sleep(1); + } else { + if (strspn(optarg, "0123456789") == + strlen(optarg)) + pr = getprotobynumber(atoi(optarg)); + else + pr = getprotobyname(optarg); + print_proto(optarg, pr, stdout); + } + + break; + + case 'z': { + char *host, *user, *domain ; + + groupname = optarg; + setnetgrent(groupname); + while (getnetgrent(&host,&user,&domain) == 1) { + fprintf(stdout, "++++\n"); + fprintf(stdout, "Host: \"%s\"\n", + (host == NULL ? "(null)" : host)); + fprintf(stdout, "User: \"%s\"\n", + (user == NULL ? "(null)" : user)); + fprintf(stdout, "Domain: \"%s\"\n", + (domain == NULL ? "(null)" : domain)); + fprintf(stdout, "----\n\n"); + } + break; + } + + default: + printf("Huh?\n"); + exit (1); + } + } + return (0); +} + +void +print_passwd(const char *name, struct passwd *pw, FILE *fp) { + if (pw == NULL) { + fprintf(fp, "%s -- NONE\n",name) ; + return ; + } + + fprintf(fp, "++++\n"); + fprintf(fp, "Name: \"%s\"\n", pw->pw_name); + fprintf(fp, "Uid: %d\n", pw->pw_uid); + fprintf(fp, "Gid: %d\n", pw->pw_gid); + fprintf(fp, "Password: \"%s\"\n", pw->pw_passwd); + fprintf(fp, "Change: %s", ctime(&pw->pw_change)); + fprintf(fp, "Class: \"%s\"\n", pw->pw_class); + fprintf(fp, "Gecos: \"%s\"\n", pw->pw_gecos); + fprintf(fp, "Dir: \"%s\"\n", pw->pw_dir); + fprintf(fp, "Shell: \"%s\"\n", pw->pw_shell); + fprintf(fp, "Expire: %s", ctime(&pw->pw_expire)); + fprintf(fp, "----\n"); +} + + + +void print_group(const char *name, struct group *gr, FILE *fp) { + char **p ; + + if (gr == NULL) { + fprintf(fp, "%s -- NONE\n", name); + return; + } + + fprintf(fp, "++++\n"); + fprintf(fp, "Name: \"%s\"\n", gr->gr_name); + fprintf(fp, "Password: \"%s\"\n", gr->gr_passwd); + fprintf(fp, "Gid: %d\n", gr->gr_gid); + fprintf(fp, "Members:\n") ; + for (p = gr->gr_mem ; p != NULL && *p != NULL ; p++) { + fprintf(fp, "\t\t%s\n",*p); + } + fprintf(fp, "----\n"); +} + + + +void print_servent(const char *name, struct servent *sv, FILE *fp) { + char **p ; + + if (sv == NULL) { + fprintf(fp, "%s -- NONE\n", name); + return; + } + + fprintf(fp, "++++\n"); + fprintf(fp, "Name: \"%s\"\n", sv->s_name); + fprintf(fp, "Aliases:\n") ; + for (p = sv->s_aliases ; p != NULL && *p != NULL ; p++) { + fprintf(fp, "\t\t%s\n",*p); + } + + fprintf(fp, "Port: %d\n", ntohs((short)sv->s_port)); + fprintf(fp, "Protocol: \"%s\"\n", sv->s_proto); + fprintf(fp, "----\n"); +} + + +void print_host(const char *name, struct hostent *ho, FILE *fp) { + char **p ; + char addr[24]; + + if (ho == NULL) { + fprintf(fp, "%s -- NONE\n", name); + return; + } + + fprintf(fp, "++++\n"); + fprintf(fp, "Name: \"%s\"\n", ho->h_name); + fprintf(fp, "Aliases:\n") ; + for (p = ho->h_aliases ; p != NULL && *p != NULL ; p++) { + fprintf(fp, "\t\t%s\n",*p); + } + + + fprintf(fp, "Address Type: %s\n", ADDR_T_STR(ho->h_addrtype)); + fprintf(fp, "Addresses:\n"); + for (p = ho->h_addr_list ; p != NULL && *p ; p++) { + addr[0] = '\0'; + inet_ntop(ho->h_addrtype, *p, addr, sizeof addr); + fprintf(fp, "\t\t%s\n",addr); + } + fprintf(fp, "----\n"); +} + + +void print_netent(const char *name, struct netent *ne, FILE *fp) { + char **p ; + char addr[24]; + long taddr; + + if (ne == NULL) { + fprintf(fp, "%s -- NONE\n", name); + return; + } + + fprintf(fp, "++++\n"); + fprintf(fp, "Name: \"%s\"\n", ne->n_name); + fprintf(fp, "Aliases:\n") ; + for (p = ne->n_aliases ; p != NULL && *p != NULL ; p++) { + fprintf(fp, "\t\t%s\n",*p); + } + + + fprintf(fp, "Address Type: %s\n", ADDR_T_STR(ne->n_addrtype)); + taddr = htonl(ne->n_net); + inet_ntop(ne->n_addrtype, &taddr, addr, sizeof addr); + fprintf(fp, "Net number: %s\n", addr); + fprintf(fp, "----\n"); +} + + +void print_proto(const char *name, struct protoent *pr, FILE *fp) { + char **p ; + char addr[24]; + long taddr; + + if (pr == NULL) { + fprintf(fp, "%s -- NONE\n", name); + return; + } + + fprintf(fp, "++++\n"); + fprintf(fp, "Name: \"%s\"\n", pr->p_name); + fprintf(fp, "Aliases:\n") ; + for (p = pr->p_aliases ; p != NULL && *p != NULL ; p++) { + fprintf(fp, "\t\t%s\n",*p); + } + + + fprintf(fp, "Protocol Number: %d\n", pr->p_proto); + fprintf(fp, "----\n"); +} + +/* + Local Variables: + compile-command: "gcc -g -I../../include -L.. -o testirpd testirpd.c ../libbind.a" + End: +*/ + diff --git a/contrib/bind/tests/irs_testserver.c b/contrib/bind/tests/irs_testserver.c new file mode 100644 index 0000000..e7ee2b9 --- /dev/null +++ b/contrib/bind/tests/irs_testserver.c @@ -0,0 +1,28 @@ +#include <stdio.h> +#include <stdarg.h> +#include <isc/ctl.h> +#include <isc/eventlib.h> + +struct ctl_verb verbs[]; + +static void +logger(enum ctl_severity sev, const char *fmt, ...) { + va_list ap ; + + va_start (ap, fmt) ; + fprintf (stderr, "logger: "); + vfprintf (stderr, fmt, ap) ; + va_end (ap) ; +} + + +main (int argc, char **argv) { + evContext ctx ; + struct sockaddr addr ; + struct ctl_sctx *sctx ; + + + sctx = ctl_server(ctx, &addr, verbs, 666, "Go away peon!", 222, + 333, 10, 5, 6, logger); + +} diff --git a/contrib/bind/tests/test_cidr.c b/contrib/bind/tests/test_cidr.c new file mode 100644 index 0000000..f4845f0 --- /dev/null +++ b/contrib/bind/tests/test_cidr.c @@ -0,0 +1,38 @@ +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdio.h> + +static void test(const char *); + +int +main() { + test("192.5.4.0/23"); + test("192.5.4.0"); + test("192.5.5.1"); + test("192.5.5.1/23"); + test("192.5.5.1/24"); + test("192.5.5.1/28"); + test("192.5.5.1/32"); + return (0); +} + +static void +test(const char *input) { + int bits; + u_char temp[sizeof (struct in_addr)]; + char output[sizeof "255.255.255.255/32"]; + + memset(temp, 0x5e, sizeof temp); + if (inet_cidr_pton(AF_INET, input, temp, &bits) < 0) { + perror(input); + exit(1); + } + if (inet_cidr_ntop(AF_INET, temp, bits, output, sizeof output)==NULL){ + perror("inet_cidr_ntop"); + exit(1); + } + printf("input '%s', temp '%x %x %x %x', bits %d, output '%s'\n", + input, temp[0], temp[1], temp[2], temp[3], bits, output); +} diff --git a/contrib/bind/tests/test_getaddr.c b/contrib/bind/tests/test_getaddr.c new file mode 100644 index 0000000..9ca2189 --- /dev/null +++ b/contrib/bind/tests/test_getaddr.c @@ -0,0 +1,160 @@ +#include <port_before.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/socket.h> +#include <netdb.h> +#include <ctype.h> +#include <port_after.h> + +char *flags[] = { + " AI_PASSIVE", + " AI_CANONNAME", + " AI_NUMERICHOST", + " 0x00000008", + " 0x00000010", + " 0x00000020", + " 0x00000040", + " 0x00000080", + " 0x00000100", + " 0x00000200", + " 0x00000400", + " 0x00000800", + " 0x00001000", + " 0x00002000", + " 0x00004000", + " 0x00008000", + " 0x00010000", + " 0x00020000", + " 0x00040000", + " 0x00080000", + " 0x00100000", + " 0x00200000", + " 0x00400000", + " 0x00800000", + " 0x01000000", + " 0x02000000", + " 0x04000000", + " 0x08000000", + " 0x10000000", + " 0x20000000", + " 0x40000000", + " 0x80000000" +}; + +void +print_ai(struct addrinfo *answer, int hints) { + int i; + + if (answer == NULL) { + fprintf(stdout, "No %s\n", hints ? "Hints" : "Answer"); + return; + } + + fprintf(stdout, "%s:\n", hints ? "Hints" : "Answer"); + + while (answer) { + fputs("flags:", stdout); + for (i = 0; i < 32 ; i++) + if (answer->ai_flags & (1 << i)) + fputs(flags[i], stdout); + fputs("\n", stdout); + fprintf(stdout, "family: %d, socktype: %d, protocol: %d\n", + answer->ai_family, answer->ai_socktype, answer->ai_protocol); + if (hints) + return; + + if (answer->ai_canonname != NULL) + fprintf(stdout, "canonname: \"%s\"\n", + answer->ai_canonname); + else + fputs("canonname: --none--\n", stdout); + + fprintf(stdout, "addrlen: %d\n", answer->ai_addrlen); + + for (i = 0; i < answer->ai_addrlen; i++) + fprintf(stdout, "%s%02x", (i == 0) ? "0x" : "", + ((unsigned char*)(answer->ai_addr))[i]); + fputs("\n", stdout); + + for (i = 0; i < answer->ai_addrlen; i++) + fprintf(stdout, "%s%d", (i == 0) ? "" : ".", + ((unsigned char*)(answer->ai_addr))[i]); + fputs("\n", stdout); + + for (i = 0; i < answer->ai_addrlen; i++) { + int c = ((unsigned char*)(answer->ai_addr))[i]; + fprintf(stdout, "%c", (isascii(c) && isprint(c)) ? + c : '.'); + } + fputs("\n", stdout); + + answer = answer->ai_next; + } +} + +void +usage() { + fputs("usage:", stdout); + fputs("\t-h <hostname>\n", stdout); + fputs("\t-s <service>\n", stdout); + fputs("\t-p AI_PASSIVE\n", stdout); + fputs("\t-c AI_CANONNAME\n", stdout); + fputs("\t-n AI_NUMERICHOST\n", stdout); + fputs("\t-4 AF_INET4\n", stdout); + fputs("\t-6 AF_INET6\n", stdout); + fputs("\t-l AF_LOCAL\n", stdout); + fputs("\t-u IPPROTO_UDP\n", stdout); + fputs("\t-t IPPROTO_TCP\n", stdout); + fputs("\t-S SOCK_STREAM\n", stdout); + fputs("\t-D SOCK_DGRAM\n", stdout); + fputs("\t-R SOCK_RAW\n", stdout); + fputs("\t-M SOCK_RDM\n", stdout); + fputs("\t-P SOCK_SEQPACKET\n", stdout); + exit(1); +} + +main(int argc, char **argv) { + int c; + char *hostname = NULL; + char *service = NULL; + struct addrinfo info; + int res; + struct addrinfo *answer; + + memset(&info, 0, sizeof info); + + while ((c = getopt(argc, argv, "h:s:pcn46ltuSDRMP")) != -1) { + switch (c) { + case 'h': hostname = optarg; break; + case 's': service = optarg; break; + case 'p': info.ai_flags |= AI_PASSIVE; break; + case 'c': info.ai_flags |= AI_CANONNAME; break; + case 'n': info.ai_flags |= AI_NUMERICHOST; break; + case '4': info.ai_family = AF_INET; break; + case '6': info.ai_family = AF_INET6; break; +#ifdef AF_LOCAL + case 'l': info.ai_family = AF_LOCAL; break; +#else + case 'l': fprintf(stdout, "AF_LOCAL not supported\n"); break; +#endif + case 't': info.ai_protocol = IPPROTO_TCP; break; + case 'u': info.ai_protocol = IPPROTO_UDP; break; + case 'S': info.ai_socktype = SOCK_STREAM; break; + case 'D': info.ai_socktype = SOCK_DGRAM; break; + case 'R': info.ai_socktype = SOCK_RAW; break; + case 'M': info.ai_socktype = SOCK_RDM; break; + case 'P': info.ai_socktype = SOCK_SEQPACKET; break; + case '?': usage(); break; + } + + } + res = getaddrinfo(hostname, service, &info, &answer); + if (res) { + fprintf(stdout, "%s\n", gai_strerror(res)); + } else { + print_ai(&info, 1); + print_ai(answer, 0); + freeaddrinfo(answer); + } + exit (0); +} |