diff options
author | Martin Nagy <mnagy@redhat.com> | 2008-12-09 19:31:51 +0100 |
---|---|---|
committer | Martin Nagy <mnagy@redhat.com> | 2008-12-09 19:31:51 +0100 |
commit | 9b941ce45484431bf095ffc39f242e81c716cbd5 (patch) | |
tree | 5e9fb4d5945e88d78d61591cdd803e8174520f81 /contrib/dbus | |
download | bind_dynamic-bind-9-6-0-rc1.tar.gz bind_dynamic-bind-9-6-0-rc1.tar.xz bind_dynamic-bind-9-6-0-rc1.zip |
Initial import.bind-9-6-0-rc1
Diffstat (limited to 'contrib/dbus')
-rwxr-xr-x | contrib/dbus/GetForwarders | 31 | ||||
-rw-r--r-- | contrib/dbus/INSTALL | 9 | ||||
-rw-r--r-- | contrib/dbus/Makefile.9.3.2b1 | 20 | ||||
-rw-r--r-- | contrib/dbus/Makefile.9.3.3rc2 | 20 | ||||
-rw-r--r-- | contrib/dbus/README.DBUS | 259 | ||||
-rwxr-xr-x | contrib/dbus/SetForwarders | 52 | ||||
-rw-r--r-- | contrib/dbus/bind-9.3.2b1-dbus.patch | 713 | ||||
-rw-r--r-- | contrib/dbus/bind-9.3.3rc2-dbus.patch | 778 | ||||
-rw-r--r-- | contrib/dbus/dbus_mgr.c | 2458 | ||||
-rw-r--r-- | contrib/dbus/dbus_mgr.h | 37 | ||||
-rw-r--r-- | contrib/dbus/dbus_service.c | 1161 | ||||
-rw-r--r-- | contrib/dbus/dbus_service.h | 287 | ||||
-rw-r--r-- | contrib/dbus/named-dbus-system.conf | 20 | ||||
-rw-r--r-- | contrib/dbus/named-dbus.service | 3 |
14 files changed, 5848 insertions, 0 deletions
diff --git a/contrib/dbus/GetForwarders b/contrib/dbus/GetForwarders new file mode 100755 index 0000000..838706d --- /dev/null +++ b/contrib/dbus/GetForwarders @@ -0,0 +1,31 @@ +#!/bin/bash +# +# This script uses the named D-BUS support, which must be enabled in +# the running named with the named '-D' option, to get and print the +# list of forwarding zones in the running server. +# +# It accepts an optional <zone> first argument which is the DNS name +# of the zone whose forwarders (if any) will be retrieved. +# +# If no zone argument is specified, all forwarding zones will be listed. +# +# Usage: GetForwarders [ <zone> ] +# +# Copyright(C) Jason Vas Dias<jvdias@redhat.com> Red Hat Inc. 2005 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation at +# http://www.fsf.org/licensing/licenses/gpl.txt +# and included in this software distribution as the "LICENSE" file. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +zone='' +if [ $# -gt 0 ]; then + zone="string:$1"; +fi +dbus-send --system --type=method_call --print-reply --reply-timeout=20000 --dest=com.redhat.named /com/redhat/named com.redhat.named.text.GetForwarders $zone; diff --git a/contrib/dbus/INSTALL b/contrib/dbus/INSTALL new file mode 100644 index 0000000..2ad526e --- /dev/null +++ b/contrib/dbus/INSTALL @@ -0,0 +1,9 @@ +To build named with D-BUS support, run +# make +in this directory. +Then cd to the top-level BIND source directory, +(../..), and +# ./configure ...; make +After building, cd back to contrib/dbus and run: +# make install +as root to install the D-BUS configuration files. diff --git a/contrib/dbus/Makefile.9.3.2b1 b/contrib/dbus/Makefile.9.3.2b1 new file mode 100644 index 0000000..6285034 --- /dev/null +++ b/contrib/dbus/Makefile.9.3.2b1 @@ -0,0 +1,20 @@ +# contrib/dbus/Makefile +# +# This Makefile will install D-BUS support into the ISC BIND 9.3.2b1+ source, +# necessary to support dynamic forwarding table management with D-BUS, for +# Red Hat NetworkManager support. +# +# After running "make" in this directory, simply run make in the top level +# BIND source directory, and D-BUS support will be enabled. +# + +all: + echo 'Enabling D-BUS support...' + @ cp -fp dbus_mgr.c dbus_service.c ../../bin/named; + @ cp -fp dbus_mgr.h dbus_service.h ../../bin/named/include/named; + @ cp -fp README.DBUS ../../doc/misc + @ cd ../..; patch -s -p1 -b --suffix=.dbus < contrib/dbus/bind-9.3.2b1-dbus.patch + +install: + install -o root -g root -m 640 named-dbus-system.conf /etc/dbus-1/system.d/named.conf + install -o root -g root -m 640 named-dbus.service /usr/share/dbus-1/services/named.service diff --git a/contrib/dbus/Makefile.9.3.3rc2 b/contrib/dbus/Makefile.9.3.3rc2 new file mode 100644 index 0000000..91a0ffe --- /dev/null +++ b/contrib/dbus/Makefile.9.3.3rc2 @@ -0,0 +1,20 @@ +# contrib/dbus/Makefile +# +# This Makefile will install D-BUS support into the ISC BIND 9.3.2b1+ source, +# necessary to support dynamic forwarding table management with D-BUS, for +# Red Hat NetworkManager support. +# +# After running "make" in this directory, simply run make in the top level +# BIND source directory, and D-BUS support will be enabled. +# + +all: + echo 'Enabling D-BUS support...' + @ cp -fp dbus_mgr.c dbus_service.c ../../bin/named; + @ cp -fp dbus_mgr.h dbus_service.h ../../bin/named/include/named; + @ cp -fp README.DBUS ../../doc/misc + @ cd ../..; patch -s -p1 -b --suffix=.dbus < contrib/dbus/bind-9.3.3rc2-dbus.patch + +install: + install -o root -g root -m 640 named-dbus-system.conf /etc/dbus-1/system.d/named.conf + install -o root -g root -m 640 named-dbus.service /usr/share/dbus-1/services/named.service diff --git a/contrib/dbus/README.DBUS b/contrib/dbus/README.DBUS new file mode 100644 index 0000000..8c5c73f --- /dev/null +++ b/contrib/dbus/README.DBUS @@ -0,0 +1,259 @@ +Dynamic Management of the ISC BIND named Forwarding Table with D-BUS + + Jason Vas Dias<jvdias@redhat.com>, Red Hat Inc., May 2005 + + +Overview: + + Red Hat has developed an extension to named that is enabled during + rpmbuild of the bind SRPM with the option --define 'WITH_DBUS=1', + and at named runtime with the -D named option. + + You can obtain the latest version of the source code for the BIND + D-BUS extensions from: + + http://people.redhat.com/~jvdias/bind-dbus/ + + The Red Hat BIND D-BUS extensions allow services such as Red Hat's + NetworkManager and dhcdbd (the DHCP Client controller D-Bus daemon) + to tell named which name servers to forward requests to dynamically, + instead of only with the "forward" and "forwarders" named.conf options. + + Dynamic forwarding table management allows named to be an effective + and efficient caching nameserver for configurations with multiple + wireless or VPN IP interfaces that are not always active, and whose + name service parameters are typically configured with DHCP. + + Problems with trying to configure such systems automatically using + only the libc resolver, causing conflicts over the contents of the + /etc/resolv.conf file, are avoided; the resolv.conf file can contain + only the users chosen search path and the single "nameserver 127.0.0.1" + entry. + + named also provides a much more efficient, both in terms of caching + performance and resolving time, and much more feature rich DNS resolver + than does the libc resolver library and nscd, and has the benefit of + existing improved IPv6 and DNSSEC support over glibc and nscd. + +Operation Guide for Developers: + + Programs can access named's dynamic forward table management services + using D-BUS, the "service messagebus" sysv-init service that is started + by default at boot (see the D-BUS documentation for details). + + When named is started with the -D option (by adding -D to the $OPTIONS + variable in /etc/sysconfig/named), named provides two D-BUS methods: + + These D-BUS names are common to all named D-BUS methods: + D-BUS Destination D-BUS Path D-BUS interface + ~~~~~~~~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~~~~~~ + com.redhat.named /com/redhat/named com.redhat.named + + D-BUS Members: + ~~~~~~~~~~~~~~ + + SetForwarders ( { [ string:<domain name>, + ~~~~~~~~~~~~~ [ ( uint32:<nameserver IPv4 address> + | array of 4 bytes : <nameserver IPv4 address> + | array of 16 bytes : <nameserver IPv6 address> + | string: <nameserver dotted-quad IPv4 or RFC2374 IPv6 address> + ) + [ uint16: <nameserver port>, ] + [ uint8: <forward policy> ] + ] + ] + } , ... + ) + + SetForwarders will create or delete members of the forwarding table. + + It accepts a list of tuples of up to 4 members: only the <domain name> + is required. + + If ONLY the <domain name> is specified, the forwarding entry for + EXACTLY that domain name is deleted if it exists. + + Only a specification of at least one <nameserver IP address> is required to + create a forwarding entry. + + The IP address can be IPv4: + ( 32-bit integer OR array of 4 bytes OR dotted-quad string ) + Or IPv6: + ( array of 16 bytes + OR RFC 2373/4 ascii string of 8 ':' separate hex quads as supported by inet_pton(3) + ) + + 32 and 16-bit integer parameters MUST be given in network byte order; ie the IPv4 address + 192.168.2.1 would be specified as uint32:16951488 on an i386 and port 53 would be uint16:13568. + + There are an optional <port> 16-bit integer parameter, to specify the name server socket + address port associated with the preceding IP address, and a <forward policy> + parameter, which sets the forward policy as follows: + 0: "none" : never forward to this nameserver for this domain. + 1: "first": forward first to this server, and then search its authoritative data. + 2: "only" : always forward to this nameserver for this domain. + + If not specified, <port> will have the value 53, and <forward policy> will be "2": "only". + named's default forward policy is "first" . + + Creation of forwarding domains is not "exact", as is deletion, but is "inclusive": + creating forwarding entry for the '.' domain sets the default set of nameservers named + will query for ALL domains, and creating an entry for "redhat.com" creates a set of + nameservers to be queried for all names suffixed by "redhat.com." . If both are specified, + the "redhat.com" servers will be tried first, followed by the "." servers. + + Forwarding entries are ONLY created in the first DNS View that matches the "localhost" client + (127.0.0.1) and destination. The default view, which exists if no views have been specified + in named.conf, matches ALL clients and destinations. If the user has configured views, none + of which match the localhost client, then no forwarding will be dynamically configurable. + Users are also free to configure a view that matches the localhost, for which forwarding + will be dynamically configurable, and other views which do not match the localhost, so that + other, remote clients can be served that will not be subject to dynamic forwarding. So it + is a fully supported configuration that users can serve authoritative data to external + clients and still use named's forwarding features for their localhost resolver. + + SetForwarders returns uint32:0 on success or a DBUS_ERROR message on failure . + + + GetForwarders ( [ string:<domain name> ] ) + ~~~~~~~~~~~~~ + Using the default "com.redhat.named" interface, returns the EXACT forwarding entry for + <domain name> as binary D-BUS types; there is also a com.redhat.named.text interface + supported by GetForwarders which returns all values as string: text . + + If a <domain name> is not specified, all forwarding table entries are dumped. + + + Examples: + ~~~~~~~~ + + Suppose we start out with the named.conf configuration: + + + options { ... + forwarders { 172.16.80.118; }; + ... + }; + + zone "redhat.com" { + forward only; + forwarders { 172.16.76.10; 172.16.52.28; }; + }; + + Using a "dbus-send" trivially modified to support uint16 parameters (!) : + + $ dbus-send --system --type=method_call --print-reply --reply-timeout=20000 \ + --dest=com.redhat.named /com/redhat/named com.redhat.named.GetForwarders + method return sender=:1.367 -> dest=:1.368 + 0 string "redhat.com" + 1 byte 2 + 2 uint32 172757164 + 3 uint16 13568 + 4 uint32 473174188 + 5 uint16 13568 + 6 string "." + 7 byte 1 + 8 uint32 1984958636 + 9 uint16 13568 + + ie. GetForwarders always returns a list of tuples of + ( <domain name>, <forward policy>, <ip address>, <port> ) + + If the "text" interface was specified: + + $ dbus-send --system --type=method_call --print-reply --reply-timeout=20000 \ + --dest=com.redhat.named /com/redhat/named com.redhat.named.text.GetForwarders + method return sender=:1.367 -> dest=:1.370 + 0 string "redhat.com" + 1 string "only" + 2 string "172.16.76.10" + 3 string "53" + 4 string "172.16.52.28" + 5 string "53" + 6 string "." + 7 string "first" + 8 string "172.16.80.118" + 9 string "53" + + So we could set the default nameserver for the root zone as follows: + + $ dbus-send --system --type=method_call --print-reply --reply-timeout=20000 \ + --dest=com.redhat.named /com/redhat/named com.redhat.named.SetForwarders \ + string:'.' string:'192.33.14.30' string:'2001:503:231d::2:30' + method return sender=:1.367 -> dest=:1.371 + 0 uint32 0 + $ dbus-send --system --type=method_call --print-reply --reply-timeout=20000 \ + --dest=com.redhat.named /com/redhat/named com.redhat.named.text.GetForwarders + method return sender=:1.367 -> dest=:1.372 + 0 string "redhat.com" + 1 string "only" + 2 string "172.16.76.10" + 3 string "53" + 4 string "172.16.52.28" + 5 string "53" + 6 string "." + 7 string "only" + 8 string "192.33.14.30" + 9 string "53" + 10 string "2001:503:231d::2:30" + 11 string "53" + + Using tcpdump one can verify that named will attempt to contact 192.33.14.30, then + 2001:503:231d::2:30, for all zones not in redhat.com; for redhat.com zones, 172.16.76.10 + and 192.33.14.30 will be tried in that order. + + If the D-BUS driver dbus-daemon should shut down, named will emit the syslog message: + "D-BUS service disabled." + And will retry connecting to D-BUS every 10 seconds - once it has connected, the message: + "D-BUS service enabled." + will be logged. + + NOTE: there are the "SetForwarders" and "GetForwarders" scripts in the contrib/dbus directory + of the BIND source code distribution which are wrappers around the dbus-send commands above. + Usage: SetForwarders [ -t first | only ] <zone> [ <server> [...<server>] ] + GetForwarders [ <zone> ] + + + DHCP Integration + ~~~~~~~~~~~~~~~~ + + With the -D option, named will try to subscribe to dhcdbd, the DHCP Client D-BUS Daemon, to + be notified of DHCP "reason", "domain-name", "domain-name-server", "ip-address", and "subnet-mask" + DHCP options when the dhclient program has received them from a DHCP server . + + If it cannot subscribe to dhcdbd, named will emit the message : + "D-BUS dhcdbd subscription disabled." + and will monitor D-BUS "NameOwnerChanged" messages for the appearance of a new owner + for "com.redhat.dhcp". When the name is owned, named will send a "com.redhat.dhcp.subscribe.binary" + message to dhcdbd to subscribe to the above options for all interfaces (provided by dhcdbd-1.5+), + and emit the log message: + "D-BUS dhcdbd subscription enabled." + + named will match on signals from the com.redhat.dhcp.subscribe.binary interface for those option + settings, and , when the last option is received (indicated by a "reason" of 15: END_OPTIONS), it + will configure the forwarding table . + + For each whitespace separated member of "domain-name-servers", AND for the reverse IPv4 in-addr.arpa + class C or less domain of the ip-address masked by the subnet-mask, it will create a forwarding entry + to query each "domain-server" . + + To support CIDR-based reverse subnet forwarding, Views would have to be configured dynamically, a + possible future direction which is not yet implemented. (It would perhaps be easier to add a + "match-queries" ACL to the forwarders table). + + When dhclient acquires a lease, named will configure forwarding, and emit the message: + "D-BUS: dhclient for interface eth0 acquired new lease - creating forwarders." + + When a lease expires or the interface is brought down (dhclient is stopped with dhcdbd), it + will revert any forwarding entries from the initial, static configuration that were modified + by the DHCP subscription to their initial values; ie. if redhat.com had a forwarder configured + in named.conf, and then an DHCP session specified forwarders for redhat.com, when the DHCP + session ends the forwarders for redhat.com are reverted to their named.conf values; thus + when all DHCP interfaces have released their leases, and if no SetForwarders commands were issued, + the forwarding configuration will be identical to that at named startup. + + + To Do: + - Sending signals when any Forwarding entry is changed (easy to implement if it would be desirable). + - CIDR based reverse Forwarding + diff --git a/contrib/dbus/SetForwarders b/contrib/dbus/SetForwarders new file mode 100755 index 0000000..8ee4ce1 --- /dev/null +++ b/contrib/dbus/SetForwarders @@ -0,0 +1,52 @@ +#!/bin/bash +# +# This script uses the named D-BUS support, which must be enabled in +# the running named with the named '-D' option, to set the forwarding zones +# in the running server. +# +# One zone argument is required, followed by any number of server IP (v4 or v6) +# addresses. If the server IP address list is empty, any forwarders for the zone +# will be removed. +# +# Usage: +# SetForwarders [ -t <'first' | 'only'> ] <zone> [ <server IP> [...<server IP>] ] +# +# Copyright(C) Jason Vas Dias<jvdias@redhat.com> Red Hat Inc. 2005 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation at +# http://www.fsf.org/licensing/licenses/gpl.txt +# and included in this software distribution as the "LICENSE" file. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +usage() { echo "Usage: SetForwarders [ -t <'first' | 'only'> ] <zone> [ <server> [...<server>] ]"; } +type='' +if [ $# -eq 0 ]; then + usage; + exit 1; +elif [ "$1" = "-t" ]; then + if [ $# -lt 2 ]; then + echo '-t option requires an argument.' + exit 1; + fi; + type=$2; + shift 2; +fi; +if [ $# -lt 1 ]; then + echo '<zone> first argument required.' + exit 1; +fi; +zone='string:'"$1"; +shift; +servers=''; +if [ $# -gt 0 ]; then + for svr in $*; do + servers="$servers string:$svr"; + done +fi; +dbus-send --system --type=method_call --print-reply --reply-timeout=20000 --dest=com.redhat.named /com/redhat/named com.redhat.named.text.SetForwarders $zone $type $servers; diff --git a/contrib/dbus/bind-9.3.2b1-dbus.patch b/contrib/dbus/bind-9.3.2b1-dbus.patch new file mode 100644 index 0000000..cdf50d6 --- /dev/null +++ b/contrib/dbus/bind-9.3.2b1-dbus.patch @@ -0,0 +1,713 @@ +--- bind-9.3.2b1/lib/dns/rbt.c.dbus 2005-06-17 21:03:24.000000000 -0400 ++++ bind-9.3.2b1/lib/dns/rbt.c 2005-10-07 12:43:26.000000000 -0400 +@@ -2172,6 +2172,47 @@ + dns_rbt_printtree(rbt->root, NULL, 0); + } + ++static void ++dns_rbt_traverse_tree(dns_rbtnode_t *root, dns_rbt_traverse_callback_t cb, void *cb_arg1, void *cb_arg2 ) { ++/* ++ * This is used ONLY to traverse the forward table by dbus_mgr at the moment. ++ * Since the forward table is not likely to be large, this can be recursive. ++ */ ++ dns_name_t name; ++ dns_offsets_t offsets; ++ char buf[DNS_NAME_MAXWIRE]; ++ isc_buffer_t buffer; ++ ++ if (root != NULL) { ++ ++ if (DOWN(root)) ++ dns_rbt_traverse_tree(DOWN(root), cb, cb_arg1, cb_arg2); ++ ++ if( LEFT(root) != NULL ) ++ dns_rbt_traverse_tree(LEFT(root), cb, cb_arg1, cb_arg2); ++ ++ if( RIGHT(root) != NULL ) ++ dns_rbt_traverse_tree(RIGHT(root), cb, cb_arg1, cb_arg2); ++ ++ if( DATA(root) == 0L ) ++ return; ++ ++ dns_name_init(&name, offsets); ++ isc_buffer_init(&buffer, buf, DNS_NAME_MAXWIRE); ++ dns_name_setbuffer( &name, &buffer); ++ dns_rbt_fullnamefromnode(root, &name); ++ ++ (*cb)(&name, DATA(root), cb_arg1, cb_arg2); ++ } ++} ++ ++void dns_rbt_traverse( dns_rbt_t *rbt, dns_rbt_traverse_callback_t cb, void *cb_arg1, void *cb_arg2 ) ++{ ++ REQUIRE(VALID_RBT(rbt)); ++ ++ dns_rbt_traverse_tree( rbt->root, cb, cb_arg1, cb_arg2 ); ++} ++ + /* + * Chain Functions + */ +--- bind-9.3.2b1/lib/dns/forward.c.dbus 2005-03-16 22:58:30.000000000 -0500 ++++ bind-9.3.2b1/lib/dns/forward.c 2005-10-07 12:43:26.000000000 -0400 +@@ -200,3 +200,89 @@ + } + isc_mem_put(fwdtable->mctx, forwarders, sizeof(dns_forwarders_t)); + } ++ ++/*** ++ *** new D-BUS Dynamic Forwarding Zones functions: ++ ***/ ++isc_result_t ++dns_fwdtable_delete(dns_fwdtable_t *fwdtable, dns_name_t *name ) ++{ ++ isc_result_t result; ++ ++ REQUIRE(VALID_FWDTABLE(fwdtable)); ++ ++ RWLOCK(&fwdtable->rwlock, isc_rwlocktype_write); ++ ++ result = dns_rbt_deletename(fwdtable->table, name, ISC_FALSE); ++ ++ RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_write); ++ ++ return (result); ++} ++ ++isc_result_t ++dns_fwdtable_find_closest(dns_fwdtable_t *fwdtable, ++ dns_name_t *name, ++ dns_name_t *foundname, ++ dns_forwarders_t **forwardersp) ++{ ++ isc_result_t result; ++ ++ REQUIRE(VALID_FWDTABLE(fwdtable)); ++ ++ RWLOCK(&fwdtable->rwlock, isc_rwlocktype_read); ++ ++ result = dns_rbt_findname(fwdtable->table, name, 0, foundname, ++ (void **)forwardersp); ++ ++ if(result == DNS_R_PARTIALMATCH) ++ result = ISC_R_SUCCESS; ++ ++ RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_read); ++ ++ return (result); ++} ++ ++isc_result_t ++dns_fwdtable_find_exact(dns_fwdtable_t *fwdtable, dns_name_t *name, ++ dns_forwarders_t **forwardersp) ++{ ++ isc_result_t result; ++ ++ REQUIRE(VALID_FWDTABLE(fwdtable)); ++ ++ REQUIRE(forwardersp != 0L); ++ ++ RWLOCK(&fwdtable->rwlock, isc_rwlocktype_read); ++ ++ result = dns_rbt_findname(fwdtable->table, name, 0, NULL, ++ (void **)forwardersp); ++ ++ if( result != ISC_R_SUCCESS ) ++ *forwardersp = 0L; ++ ++ RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_read); ++ ++ return (result); ++} ++ ++static ++void dns_fwdtable_traverse ++( ++ dns_name_t *name, ++ void *node_data, ++ void *cbp, ++ void *cb_arg ++) ++{ ++ dns_fwdtable_callback_t cb = (dns_fwdtable_callback_t) cbp; ++ ++ (*cb)( name, node_data, cb_arg); ++} ++ ++void dns_fwdtable_foreach(dns_fwdtable_t *fwdtable, dns_fwdtable_callback_t cb, void *cb_arg ) ++{ ++ REQUIRE(VALID_FWDTABLE(fwdtable)); ++ ++ dns_rbt_traverse( fwdtable->table, dns_fwdtable_traverse, cb, cb_arg ); ++} +--- bind-9.3.2b1/lib/dns/include/dns/forward.h.dbus 2005-03-16 22:58:31.000000000 -0500 ++++ bind-9.3.2b1/lib/dns/include/dns/forward.h 2005-10-07 12:43:26.000000000 -0400 +@@ -98,6 +98,37 @@ + * all memory associated with the forwarding table is freed. + */ + ++ ++/* These are ONLY used by dbus_mgr : ++ */ ++ ++isc_result_t ++dns_fwdtable_delete( dns_fwdtable_t *fwdtable, dns_name_t *name ); ++/* ++ * Removes an entry from the forwarding table. ++ */ ++ ++isc_result_t ++dns_fwdtable_find_exact(dns_fwdtable_t *fwdtable, dns_name_t *name, ++ dns_forwarders_t **forwardersp); ++/* ++ * Finds an exact match for "name" in the forwarding table. ++ */ ++ ++isc_result_t ++dns_fwdtable_find_closest(dns_fwdtable_t *fwdtable, dns_name_t *name, dns_name_t *foundname, ++ dns_forwarders_t **forwardersp); ++/* ++ * Finds the closest match for "*name" in the forwarding table, returning ++ * the actual name matching in *name if different to *name passed in. ++ */ ++ ++typedef void (*dns_fwdtable_callback_t)( dns_name_t *, dns_forwarders_t *, void *); ++void dns_fwdtable_foreach(dns_fwdtable_t *fwdtable, dns_fwdtable_callback_t cb, void * ); ++/* Invoke cb for each member of fwdtable ++ */ ++ ++ + ISC_LANG_ENDDECLS + + #endif /* DNS_FORWARD_H */ +--- bind-9.3.2b1/lib/dns/include/dns/rbt.h.dbus 2004-10-11 01:55:51.000000000 -0400 ++++ bind-9.3.2b1/lib/dns/include/dns/rbt.h 2005-10-07 12:43:26.000000000 -0400 +@@ -833,6 +833,17 @@ + * <something_else> Any error result from dns_name_concatenate. + */ + ++ ++typedef void (*dns_rbt_traverse_callback_t)( dns_name_t *name, ++ void *node_data, ++ void *cb_arg1, ++ void *cb_arg2); ++ ++void dns_rbt_traverse( dns_rbt_t *rbt, dns_rbt_traverse_callback_t cb, void *cb_arg1, void *cb_arg2 ); ++/* tree traversal function (only used by D-BUS dynamic forwarding dbus_mgr at ++ * the moment) ++ */ ++ + ISC_LANG_ENDDECLS + + #endif /* DNS_RBT_H */ +--- bind-9.3.2b1/lib/isc/unix/socket.c.dbus 2005-08-25 00:32:55.000000000 -0400 ++++ bind-9.3.2b1/lib/isc/unix/socket.c 2005-10-07 13:40:03.000000000 -0400 +@@ -148,6 +148,11 @@ + ISC_LIST(isc_socketevent_t) recv_list; + ISC_LIST(isc_socket_newconnev_t) accept_list; + isc_socket_connev_t *connect_ev; ++ ++ /* these are used only by isc_sockettype_fd sockets:*/ ++ isc_socketevent_t *read_ready_event; ++ isc_socketevent_t *write_ready_event; ++ isc_socketevent_t *selected_event; + + /* + * Internal events. Posted when a descriptor is readable or +@@ -304,7 +309,7 @@ + + static void + wakeup_socket(isc_socketmgr_t *manager, int fd, int msg) { +- isc_socket_t *sock; ++ isc_socket_t *sock=0L; + + /* + * This is a wakeup on a socket. If the socket is not in the +@@ -1266,6 +1271,9 @@ + sock->connected = 0; + sock->connecting = 0; + sock->bound = 0; ++ sock->read_ready_event = 0L; ++ sock->write_ready_event = 0L; ++ sock->selected_event = 0L; + + /* + * initialize the lock +@@ -1378,13 +1386,16 @@ + case isc_sockettype_tcp: + sock->fd = socket(pf, SOCK_STREAM, IPPROTO_TCP); + break; ++ ++ case isc_sockettype_fd: ++ sock->fd = pf; + } + + #ifdef F_DUPFD + /* + * Leave a space for stdio to work in. + */ +- if (sock->fd >= 0 && sock->fd < 20) { ++ if ( (type != isc_sockettype_fd) && (sock->fd >= 0) && (sock->fd < 20) ) { + int new, tmp; + new = fcntl(sock->fd, F_DUPFD, 20); + tmp = errno; +@@ -1438,7 +1449,7 @@ + } + } + +- if (make_nonblock(sock->fd) != ISC_R_SUCCESS) { ++ if ((type != isc_sockettype_fd) && (make_nonblock(sock->fd) != ISC_R_SUCCESS)) { + (void)close(sock->fd); + free_socket(&sock); + return (ISC_R_UNEXPECTED); +@@ -1706,6 +1717,38 @@ + isc_task_send(ev->ev_sender, (isc_event_t **)&iev); + } + ++static ++isc_event_t *dispatch_read_ready(isc_socketmgr_t *manager, isc_socket_t *sock) ++{ ++ isc_event_t *dev = (isc_event_t*)sock->read_ready_event, *ev; ++ ++ ev = isc_mem_get(manager->mctx, dev->ev_size); ++ memcpy(ev,dev,dev->ev_size); ++ ISC_LINK_INIT(ev,ev_link); ++ isc_task_send(dev->ev_sender, &ev ); ++ return (isc_event_t *)sock->selected_event; ++} ++ ++static ++isc_event_t *dispatch_write_ready(isc_socketmgr_t *manager,isc_socket_t *sock) ++{ ++ isc_event_t *dev = (isc_event_t*)sock->write_ready_event, *ev; ++ ev = isc_mem_get(manager->mctx, dev->ev_size); ++ memcpy(ev,dev,dev->ev_size); ++ ISC_LINK_INIT(ev,ev_link); ++ isc_task_send(dev->ev_sender, &ev ); ++ return (isc_event_t *)sock->selected_event; ++} ++ ++static ++void dispatch_selected(isc_socketmgr_t *manager, isc_event_t *dev) ++{ isc_event_t *ev; ++ ev = isc_mem_get(manager->mctx, dev->ev_size); ++ memcpy(ev,dev,dev->ev_size); ++ ISC_LINK_INIT(ev,ev_link); ++ isc_task_send(dev->ev_sender, &ev ); ++} ++ + /* + * Dequeue an item off the given socket's read queue, set the result code + * in the done event to the one provided, and send it to the task it was +@@ -2113,6 +2156,7 @@ + int i; + isc_socket_t *sock; + isc_boolean_t unlock_sock; ++ isc_event_t *sock_selected = 0L; + + REQUIRE(maxfd <= (int)FD_SETSIZE); + +@@ -2146,11 +2190,15 @@ + unlock_sock = ISC_TRUE; + LOCK(&sock->lock); + if (!SOCK_DEAD(sock)) { ++ if( sock->type != isc_sockettype_fd ) ++ { + if (sock->listener) + dispatch_accept(sock); + else + dispatch_recv(sock); +- } ++ }else ++ sock_selected = dispatch_read_ready(manager,sock); ++ } + FD_CLR(i, &manager->read_fds); + } + check_write: +@@ -2164,16 +2212,24 @@ + LOCK(&sock->lock); + } + if (!SOCK_DEAD(sock)) { ++ if( sock->type != isc_sockettype_fd ) ++ { + if (sock->connecting) + dispatch_connect(sock); + else + dispatch_send(sock); ++ }else ++ sock_selected = dispatch_write_ready(manager,sock); + } + FD_CLR(i, &manager->write_fds); + } + if (unlock_sock) + UNLOCK(&sock->lock); + } ++ if( sock_selected != 0L ) ++ { ++ dispatch_selected(manager, sock_selected); ++ } + } + + #ifdef ISC_PLATFORM_USETHREADS +@@ -2192,7 +2248,7 @@ + int cc; + fd_set readfds; + fd_set writefds; +- int msg, fd; ++ int msg, fd = -1; + int maxfd; + char strbuf[ISC_STRERRORSIZE]; + +@@ -3523,3 +3579,55 @@ + return (ISC_R_SUCCESS); + } + #endif /* ISC_PLATFORM_USETHREADS */ ++ ++isc_socketevent_t* ++isc_socket_fd_handle_reads( isc_socket_t *sock, isc_socketevent_t *dev ) ++{ ++ REQUIRE(VALID_SOCKET(sock)); ++ if(dev != 0L) ++ { ++ sock->references=1; ++ sock->read_ready_event = dev; ++ select_poke(sock->manager, sock->fd, SELECT_POKE_READ); ++ }else ++ { ++ dev = sock->read_ready_event ; ++ sock->read_ready_event = 0L ; ++ } ++ return dev; ++} ++ ++isc_socketevent_t* ++isc_socket_fd_handle_writes( isc_socket_t *sock, isc_socketevent_t *dev ) ++{ ++ REQUIRE(VALID_SOCKET(sock)); ++ if(dev != 0L) ++ { ++ sock->references=1; ++ sock->write_ready_event = dev; ++ select_poke(sock->manager, sock->fd, SELECT_POKE_WRITE); ++ }else ++ { ++ dev = sock->write_ready_event; ++ sock->write_ready_event = 0L; ++ } ++ return dev; ++} ++ ++isc_socketevent_t* ++isc_socket_fd_handle_selected( isc_socket_t *sock, isc_socketevent_t *dev ) ++{ ++ REQUIRE(VALID_SOCKET(sock)); ++ if(dev != 0L) ++ { ++ sock->references=1; ++ sock->selected_event = dev; ++ }else ++ { ++ dev = sock->selected_event; ++ sock->selected_event = 0L; ++ sock->references=0; ++ destroy(&sock); ++ } ++ return dev; ++} +--- bind-9.3.2b1/lib/isc/include/isc/socket.h.dbus 2004-03-08 04:04:53.000000000 -0500 ++++ bind-9.3.2b1/lib/isc/include/isc/socket.h 2005-10-07 12:43:26.000000000 -0400 +@@ -136,6 +136,10 @@ + #define ISC_SOCKEVENT_NEWCONN (ISC_EVENTCLASS_SOCKET + 3) + #define ISC_SOCKEVENT_CONNECT (ISC_EVENTCLASS_SOCKET + 4) + ++#define ISC_SOCKEVENT_READ_READY (ISC_EVENTCLASS_SOCKET + 5) ++#define ISC_SOCKEVENT_WRITE_READY (ISC_EVENTCLASS_SOCKET + 6) ++#define ISC_SOCKEVENT_SELECTED (ISC_EVENTCLASS_SOCKET + 7) ++ + /* + * Internal events. + */ +@@ -144,7 +148,8 @@ + + typedef enum { + isc_sockettype_udp = 1, +- isc_sockettype_tcp = 2 ++ isc_sockettype_tcp = 2, ++ isc_sockettype_fd = 8 + } isc_sockettype_t; + + /* +@@ -699,6 +704,30 @@ + * 'sock' is a valid socket. + */ + ++isc_socketevent_t* ++isc_socket_fd_handle_reads( isc_socket_t *sock, isc_socketevent_t *dev ); ++/* register the "dev" event to be sent when the isc_sockettype_fd sock ++ * was select()-ed for read. If there is already an event registered, it ++ * is returned, otherwise 0 is returned. If dev is 0, removes any existing ++ * registered event. ++ */ ++ ++isc_socketevent_t* ++isc_socket_fd_handle_writes( isc_socket_t *sock, isc_socketevent_t *dev ); ++/* register the "dev" event to be sent when the isc_sockettype_fd sock ++ * was select()-ed for write. If there is already an event registered, it ++ * is returned, otherwise 0 is returned. If dev is 0, removes any existing ++ * registered event. ++ */ ++ ++isc_socketevent_t* ++isc_socket_fd_handle_selected( isc_socket_t *sock, isc_socketevent_t *dev ); ++/* register the "dev" event to be sent when ALL isc_sockettype_fd sockets ++ * have been select()-ed . If there is already an event registered, it ++ * is returned, otherwise 0 is returned. If dev is 0, removes any existing ++ * registered event. ++ */ ++ + ISC_LANG_ENDDECLS + + #endif /* ISC_SOCKET_H */ +--- bind-9.3.2b1/bin/named/log.c.dbus 2005-05-24 19:58:17.000000000 -0400 ++++ bind-9.3.2b1/bin/named/log.c 2005-10-07 12:43:26.000000000 -0400 +@@ -41,6 +41,7 @@ + { "queries", 0 }, + { "unmatched", 0 }, + { "update-security", 0 }, ++ { "dbus", 0 }, + { NULL, 0 } + }; + +@@ -60,6 +61,7 @@ + { "notify", 0 }, + { "control", 0 }, + { "lwresd", 0 }, ++ { "dbus", 0 }, + { NULL, 0 } + }; + +--- bind-9.3.2b1/bin/named/Makefile.in.dbus 2004-09-06 17:47:25.000000000 -0400 ++++ bind-9.3.2b1/bin/named/Makefile.in 2005-10-07 13:44:22.000000000 -0400 +@@ -35,7 +35,9 @@ + ${LWRES_INCLUDES} ${DNS_INCLUDES} ${BIND9_INCLUDES} \ + ${ISCCFG_INCLUDES} ${ISCCC_INCLUDES} ${ISC_INCLUDES} \ + ${DBDRIVER_INCLUDES} +- ++DBUS_ARCHDEP_LIBDIR ?= lib ++DBUS_INCLUDES = \ ++ -I/usr/${DBUS_ARCHDEP_LIBDIR}/dbus-1.0/include -I/usr/include/dbus-1.0 + CDEFINES = + CWARNINGS = + +@@ -52,6 +54,7 @@ + ISCDEPLIBS = ../../lib/isc/libisc.@A@ + LWRESDEPLIBS = ../../lib/lwres/liblwres.@A@ + BIND9DEPLIBS = ../../lib/bind9/libbind9.@A@ ++DBUSLIBS= -ldbus-1 + + DEPLIBS = ${LWRESDEPLIBS} ${DNSDEPLIBS} ${BIND9DEPLIBS} \ + ${ISCCFGDEPLIBS} ${ISCCCDEPLIBS} ${ISCDEPLIBS} +@@ -71,6 +74,7 @@ + zoneconf.@O@ \ + lwaddr.@O@ lwresd.@O@ lwdclient.@O@ lwderror.@O@ lwdgabn.@O@ \ + lwdgnba.@O@ lwdgrbn.@O@ lwdnoop.@O@ lwsearch.@O@ \ ++ dbus_service.@O@ dbus_mgr.@O@ \ + $(DBDRIVER_OBJS) + + UOBJS = unix/os.@O@ +@@ -83,6 +87,7 @@ + zoneconf.c \ + lwaddr.c lwresd.c lwdclient.c lwderror.c lwdgabn.c \ + lwdgnba.c lwdgrbn.c lwdnoop.c lwsearch.c \ ++ dbus_service.c dbus_mgr.c \ + $(DBDRIVER_SRCS) + + MANPAGES = named.8 lwresd.8 named.conf.5 +@@ -105,9 +110,14 @@ + -DNS_LOCALSTATEDIR=\"${localstatedir}\" \ + -c ${srcdir}/config.c + ++dbus_service.@O@: dbus_service.c ++ ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} \ ++ ${DBUS_INCLUDES} \ ++ -c ${srcdir}/dbus_service.c ++ + named@EXEEXT@: ${OBJS} ${UOBJS} ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ +- ${OBJS} ${UOBJS} ${LIBS} ++ ${OBJS} ${UOBJS} ${LIBS} ${DBUSLIBS} + + lwresd@EXEEXT@: named@EXEEXT@ + rm -f lwresd@EXEEXT@ +--- bind-9.3.2b1/bin/named/named.8.dbus 2005-05-12 22:43:20.000000000 -0400 ++++ bind-9.3.2b1/bin/named/named.8 2005-10-07 13:50:12.000000000 -0400 +@@ -41,7 +41,7 @@ + named \- Internet domain name server + .SH "SYNOPSIS" + .HP 6 +-\fBnamed\fR [\fB\-4\fR] [\fB\-6\fR] [\fB\-c\ \fIconfig\-file\fR\fR] [\fB\-d\ \fIdebug\-level\fR\fR] [\fB\-f\fR] [\fB\-g\fR] [\fB\-n\ \fI#cpus\fR\fR] [\fB\-p\ \fIport\fR\fR] [\fB\-s\fR] [\fB\-t\ \fIdirectory\fR\fR] [\fB\-u\ \fIuser\fR\fR] [\fB\-v\fR] [\fB\-x\ \fIcache\-file\fR\fR] ++\fBnamed\fR [\fB\-4\fR] [\fB\-6\fR] [\fB\-c\ \fIconfig\-file\fR\fR] [\fB\-d\ \fIdebug\-level\fR\fR] [\fB\-f\fR] [\fB\-g\fR] [\fB\-n\ \fI#cpus\fR\fR] [\fB\-p\ \fIport\fR\fR] [\fB\-s\fR] [\fB\-t\ \fIdirectory\fR\fR] [\fB\-u\ \fIuser\fR\fR] [\fB\-v\fR] [\fB\-x\ \fIcache\-file\fR\fR] [\fB\-D\fR] + .SH "DESCRIPTION" + .PP + \fBnamed\fR is a Domain Name System (DNS) server, part of the BIND 9 distribution from ISC\&. For more information on the DNS, see RFCs 1033, 1034, and 1035\&. +@@ -103,6 +103,13 @@ + .B "Warning:" + This option must not be used\&. It is only of interest to BIND 9 developers and may be removed or changed in a future release\&. + .RE ++.sp ++.TP ++\fB\-D\fR ++Enable dynamic management of the forwarding table with D-BUS ++messages. This option is required for Red Hat NetworkManager ++support. See doc/README.DBUS . ++.sp + .SH "SIGNALS" + .PP + In routine operation, signals should not be used to control the nameserver; \fBrndc\fR should be used instead\&. +@@ -117,6 +124,7 @@ + .SH "CONFIGURATION" + .PP + The \fBnamed\fR configuration file is too complex to describe in detail here\&. A complete description is provided in the BIND 9 Administrator Reference Manual\&. ++.PP + .SH "FILES" + .TP + \fI/etc/named\&.conf\fR +--- bind-9.3.2b1/bin/named/main.c.dbus 2005-04-28 21:04:47.000000000 -0400 ++++ bind-9.3.2b1/bin/named/main.c 2005-10-07 12:43:26.000000000 -0400 +@@ -239,7 +239,8 @@ + "usage: named [-4|-6] [-c conffile] [-d debuglevel] " + "[-f|-g] [-n number_of_cpus]\n" + " [-p port] [-s] [-t chrootdir] [-u username]\n" +- " [-m {usage|trace|record}]\n"); ++ " [-m {usage|trace|record}]\n" ++ " [-D ]\n"); + } + + static void +@@ -345,7 +346,7 @@ + + isc_commandline_errprint = ISC_FALSE; + while ((ch = isc_commandline_parse(argc, argv, +- "46c:C:d:fgi:lm:n:N:p:P:st:u:vx:")) != -1) { ++ "46c:C:d:fgi:lm:n:N:p:P:st:u:vx:D")) != -1) { + switch (ch) { + case '4': + if (disable4) +@@ -434,6 +435,9 @@ + case 'v': + printf("BIND %s\n", ns_g_version); + exit(0); ++ case 'D': ++ ns_g_dbus = 1; ++ break; + case '?': + usage(); + ns_main_earlyfatal("unknown option '-%c'", +--- bind-9.3.2b1/bin/named/server.c.dbus 2005-07-26 22:53:15.000000000 -0400 ++++ bind-9.3.2b1/bin/named/server.c 2005-10-07 12:43:26.000000000 -0400 +@@ -86,6 +86,8 @@ + #include <stdlib.h> + #endif + ++#include <named/dbus_mgr.h> ++ + /* + * Check an operation for failure. Assumes that the function + * using it has a 'result' variable and a 'cleanup' label. +@@ -1496,12 +1498,12 @@ + if (result != ISC_R_SUCCESS) { + char namebuf[DNS_NAME_FORMATSIZE]; + dns_name_format(origin, namebuf, sizeof(namebuf)); +- cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING, +- "could not set up forwarding for domain '%s': %s", ++ cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_NOTICE, ++ "setting up forwarding failed for domain '%s': %s", + namebuf, isc_result_totext(result)); + goto cleanup; + } +- ++ + result = ISC_R_SUCCESS; + + cleanup: +@@ -2873,6 +2875,20 @@ + + CHECKFATAL(load_zones(server, ISC_FALSE), "loading zones"); + ++ server->dbus_mgr = 0L; ++ if( ns_g_dbus ) ++ if( dbus_mgr_create ++ ( ns_g_mctx, ns_g_taskmgr, ns_g_socketmgr, ns_g_timermgr, ++ &server->dbus_mgr ++ ) != ISC_R_SUCCESS ++ ) ++ { ++ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, ++ NS_LOGMODULE_SERVER, ISC_LOG_WARNING, ++ "dbus_mgr initialization failed. D-BUS service is disabled." ++ ); ++ } ++ + ns_os_started(); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, + ISC_LOG_NOTICE, "running"); +@@ -2935,6 +2951,9 @@ + + dns_db_detach(&server->in_roothints); + ++ if( server->dbus_mgr != 0L ) ++ dbus_mgr_shutdown(server->dbus_mgr); ++ + isc_task_endexclusive(server->task); + + isc_task_detach(&server->task); +--- bind-9.3.2b1/bin/named/include/named/globals.h.dbus 2004-03-07 23:04:20.000000000 -0500 ++++ bind-9.3.2b1/bin/named/include/named/globals.h 2005-10-07 13:47:36.000000000 -0400 +@@ -112,6 +112,8 @@ + + EXTERN int ns_g_listen INIT(3); + ++EXTERN int ns_g_dbus INIT(0); ++ + #undef EXTERN + #undef INIT + +--- bind-9.3.2b1/bin/named/include/named/server.h.dbus 2004-03-07 23:04:21.000000000 -0500 ++++ bind-9.3.2b1/bin/named/include/named/server.h 2005-10-07 12:43:26.000000000 -0400 +@@ -91,7 +91,8 @@ + ns_controls_t * controls; /* Control channels */ + unsigned int dispatchgen; + ns_dispatchlist_t dispatches; +- ++ ++ ns_dbus_mgr_t * dbus_mgr; + }; + + #define NS_SERVER_MAGIC ISC_MAGIC('S','V','E','R') +--- bind-9.3.2b1/bin/named/include/named/log.h.dbus 2004-03-07 23:04:21.000000000 -0500 ++++ bind-9.3.2b1/bin/named/include/named/log.h 2005-10-07 12:43:26.000000000 -0400 +@@ -34,6 +34,7 @@ + #define NS_LOGCATEGORY_QUERIES (&ns_g_categories[4]) + #define NS_LOGCATEGORY_UNMATCHED (&ns_g_categories[5]) + #define NS_LOGCATEGORY_UPDATE_SECURITY (&ns_g_categories[6]) ++#define NS_LOGCATEGORY_DBUS (&ns_g_categories[7]) + + /* + * Backwards compatibility. +@@ -51,6 +52,7 @@ + #define NS_LOGMODULE_NOTIFY (&ns_g_modules[8]) + #define NS_LOGMODULE_CONTROL (&ns_g_modules[9]) + #define NS_LOGMODULE_LWRESD (&ns_g_modules[10]) ++#define NS_LOGMODULE_DBUS (&ns_g_modules[11]) + + isc_result_t + ns_log_init(isc_boolean_t safe); +--- bind-9.3.2b1/bin/named/include/named/types.h.dbus 2004-03-06 05:21:26.000000000 -0500 ++++ bind-9.3.2b1/bin/named/include/named/types.h 2005-10-07 12:43:26.000000000 -0400 +@@ -38,4 +38,6 @@ + typedef struct ns_dispatch ns_dispatch_t; + typedef ISC_LIST(ns_dispatch_t) ns_dispatchlist_t; + ++typedef struct ns_dbus_mgr ns_dbus_mgr_t ; ++ + #endif /* NAMED_TYPES_H */ diff --git a/contrib/dbus/bind-9.3.3rc2-dbus.patch b/contrib/dbus/bind-9.3.3rc2-dbus.patch new file mode 100644 index 0000000..9048db7 --- /dev/null +++ b/contrib/dbus/bind-9.3.3rc2-dbus.patch @@ -0,0 +1,778 @@ +--- bind-9.3.3rc2/lib/dns/forward.c.dbus 2005-03-17 04:58:30.000000000 +0100 ++++ bind-9.3.3rc2/lib/dns/forward.c 2006-09-18 10:08:37.000000000 +0200 +@@ -200,3 +200,89 @@ + } + isc_mem_put(fwdtable->mctx, forwarders, sizeof(dns_forwarders_t)); + } ++ ++/*** ++ *** new D-BUS Dynamic Forwarding Zones functions: ++ ***/ ++isc_result_t ++dns_fwdtable_delete(dns_fwdtable_t *fwdtable, dns_name_t *name ) ++{ ++ isc_result_t result; ++ ++ REQUIRE(VALID_FWDTABLE(fwdtable)); ++ ++ RWLOCK(&fwdtable->rwlock, isc_rwlocktype_write); ++ ++ result = dns_rbt_deletename(fwdtable->table, name, ISC_FALSE); ++ ++ RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_write); ++ ++ return (result); ++} ++ ++isc_result_t ++dns_fwdtable_find_closest(dns_fwdtable_t *fwdtable, ++ dns_name_t *name, ++ dns_name_t *foundname, ++ dns_forwarders_t **forwardersp) ++{ ++ isc_result_t result; ++ ++ REQUIRE(VALID_FWDTABLE(fwdtable)); ++ ++ RWLOCK(&fwdtable->rwlock, isc_rwlocktype_read); ++ ++ result = dns_rbt_findname(fwdtable->table, name, 0, foundname, ++ (void **)forwardersp); ++ ++ if(result == DNS_R_PARTIALMATCH) ++ result = ISC_R_SUCCESS; ++ ++ RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_read); ++ ++ return (result); ++} ++ ++isc_result_t ++dns_fwdtable_find_exact(dns_fwdtable_t *fwdtable, dns_name_t *name, ++ dns_forwarders_t **forwardersp) ++{ ++ isc_result_t result; ++ ++ REQUIRE(VALID_FWDTABLE(fwdtable)); ++ ++ REQUIRE(forwardersp != 0L); ++ ++ RWLOCK(&fwdtable->rwlock, isc_rwlocktype_read); ++ ++ result = dns_rbt_findname(fwdtable->table, name, 0, NULL, ++ (void **)forwardersp); ++ ++ if( result != ISC_R_SUCCESS ) ++ *forwardersp = 0L; ++ ++ RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_read); ++ ++ return (result); ++} ++ ++static ++void dns_fwdtable_traverse ++( ++ dns_name_t *name, ++ void *node_data, ++ void *cbp, ++ void *cb_arg ++) ++{ ++ dns_fwdtable_callback_t cb = (dns_fwdtable_callback_t) cbp; ++ ++ (*cb)( name, node_data, cb_arg); ++} ++ ++void dns_fwdtable_foreach(dns_fwdtable_t *fwdtable, dns_fwdtable_callback_t cb, void *cb_arg ) ++{ ++ REQUIRE(VALID_FWDTABLE(fwdtable)); ++ ++ dns_rbt_traverse( fwdtable->table, dns_fwdtable_traverse, cb, cb_arg ); ++} +--- bind-9.3.3rc2/lib/dns/include/dns/forward.h.dbus 2005-03-17 04:58:31.000000000 +0100 ++++ bind-9.3.3rc2/lib/dns/include/dns/forward.h 2006-09-18 10:08:37.000000000 +0200 +@@ -98,6 +98,37 @@ + * all memory associated with the forwarding table is freed. + */ + ++ ++/* These are ONLY used by dbus_mgr : ++ */ ++ ++isc_result_t ++dns_fwdtable_delete( dns_fwdtable_t *fwdtable, dns_name_t *name ); ++/* ++ * Removes an entry from the forwarding table. ++ */ ++ ++isc_result_t ++dns_fwdtable_find_exact(dns_fwdtable_t *fwdtable, dns_name_t *name, ++ dns_forwarders_t **forwardersp); ++/* ++ * Finds an exact match for "name" in the forwarding table. ++ */ ++ ++isc_result_t ++dns_fwdtable_find_closest(dns_fwdtable_t *fwdtable, dns_name_t *name, dns_name_t *foundname, ++ dns_forwarders_t **forwardersp); ++/* ++ * Finds the closest match for "*name" in the forwarding table, returning ++ * the actual name matching in *name if different to *name passed in. ++ */ ++ ++typedef void (*dns_fwdtable_callback_t)( dns_name_t *, dns_forwarders_t *, void *); ++void dns_fwdtable_foreach(dns_fwdtable_t *fwdtable, dns_fwdtable_callback_t cb, void * ); ++/* Invoke cb for each member of fwdtable ++ */ ++ ++ + ISC_LANG_ENDDECLS + + #endif /* DNS_FORWARD_H */ +--- bind-9.3.3rc2/lib/dns/include/dns/rbt.h.dbus 2004-10-11 07:55:51.000000000 +0200 ++++ bind-9.3.3rc2/lib/dns/include/dns/rbt.h 2006-09-18 10:08:37.000000000 +0200 +@@ -833,6 +833,17 @@ + * <something_else> Any error result from dns_name_concatenate. + */ + ++ ++typedef void (*dns_rbt_traverse_callback_t)( dns_name_t *name, ++ void *node_data, ++ void *cb_arg1, ++ void *cb_arg2); ++ ++void dns_rbt_traverse( dns_rbt_t *rbt, dns_rbt_traverse_callback_t cb, void *cb_arg1, void *cb_arg2 ); ++/* tree traversal function (only used by D-BUS dynamic forwarding dbus_mgr at ++ * the moment) ++ */ ++ + ISC_LANG_ENDDECLS + + #endif /* DNS_RBT_H */ +--- bind-9.3.3rc2/lib/dns/rbt.c.dbus 2005-06-18 03:03:24.000000000 +0200 ++++ bind-9.3.3rc2/lib/dns/rbt.c 2006-09-18 10:08:37.000000000 +0200 +@@ -2172,6 +2172,47 @@ + dns_rbt_printtree(rbt->root, NULL, 0); + } + ++static void ++dns_rbt_traverse_tree(dns_rbtnode_t *root, dns_rbt_traverse_callback_t cb, void *cb_arg1, void *cb_arg2 ) { ++/* ++ * This is used ONLY to traverse the forward table by dbus_mgr at the moment. ++ * Since the forward table is not likely to be large, this can be recursive. ++ */ ++ dns_name_t name; ++ dns_offsets_t offsets; ++ char buf[DNS_NAME_MAXWIRE]; ++ isc_buffer_t buffer; ++ ++ if (root != NULL) { ++ ++ if (DOWN(root)) ++ dns_rbt_traverse_tree(DOWN(root), cb, cb_arg1, cb_arg2); ++ ++ if( LEFT(root) != NULL ) ++ dns_rbt_traverse_tree(LEFT(root), cb, cb_arg1, cb_arg2); ++ ++ if( RIGHT(root) != NULL ) ++ dns_rbt_traverse_tree(RIGHT(root), cb, cb_arg1, cb_arg2); ++ ++ if( DATA(root) == 0L ) ++ return; ++ ++ dns_name_init(&name, offsets); ++ isc_buffer_init(&buffer, buf, DNS_NAME_MAXWIRE); ++ dns_name_setbuffer( &name, &buffer); ++ dns_rbt_fullnamefromnode(root, &name); ++ ++ (*cb)(&name, DATA(root), cb_arg1, cb_arg2); ++ } ++} ++ ++void dns_rbt_traverse( dns_rbt_t *rbt, dns_rbt_traverse_callback_t cb, void *cb_arg1, void *cb_arg2 ) ++{ ++ REQUIRE(VALID_RBT(rbt)); ++ ++ dns_rbt_traverse_tree( rbt->root, cb, cb_arg1, cb_arg2 ); ++} ++ + /* + * Chain Functions + */ +--- bind-9.3.3rc2/lib/isc/include/isc/socket.h.dbus 2004-03-08 10:04:53.000000000 +0100 ++++ bind-9.3.3rc2/lib/isc/include/isc/socket.h 2006-09-18 10:08:37.000000000 +0200 +@@ -136,6 +136,10 @@ + #define ISC_SOCKEVENT_NEWCONN (ISC_EVENTCLASS_SOCKET + 3) + #define ISC_SOCKEVENT_CONNECT (ISC_EVENTCLASS_SOCKET + 4) + ++#define ISC_SOCKEVENT_READ_READY (ISC_EVENTCLASS_SOCKET + 5) ++#define ISC_SOCKEVENT_WRITE_READY (ISC_EVENTCLASS_SOCKET + 6) ++#define ISC_SOCKEVENT_SELECTED (ISC_EVENTCLASS_SOCKET + 7) ++ + /* + * Internal events. + */ +@@ -144,7 +148,8 @@ + + typedef enum { + isc_sockettype_udp = 1, +- isc_sockettype_tcp = 2 ++ isc_sockettype_tcp = 2, ++ isc_sockettype_fd = 8 + } isc_sockettype_t; + + /* +@@ -699,6 +704,30 @@ + * 'sock' is a valid socket. + */ + ++isc_socketevent_t* ++isc_socket_fd_handle_reads( isc_socket_t *sock, isc_socketevent_t *dev ); ++/* register the "dev" event to be sent when the isc_sockettype_fd sock ++ * was select()-ed for read. If there is already an event registered, it ++ * is returned, otherwise 0 is returned. If dev is 0, removes any existing ++ * registered event. ++ */ ++ ++isc_socketevent_t* ++isc_socket_fd_handle_writes( isc_socket_t *sock, isc_socketevent_t *dev ); ++/* register the "dev" event to be sent when the isc_sockettype_fd sock ++ * was select()-ed for write. If there is already an event registered, it ++ * is returned, otherwise 0 is returned. If dev is 0, removes any existing ++ * registered event. ++ */ ++ ++isc_socketevent_t* ++isc_socket_fd_handle_selected( isc_socket_t *sock, isc_socketevent_t *dev ); ++/* register the "dev" event to be sent when ALL isc_sockettype_fd sockets ++ * have been select()-ed . If there is already an event registered, it ++ * is returned, otherwise 0 is returned. If dev is 0, removes any existing ++ * registered event. ++ */ ++ + ISC_LANG_ENDDECLS + + #endif /* ISC_SOCKET_H */ +--- bind-9.3.3rc2/lib/isc/unix/socket.c.dbus 2006-05-19 04:53:36.000000000 +0200 ++++ bind-9.3.3rc2/lib/isc/unix/socket.c 2006-09-18 10:08:37.000000000 +0200 +@@ -148,6 +148,11 @@ + ISC_LIST(isc_socketevent_t) recv_list; + ISC_LIST(isc_socket_newconnev_t) accept_list; + isc_socket_connev_t *connect_ev; ++ ++ /* these are used only by isc_sockettype_fd sockets:*/ ++ isc_socketevent_t *read_ready_event; ++ isc_socketevent_t *write_ready_event; ++ isc_socketevent_t *selected_event; + + /* + * Internal events. Posted when a descriptor is readable or +@@ -304,7 +309,7 @@ + + static void + wakeup_socket(isc_socketmgr_t *manager, int fd, int msg) { +- isc_socket_t *sock; ++ isc_socket_t *sock=0L; + + /* + * This is a wakeup on a socket. If the socket is not in the +@@ -1289,6 +1294,9 @@ + sock->connected = 0; + sock->connecting = 0; + sock->bound = 0; ++ sock->read_ready_event = 0L; ++ sock->write_ready_event = 0L; ++ sock->selected_event = 0L; + + /* + * initialize the lock +@@ -1401,13 +1409,16 @@ + case isc_sockettype_tcp: + sock->fd = socket(pf, SOCK_STREAM, IPPROTO_TCP); + break; ++ ++ case isc_sockettype_fd: ++ sock->fd = pf; + } + + #ifdef F_DUPFD + /* + * Leave a space for stdio to work in. + */ +- if (sock->fd >= 0 && sock->fd < 20) { ++ if ( (type != isc_sockettype_fd) && (sock->fd >= 0) && (sock->fd < 20) ) { + int new, tmp; + new = fcntl(sock->fd, F_DUPFD, 20); + tmp = errno; +@@ -1461,7 +1472,7 @@ + } + } + +- if (make_nonblock(sock->fd) != ISC_R_SUCCESS) { ++ if ((type != isc_sockettype_fd) && (make_nonblock(sock->fd) != ISC_R_SUCCESS)) { + (void)close(sock->fd); + free_socket(&sock); + return (ISC_R_UNEXPECTED); +@@ -1729,6 +1740,38 @@ + isc_task_send(ev->ev_sender, (isc_event_t **)&iev); + } + ++static ++isc_event_t *dispatch_read_ready(isc_socketmgr_t *manager, isc_socket_t *sock) ++{ ++ isc_event_t *dev = (isc_event_t*)sock->read_ready_event, *ev; ++ ++ ev = isc_mem_get(manager->mctx, dev->ev_size); ++ memcpy(ev,dev,dev->ev_size); ++ ISC_LINK_INIT(ev,ev_link); ++ isc_task_send(dev->ev_sender, &ev ); ++ return (isc_event_t *)sock->selected_event; ++} ++ ++static ++isc_event_t *dispatch_write_ready(isc_socketmgr_t *manager,isc_socket_t *sock) ++{ ++ isc_event_t *dev = (isc_event_t*)sock->write_ready_event, *ev; ++ ev = isc_mem_get(manager->mctx, dev->ev_size); ++ memcpy(ev,dev,dev->ev_size); ++ ISC_LINK_INIT(ev,ev_link); ++ isc_task_send(dev->ev_sender, &ev ); ++ return (isc_event_t *)sock->selected_event; ++} ++ ++static ++void dispatch_selected(isc_socketmgr_t *manager, isc_event_t *dev) ++{ isc_event_t *ev; ++ ev = isc_mem_get(manager->mctx, dev->ev_size); ++ memcpy(ev,dev,dev->ev_size); ++ ISC_LINK_INIT(ev,ev_link); ++ isc_task_send(dev->ev_sender, &ev ); ++} ++ + /* + * Dequeue an item off the given socket's read queue, set the result code + * in the done event to the one provided, and send it to the task it was +@@ -2136,6 +2179,7 @@ + int i; + isc_socket_t *sock; + isc_boolean_t unlock_sock; ++ isc_event_t *sock_selected = 0L; + + REQUIRE(maxfd <= (int)FD_SETSIZE); + +@@ -2169,11 +2213,15 @@ + unlock_sock = ISC_TRUE; + LOCK(&sock->lock); + if (!SOCK_DEAD(sock)) { ++ if( sock->type != isc_sockettype_fd ) ++ { + if (sock->listener) + dispatch_accept(sock); + else + dispatch_recv(sock); +- } ++ }else ++ sock_selected = dispatch_read_ready(manager,sock); ++ } + FD_CLR(i, &manager->read_fds); + } + check_write: +@@ -2187,16 +2235,24 @@ + LOCK(&sock->lock); + } + if (!SOCK_DEAD(sock)) { ++ if( sock->type != isc_sockettype_fd ) ++ { + if (sock->connecting) + dispatch_connect(sock); + else + dispatch_send(sock); ++ }else ++ sock_selected = dispatch_write_ready(manager,sock); + } + FD_CLR(i, &manager->write_fds); + } + if (unlock_sock) + UNLOCK(&sock->lock); + } ++ if( sock_selected != 0L ) ++ { ++ dispatch_selected(manager, sock_selected); ++ } + } + + #ifdef ISC_PLATFORM_USETHREADS +@@ -2215,7 +2271,7 @@ + int cc; + fd_set readfds; + fd_set writefds; +- int msg, fd; ++ int msg, fd = -1; + int maxfd; + char strbuf[ISC_STRERRORSIZE]; + +@@ -3546,3 +3602,55 @@ + return (ISC_R_SUCCESS); + } + #endif /* ISC_PLATFORM_USETHREADS */ ++ ++isc_socketevent_t* ++isc_socket_fd_handle_reads( isc_socket_t *sock, isc_socketevent_t *dev ) ++{ ++ REQUIRE(VALID_SOCKET(sock)); ++ if(dev != 0L) ++ { ++ sock->references=1; ++ sock->read_ready_event = dev; ++ select_poke(sock->manager, sock->fd, SELECT_POKE_READ); ++ }else ++ { ++ dev = sock->read_ready_event ; ++ sock->read_ready_event = 0L ; ++ } ++ return dev; ++} ++ ++isc_socketevent_t* ++isc_socket_fd_handle_writes( isc_socket_t *sock, isc_socketevent_t *dev ) ++{ ++ REQUIRE(VALID_SOCKET(sock)); ++ if(dev != 0L) ++ { ++ sock->references=1; ++ sock->write_ready_event = dev; ++ select_poke(sock->manager, sock->fd, SELECT_POKE_WRITE); ++ }else ++ { ++ dev = sock->write_ready_event; ++ sock->write_ready_event = 0L; ++ } ++ return dev; ++} ++ ++isc_socketevent_t* ++isc_socket_fd_handle_selected( isc_socket_t *sock, isc_socketevent_t *dev ) ++{ ++ REQUIRE(VALID_SOCKET(sock)); ++ if(dev != 0L) ++ { ++ sock->references=1; ++ sock->selected_event = dev; ++ }else ++ { ++ dev = sock->selected_event; ++ sock->selected_event = 0L; ++ sock->references=0; ++ destroy(&sock); ++ } ++ return dev; ++} +--- bind-9.3.3rc2/bin/named/named.8.dbus 2006-06-29 15:02:30.000000000 +0200 ++++ bind-9.3.3rc2/bin/named/named.8 2006-09-18 10:08:37.000000000 +0200 +@@ -33,7 +33,7 @@ + named \- Internet domain name server + .SH "SYNOPSIS" + .HP 6 +-\fBnamed\fR [\fB\-4\fR] [\fB\-6\fR] [\fB\-c\ \fR\fB\fIconfig\-file\fR\fR] [\fB\-d\ \fR\fB\fIdebug\-level\fR\fR] [\fB\-f\fR] [\fB\-g\fR] [\fB\-n\ \fR\fB\fI#cpus\fR\fR] [\fB\-p\ \fR\fB\fIport\fR\fR] [\fB\-s\fR] [\fB\-t\ \fR\fB\fIdirectory\fR\fR] [\fB\-u\ \fR\fB\fIuser\fR\fR] [\fB\-v\fR] [\fB\-x\ \fR\fB\fIcache\-file\fR\fR] ++\fBnamed\fR [\fB\-4\fR] [\fB\-6\fR] [\fB\-c\ \fR\fB\fIconfig\-file\fR\fR] [\fB\-d\ \fR\fB\fIdebug\-level\fR\fR] [\fB\-f\fR] [\fB\-g\fR] [\fB\-n\ \fR\fB\fI#cpus\fR\fR] [\fB\-p\ \fR\fB\fIport\fR\fR] [\fB\-s\fR] [\fB\-t\ \fR\fB\fIdirectory\fR\fR] [\fB\-u\ \fR\fB\fIuser\fR\fR] [\fB\-v\fR] [\fB\-x\ \fR\fB\fIcache\-file\fR\fR] [\fB\-D\fR] + .SH "DESCRIPTION" + .PP + \fBnamed\fR +@@ -146,6 +146,13 @@ + .B "Warning:" + This option must not be used. It is only of interest to BIND 9 developers and may be removed or changed in a future release. + .RE ++.sp ++.TP ++\fB\-D\fR ++Enable dynamic management of the forwarding table with D-BUS ++messages. This option is required for Red Hat NetworkManager ++support. See doc/README.DBUS . ++.sp + .SH "SIGNALS" + .PP + In routine operation, signals should not be used to control the nameserver; +@@ -165,6 +172,73 @@ + \fBnamed\fR + configuration file is too complex to describe in detail here. A complete description is provided in the + BIND 9 Administrator Reference Manual. ++.PP ++.SH "NOTES" ++.PP ++.TP ++\fBRed Hat SELinux BIND Security Profile:\fR ++.PP ++By default, Red Hat ships BIND with the most secure SELinux policy ++that will not prevent normal BIND operation and will prevent exploitation ++of all known BIND security vulnerabilities . See the selinux(8) man page ++for information about SElinux. ++.PP ++It is not necessary to run named in a chroot environment if the Red Hat ++SELinux policy for named is enabled. When enabled, this policy is far ++more secure than a chroot environment. ++.PP ++With this extra security comes some restrictions: ++.br ++By default, the SELinux policy does not allow named to write any master ++zone database files. Only the root user may create files in the $ROOTDIR/var/named ++zone database file directory (the options { "directory" } option), where ++$ROOTDIR is set in /etc/sysconfig/named. ++.br ++The "named" group must be granted read privelege to ++these files in order for named to be enabled to read them. ++.br ++Any file created in the zone database file directory is automatically assigned ++the SELinux file context named_zone_t . ++.br ++By default, SELinux prevents any role from modifying named_zone_t files; this ++means that files in the zone database directory cannot be modified by dynamic ++DNS (DDNS) updates or zone transfers. ++.br ++The Red Hat BIND distribution and SELinux policy creates two directories where ++named is allowed to create and modify files: $ROOTDIR/var/named/slaves and ++$ROOTDIR/var/named/data. By placing files you want named to modify, such as ++slave or DDNS updateable zone files and database / statistics dump files in ++these directories, named will work normally and no further operator action is ++required. Files in these directories are automatically assigned the 'named_cache_t' ++file context, which SELinux allows named to write. ++.br ++You can enable the named_t domain to write and create named_zone_t files by use ++of the SELinux tunable boolean variable "named_write_master_zones", using the ++setsebool(8) command or the system-config-security GUI . If you do this, you ++must also set the ENABLE_ZONE_WRITE variable in /etc/sysconfig/named to ++1 / yes to set the ownership of files in the $ROOTDIR/var/named directory ++to named:named in order for named to be allowed to write them. ++.PP ++\fBRed Hat BIND named_sdb SDB support:\fR ++.PP ++Red Hat ships the bind-sdb RPM that provides the /usr/sbin/named_sdb program, ++which is named compiled with the Simplified Database Backend modules that ISC ++provides in the "contrib/sdb" directory. ++.br ++The SDB modules for LDAP, PostGreSQL and DirDB are compiled into named_sdb. ++.br ++To run named_sdb, set the ENABLE_SDB variable in /etc/sysconfig/named to 1 or "yes", ++and then the "service named start" named initscript will run named_sdb instead ++of named . ++.br ++See the documentation for the various SDB modules in /usr/share/doc/bind-sdb-*/ . ++.PP ++\fBRed Hat system-config-bind:\fR ++.PP ++Red Hat provides the system-config-bind GUI to configure named.conf and zone ++database files. Run the "system-config-bind" command and access the manual ++by selecting the Help menu. ++.PP + .SH "FILES" + .TP 3n + \fI/etc/named.conf\fR +--- bind-9.3.3rc2/bin/named/include/named/globals.h.dbus 2006-03-02 01:37:20.000000000 +0100 ++++ bind-9.3.3rc2/bin/named/include/named/globals.h 2006-09-18 10:08:37.000000000 +0200 +@@ -112,6 +112,8 @@ + + EXTERN int ns_g_listen INIT(3); + ++EXTERN int ns_g_dbus INIT(0); ++ + #undef EXTERN + #undef INIT + +--- bind-9.3.3rc2/bin/named/include/named/log.h.dbus 2004-03-08 05:04:21.000000000 +0100 ++++ bind-9.3.3rc2/bin/named/include/named/log.h 2006-09-18 10:08:37.000000000 +0200 +@@ -34,6 +34,7 @@ + #define NS_LOGCATEGORY_QUERIES (&ns_g_categories[4]) + #define NS_LOGCATEGORY_UNMATCHED (&ns_g_categories[5]) + #define NS_LOGCATEGORY_UPDATE_SECURITY (&ns_g_categories[6]) ++#define NS_LOGCATEGORY_DBUS (&ns_g_categories[7]) + + /* + * Backwards compatibility. +@@ -51,6 +52,7 @@ + #define NS_LOGMODULE_NOTIFY (&ns_g_modules[8]) + #define NS_LOGMODULE_CONTROL (&ns_g_modules[9]) + #define NS_LOGMODULE_LWRESD (&ns_g_modules[10]) ++#define NS_LOGMODULE_DBUS (&ns_g_modules[11]) + + isc_result_t + ns_log_init(isc_boolean_t safe); +--- bind-9.3.3rc2/bin/named/include/named/server.h.dbus 2006-03-02 01:37:20.000000000 +0100 ++++ bind-9.3.3rc2/bin/named/include/named/server.h 2006-09-18 10:08:37.000000000 +0200 +@@ -91,7 +91,8 @@ + ns_controls_t * controls; /* Control channels */ + unsigned int dispatchgen; + ns_dispatchlist_t dispatches; +- ++ ++ ns_dbus_mgr_t * dbus_mgr; + }; + + #define NS_SERVER_MAGIC ISC_MAGIC('S','V','E','R') +--- bind-9.3.3rc2/bin/named/include/named/types.h.dbus 2004-03-06 11:21:26.000000000 +0100 ++++ bind-9.3.3rc2/bin/named/include/named/types.h 2006-09-18 10:08:37.000000000 +0200 +@@ -38,4 +38,6 @@ + typedef struct ns_dispatch ns_dispatch_t; + typedef ISC_LIST(ns_dispatch_t) ns_dispatchlist_t; + ++typedef struct ns_dbus_mgr ns_dbus_mgr_t ; ++ + #endif /* NAMED_TYPES_H */ +--- bind-9.3.3rc2/bin/named/log.c.dbus 2005-05-25 01:58:17.000000000 +0200 ++++ bind-9.3.3rc2/bin/named/log.c 2006-09-18 10:08:37.000000000 +0200 +@@ -41,6 +41,7 @@ + { "queries", 0 }, + { "unmatched", 0 }, + { "update-security", 0 }, ++ { "dbus", 0 }, + { NULL, 0 } + }; + +@@ -60,6 +61,7 @@ + { "notify", 0 }, + { "control", 0 }, + { "lwresd", 0 }, ++ { "dbus", 0 }, + { NULL, 0 } + }; + +--- bind-9.3.3rc2/bin/named/main.c.dbus 2006-01-06 01:01:42.000000000 +0100 ++++ bind-9.3.3rc2/bin/named/main.c 2006-09-18 10:08:37.000000000 +0200 +@@ -239,7 +239,8 @@ + "usage: named [-4|-6] [-c conffile] [-d debuglevel] " + "[-f|-g] [-n number_of_cpus]\n" + " [-p port] [-s] [-t chrootdir] [-u username]\n" +- " [-m {usage|trace|record}]\n"); ++ " [-m {usage|trace|record}]\n" ++ " [-D ]\n"); + } + + static void +@@ -345,7 +346,7 @@ + + isc_commandline_errprint = ISC_FALSE; + while ((ch = isc_commandline_parse(argc, argv, +- "46c:C:d:fgi:lm:n:N:p:P:st:u:vx:")) != -1) { ++ "46c:C:d:fgi:lm:n:N:p:P:st:u:vx:D")) != -1) { + switch (ch) { + case '4': + if (disable4) +@@ -434,6 +435,9 @@ + case 'v': + printf("BIND %s\n", ns_g_version); + exit(0); ++ case 'D': ++ ns_g_dbus = 1; ++ break; + case '?': + usage(); + ns_main_earlyfatal("unknown option '-%c'", +--- bind-9.3.3rc2/bin/named/server.c.dbus 2006-05-24 06:30:24.000000000 +0200 ++++ bind-9.3.3rc2/bin/named/server.c 2006-09-18 10:08:37.000000000 +0200 +@@ -86,6 +86,8 @@ + #include <stdlib.h> + #endif + ++#include <named/dbus_mgr.h> ++ + /* + * Check an operation for failure. Assumes that the function + * using it has a 'result' variable and a 'cleanup' label. +@@ -1495,12 +1497,12 @@ + if (result != ISC_R_SUCCESS) { + char namebuf[DNS_NAME_FORMATSIZE]; + dns_name_format(origin, namebuf, sizeof(namebuf)); +- cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING, +- "could not set up forwarding for domain '%s': %s", ++ cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_NOTICE, ++ "setting up forwarding failed for domain '%s': %s", + namebuf, isc_result_totext(result)); + goto cleanup; + } +- ++ + result = ISC_R_SUCCESS; + + cleanup: +@@ -2875,6 +2877,20 @@ + + CHECKFATAL(load_zones(server, ISC_FALSE), "loading zones"); + ++ server->dbus_mgr = 0L; ++ if( ns_g_dbus ) ++ if( dbus_mgr_create ++ ( ns_g_mctx, ns_g_taskmgr, ns_g_socketmgr, ns_g_timermgr, ++ &server->dbus_mgr ++ ) != ISC_R_SUCCESS ++ ) ++ { ++ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, ++ NS_LOGMODULE_SERVER, ISC_LOG_WARNING, ++ "dbus_mgr initialization failed. D-BUS service is disabled." ++ ); ++ } ++ + ns_os_started(); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, + ISC_LOG_NOTICE, "running"); +@@ -2937,6 +2953,9 @@ + + dns_db_detach(&server->in_roothints); + ++ if( server->dbus_mgr != 0L ) ++ dbus_mgr_shutdown(server->dbus_mgr); ++ + isc_task_endexclusive(server->task); + + isc_task_detach(&server->task); +--- bind-9.3.3rc2/bin/named/Makefile.in.dbus 2004-09-06 23:47:25.000000000 +0200 ++++ bind-9.3.3rc2/bin/named/Makefile.in 2006-09-18 10:10:58.000000000 +0200 +@@ -35,7 +35,8 @@ + ${LWRES_INCLUDES} ${DNS_INCLUDES} ${BIND9_INCLUDES} \ + ${ISCCFG_INCLUDES} ${ISCCC_INCLUDES} ${ISC_INCLUDES} \ + ${DBDRIVER_INCLUDES} +- ++DBUS_INCLUDES = \ ++ -I/usr/lib/dbus-1.0/include -I/usr/include/dbus-1.0 + CDEFINES = + CWARNINGS = + +@@ -52,6 +53,7 @@ + ISCDEPLIBS = ../../lib/isc/libisc.@A@ + LWRESDEPLIBS = ../../lib/lwres/liblwres.@A@ + BIND9DEPLIBS = ../../lib/bind9/libbind9.@A@ ++DBUSLIBS= -ldbus-1 + + DEPLIBS = ${LWRESDEPLIBS} ${DNSDEPLIBS} ${BIND9DEPLIBS} \ + ${ISCCFGDEPLIBS} ${ISCCCDEPLIBS} ${ISCDEPLIBS} +@@ -71,6 +73,7 @@ + zoneconf.@O@ \ + lwaddr.@O@ lwresd.@O@ lwdclient.@O@ lwderror.@O@ lwdgabn.@O@ \ + lwdgnba.@O@ lwdgrbn.@O@ lwdnoop.@O@ lwsearch.@O@ \ ++ dbus_service.@O@ dbus_mgr.@O@ \ + $(DBDRIVER_OBJS) + + UOBJS = unix/os.@O@ +@@ -83,6 +86,7 @@ + zoneconf.c \ + lwaddr.c lwresd.c lwdclient.c lwderror.c lwdgabn.c \ + lwdgnba.c lwdgrbn.c lwdnoop.c lwsearch.c \ ++ dbus_service.c dbus_mgr.c \ + $(DBDRIVER_SRCS) + + MANPAGES = named.8 lwresd.8 named.conf.5 +@@ -105,9 +109,14 @@ + -DNS_LOCALSTATEDIR=\"${localstatedir}\" \ + -c ${srcdir}/config.c + ++dbus_service.o: dbus_service.c ++ ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} \ ++ ${DBUS_INCLUDES} \ ++ -c ${srcdir}/dbus_service.c ++ + named@EXEEXT@: ${OBJS} ${UOBJS} ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ +- ${OBJS} ${UOBJS} ${LIBS} ++ ${OBJS} ${UOBJS} ${LIBS} ${DBUSLIBS} + + lwresd@EXEEXT@: named@EXEEXT@ + rm -f lwresd@EXEEXT@ diff --git a/contrib/dbus/dbus_mgr.c b/contrib/dbus/dbus_mgr.c new file mode 100644 index 0000000..b744790 --- /dev/null +++ b/contrib/dbus/dbus_mgr.c @@ -0,0 +1,2458 @@ +/* dbus_mgr.c + * + * named module to provide dynamic forwarding zones in + * response to D-BUS dhcp events or commands. + * + * Copyright(C) Jason Vas Dias, Red Hat Inc., 2005 + * Modified by Adam Tkac, Red Hat Inc., 2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation at + * http://www.fsf.org/licensing/licenses/gpl.txt + * and included in this software distribution as the "LICENSE" file. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include <config.h> +#include <isc/types.h> +#include <isc/net.h> +#include <isc/mem.h> +#include <isc/magic.h> +#include <isc/list.h> +#include <isc/task.h> +#include <isc/event.h> +#include <isc/socket.h> +#include <isc/timer.h> +#include <isc/netaddr.h> +#include <isc/sockaddr.h> +#include <isc/buffer.h> +#include <isc/log.h> + +#include <dns/name.h> +#include <dns/acl.h> +#include <dns/fixedname.h> +#include <dns/view.h> +#include <dns/forward.h> + +#include <named/types.h> +#include <named/config.h> +#include <named/server.h> +#include <named/globals.h> +#include <named/log.h> + +#include <named/dbus_service.h> +#include <named/dbus_mgr.h> + +#include <string.h> +#include <search.h> + +typedef void (*__free_fn_t) (void *__nodep); +extern void tdestroy (void *__root, __free_fn_t __freefct); +extern void free(void*); + +#ifdef ISC_USE_INTERNAL_MALLOC +# if ISC_USE_INTERNAL_MALLOC +# error dbus_mgr cannot be used if ISC_USE_INTERNAL_MALLOC==1 +# endif +#endif + +#define DBUSMGR_DESTINATION "com.redhat.named" +#define DBUSMGR_OBJECT_PATH "/com/redhat/named" +#define DBUSMGR_INTERFACE "com.redhat.named" + +#define DBUSMGR_MAGIC ISC_MAGIC('D', 'B', 'U', 'S') + +struct ns_dbus_mgr +{ + unsigned int magic; + isc_mem_t * mctx; /* Memory context. */ + isc_taskmgr_t * taskmgr; /* Task manager. */ + isc_socketmgr_t * socketmgr; /* Socket manager. */ + isc_timermgr_t * timermgr; /* Timer manager. */ + isc_task_t * task; /* task */ + isc_timer_t * timer; /* dbus_init retry */ + void * sockets; /* dbus fd tree */ + void * dhc_if; /* dhcp interface tree */ + void * ifwdt; /* initial forwarder tree */ + char * dhcdbd_name; /* dhcdbd destination */ + DBUS_SVC dbus; /* dbus handle */ +}; + +typedef +struct dbus_mgr_sock_s +{ + int fd; + struct ns_dbus_mgr *mgr; + isc_socket_t *sock; + isc_socketevent_t *ser; + isc_socketevent_t *sew; + isc_socketevent_t *sel; +} DBusMgrSocket; + +typedef +enum dhc_state_e +{ + DHC_NBI, /* no broadcast interfaces found */ + DHC_PREINIT, /* configuration started */ + DHC_BOUND, /* lease obtained */ + DHC_RENEW, /* lease renewed */ + DHC_REBOOT, /* have valid lease, but now obtained a different one */ + DHC_REBIND, /* new, different lease */ + DHC_STOP, /* remove old lease */ + DHC_MEDIUM, /* media selection begun */ + DHC_TIMEOUT, /* timed out contacting DHCP server */ + DHC_FAIL, /* all attempts to contact server timed out, sleeping */ + DHC_EXPIRE, /* lease has expired, renewing */ + DHC_RELEASE, /* releasing lease */ + DHC_START, /* sent when dhclient started OK */ + DHC_ABEND, /* dhclient exited abnormally */ + DHC_END, /* dhclient exited normally */ + DHC_END_OPTIONS, /* last option in subscription sent */ + DHC_INVALID=255 +} DHC_State; + +typedef ISC_LIST(dns_name_t) DNSNameList; + +typedef ISC_LIST(isc_sockaddr_t) SockAddrList; + +typedef struct dbm_fwdr_s +{ + dns_fwdpolicy_t fwdpolicy; + dns_name_t dn; + SockAddrList sa; + ISC_LINK( struct dbm_fwdr_s ) link; +} DBusMgrInitialFwdr; + +typedef +struct dhc_if_s +{ + char *if_name; + DHC_State dhc_state; + DHC_State previous_state; + struct in_addr ip; + struct in_addr subnet_mask; + DNSNameList dn; + SockAddrList dns; +} DHC_IF; + +static void +dbus_mgr_watch_handler( int fd, dbus_svc_WatchFlags flags, void *mgrp ); + +static +dbus_svc_HandlerResult +dbus_mgr_message_handler +( + DBusMsgHandlerArgs +); + +static +void dbus_mgr_close_socket( const void *p, const VISIT which, const int level); + +static +void dbus_mgr_destroy_socket( void *p ); + +static +void dbus_mgr_free_dhc( void *p ); + +static void +dbus_mgr_watches_selected(isc_task_t *t, isc_event_t *ev); + +static isc_result_t +dbus_mgr_init_dbus(ns_dbus_mgr_t *); + +static isc_result_t +dbus_mgr_record_initial_fwdtable(ns_dbus_mgr_t *); + +static +dns_fwdtable_t *dbus_mgr_get_fwdtable(void); + +static void +dbus_mgr_free_initial_fwdtable(ns_dbus_mgr_t *); + +static +uint8_t dbus_mgr_subscribe_to_dhcdbd( ns_dbus_mgr_t * ); + +static +void dbus_mgr_dbus_shutdown_handler ( ns_dbus_mgr_t * ); + +static +int dbus_mgr_log_err( const char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + isc_log_vwrite(ns_g_lctx, + NS_LOGCATEGORY_DBUS, + NS_LOGMODULE_DBUS, + ISC_LOG_NOTICE, + fmt, va + ); + va_end(va); + return 0; +} + +static +int dbus_mgr_log_dbg( const char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + isc_log_vwrite(ns_g_lctx, + NS_LOGCATEGORY_DBUS, + NS_LOGMODULE_DBUS, + ISC_LOG_DEBUG(80), + fmt, va + ); + va_end(va); + return 0; +} + +static +int dbus_mgr_log_info( const char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + isc_log_vwrite(ns_g_lctx, + NS_LOGCATEGORY_DBUS, + NS_LOGMODULE_DBUS, + ISC_LOG_DEBUG(1), + fmt, va + ); + va_end(va); + return 0; +} + +isc_result_t +dbus_mgr_create +( isc_mem_t *mctx, + isc_taskmgr_t *taskmgr, + isc_socketmgr_t *socketmgr, + isc_timermgr_t *timermgr, + ns_dbus_mgr_t **dbus_mgr +) +{ + isc_result_t result; + ns_dbus_mgr_t *mgr; + + *dbus_mgr = 0L; + + mgr = isc_mem_get(mctx, sizeof(*mgr)); + if (mgr == NULL) + return (ISC_R_NOMEMORY); + + mgr->magic = DBUSMGR_MAGIC; + mgr->mctx = mctx; + mgr->taskmgr = taskmgr; + mgr->socketmgr = socketmgr; + mgr->timermgr = timermgr; + mgr->task = 0L; + mgr->sockets = 0L; + mgr->timer = 0L; + mgr->dhc_if = 0L; + mgr->ifwdt = 0L; + mgr->dhcdbd_name = 0L; + + if( (result = isc_task_create( taskmgr, 100, &(mgr->task))) + != ISC_R_SUCCESS + ) goto cleanup_mgr; + + isc_task_setname( mgr->task, "dbusmgr", mgr ); + + mgr->dbus = 0L; + + if( (result = dbus_mgr_record_initial_fwdtable( mgr )) + != ISC_R_SUCCESS + ) goto cleanup_mgr; + + if( (result = dbus_mgr_init_dbus( mgr )) + != ISC_R_SUCCESS + ) goto cleanup_mgr; + + *dbus_mgr = mgr; + + return ISC_R_SUCCESS; + + cleanup_mgr: + if ( dbus_mgr_get_fwdtable() != NULL) + dbus_mgr_free_initial_fwdtable (mgr); + if( mgr->task != 0L ) + isc_task_detach(&(mgr->task)); + isc_mem_put(mctx, mgr, sizeof(*mgr)); + return (result); +} + +static isc_result_t +dbus_mgr_init_dbus(ns_dbus_mgr_t * mgr) +{ + char destination[]=DBUSMGR_DESTINATION; + isc_result_t result; + + if( mgr->sockets != 0L ) + { + isc_task_purgerange(mgr->task, 0L, ISC_SOCKEVENT_READ_READY, ISC_SOCKEVENT_SELECTED, 0L); + twalk(mgr->sockets, dbus_mgr_close_socket); + tdestroy(mgr->sockets, dbus_mgr_destroy_socket); + mgr->sockets = 0L; + } + + if( mgr->dbus != 0L ) + { + dbus_svc_shutdown(mgr->dbus); + mgr->dbus = 0L; + } + + result = dbus_svc_init(DBUS_PRIVATE_SYSTEM, destination, &mgr->dbus, + dbus_mgr_watch_handler, 0L, 0L, mgr); + + if(result != ISC_R_SUCCESS) + goto cleanup; + + if( mgr->dbus == 0L ) + { + if( mgr->timer == 0L) + { + isc_task_purgerange(mgr->task, 0L, ISC_SOCKEVENT_READ_READY, ISC_SOCKEVENT_SELECTED, 0L); + if( mgr->sockets != 0L ) + { + twalk(mgr->sockets, dbus_mgr_close_socket); + tdestroy(mgr->sockets, dbus_mgr_destroy_socket); + mgr->sockets = 0L; + } + dbus_mgr_dbus_shutdown_handler ( mgr ); + return ISC_R_SUCCESS; + } + goto cleanup; + } + + if( !dbus_svc_add_filter + ( mgr->dbus, dbus_mgr_message_handler, mgr, 4, + "type=signal,path=/org/freedesktop/DBus,member=NameOwnerChanged", + "type=signal,path=/org/freedesktop/DBus/Local,member=Disconnected", + "type=signal,interface=com.redhat.dhcp.subscribe.binary", + "type=method_call,destination=com.redhat.named,path=/com/redhat/named" + ) + ) + { + dbus_mgr_log_err( "dbus_svc_add_filter failed" ); + goto cleanup; + } + + if( mgr->timer != 0L ) + { + isc_timer_reset(mgr->timer, + isc_timertype_inactive, + NULL, NULL, ISC_TRUE + ); + } + + if( !dbus_mgr_subscribe_to_dhcdbd( mgr ) ) + dbus_mgr_log_err("D-BUS dhcdbd subscription disabled."); + + dbus_mgr_log_err("D-BUS service enabled."); + return ISC_R_SUCCESS; + + cleanup: + isc_task_purgerange(mgr->task, 0L, ISC_SOCKEVENT_READ_READY, ISC_SOCKEVENT_SELECTED, 0L); + twalk(mgr->sockets, dbus_mgr_close_socket); + tdestroy(mgr->sockets, dbus_mgr_destroy_socket); + mgr->sockets = 0L; + if( mgr->dbus ) + { + dbus_svc_shutdown(mgr->dbus); + mgr->dbus = 0L; + } + return ISC_R_FAILURE; +} + +static +uint8_t dbus_mgr_subscribe_to_dhcdbd( ns_dbus_mgr_t *mgr ) +{ + DBUS_SVC dbus = mgr->dbus; + char subs[1024], path[1024], + dhcdbd_destination[]="com.redhat.dhcp", *ddp[1]={ &(dhcdbd_destination[0]) }, + *dhcdbd_name=0L; + const char *options[] = { "reason", "ip-address", "subnet-mask", + "domain-name", "domain-name-servers" + }; + dbus_svc_MessageHandle msg; + int i, n_opts = 5; + + if( mgr->dhcdbd_name == 0L ) + { + msg = dbus_svc_call + ( dbus, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "GetNameOwner", + "org.freedesktop.DBus", + TYPE_STRING, &ddp, + TYPE_INVALID + ); + if( msg == 0L ) + return 0; + + if( !dbus_svc_get_args(dbus, msg, + TYPE_STRING, &(dhcdbd_name), + TYPE_INVALID + ) + ) return 0; + + mgr->dhcdbd_name = isc_mem_get(mgr->mctx, strlen(dhcdbd_name) + 1); + if( mgr->dhcdbd_name == 0L ) + return 0; + + strcpy(mgr->dhcdbd_name, dhcdbd_name); + + } + + sprintf(path,"/com/redhat/dhcp/subscribe"); + sprintf(subs,"com.redhat.dhcp.binary"); + + for(i = 0; i < n_opts; i++) + { + msg = dbus_svc_call + ( dbus, + "com.redhat.dhcp", + path, + "binary", + subs, + TYPE_STRING, &(options[i]), + TYPE_INVALID + ); + if(msg == 0L) + return 0; + if ( dbus_svc_message_type( msg ) == ERROR ) + return 0; + } + dbus_mgr_log_err("D-BUS dhcdbd subscription enabled."); + return 1; +} + +void +dbus_mgr_shutdown +( ns_dbus_mgr_t *mgr +) +{ + if( mgr->timer != 0L ) + isc_timer_detach(&(mgr->timer)); + if( mgr->dbus != 0L ) + { + isc_task_purgerange(mgr->task, 0L, ISC_SOCKEVENT_READ_READY, ISC_SOCKEVENT_SELECTED, 0L); + if( mgr->sockets != 0L ) + { + twalk(mgr->sockets, dbus_mgr_close_socket); + tdestroy(mgr->sockets, dbus_mgr_destroy_socket); + mgr->sockets = 0L; + } + dbus_svc_shutdown(mgr->dbus); + } + if( mgr->dhc_if != 0L ) + tdestroy(mgr->dhc_if, dbus_mgr_free_dhc); + if( mgr->dhcdbd_name != 0L ) + isc_mem_put(mgr->mctx, mgr->dhcdbd_name, strlen(mgr->dhcdbd_name) + 1); + isc_task_detach(&(mgr->task)); + dbus_mgr_free_initial_fwdtable(mgr); + isc_mem_put(mgr->mctx, mgr, sizeof(ns_dbus_mgr_t)); +} + +static +void dbus_mgr_restart_dbus(isc_task_t *t, isc_event_t *ev) +{ + ns_dbus_mgr_t *mgr = (ns_dbus_mgr_t*)(ev->ev_arg) ; + t=t; + isc_event_free(&ev); + dbus_mgr_log_dbg("attempting to connect to D-BUS"); + dbus_mgr_init_dbus( mgr ); +} + +static +void dbus_mgr_handle_dbus_shutdown_event(isc_task_t *t, isc_event_t *ev) +{ + ns_dbus_mgr_t *mgr = ev->ev_arg; + isc_time_t tick={10,0}; + isc_interval_t tock={10,0}; + DBUS_SVC dbus = mgr->dbus; + t = t; + + mgr->dbus = 0L; + + isc_event_free(&ev); + + if ( dbus != 0L ) + { + isc_task_purgerange(mgr->task, 0L, ISC_SOCKEVENT_READ_READY, ISC_SOCKEVENT_SELECTED, 0L); + if( mgr->sockets != 0L ) + { + twalk(mgr->sockets, dbus_mgr_close_socket); + tdestroy(mgr->sockets, dbus_mgr_destroy_socket); + mgr->sockets = 0L; + } + dbus_svc_shutdown(dbus); + } + + dbus_mgr_log_err( "D-BUS service disabled." ); + + if( mgr->timer != 0L ) + { + isc_timer_reset(mgr->timer, + isc_timertype_ticker, + &tick, &tock, ISC_TRUE + ); + }else + if( isc_timer_create + ( mgr->timermgr, + isc_timertype_ticker, + &tick, &tock, + mgr->task, + dbus_mgr_restart_dbus, + mgr, + &(mgr->timer) + ) != ISC_R_SUCCESS + ) + { + dbus_mgr_log_err( "D-BUS service cannot be restored." ); + } +} + +static +void dbus_mgr_dbus_shutdown_handler ( ns_dbus_mgr_t *mgr ) +{ + isc_event_t *dbus_shutdown_event = + isc_event_allocate + ( mgr->mctx, + mgr->task, + 1, + dbus_mgr_handle_dbus_shutdown_event, + mgr, + sizeof(isc_event_t) + ); + if( dbus_shutdown_event != 0L ) + { + isc_task_purgerange(mgr->task, 0L, ISC_SOCKEVENT_READ_READY, ISC_SOCKEVENT_SELECTED, 0L); + isc_task_send( mgr->task, &dbus_shutdown_event ); + }else + dbus_mgr_log_err("unable to allocate dbus shutdown event"); +} + +static +dns_view_t *dbus_mgr_get_localhost_view(void) +{ + dns_view_t *view; + isc_netaddr_t localhost = { AF_INET, { { htonl( ( 127 << 24 ) | 1 ) } }, 0 }; + int match; + + for (view = ISC_LIST_HEAD(ns_g_server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link) + ) + { + /* return first view matching "localhost" source and dest */ + + if(( (view->matchclients != 0L ) /* 0L: accept "any" */ + &&(( dns_acl_match( &localhost, + NULL, /* unsigned queries */ + view->matchclients, + &(ns_g_server->aclenv), + &match, + NULL /* no match list */ + ) != ISC_R_SUCCESS + ) || (match <= 0) + ) + ) + ||( (view->matchdestinations != 0L ) /* 0L: accept "any" */ + &&(( dns_acl_match( &localhost, + NULL, /* unsigned queries */ + view->matchdestinations, + &(ns_g_server->aclenv), + &match, + NULL /* no match list */ + ) != ISC_R_SUCCESS + ) || (match <= 0) + ) + ) + ) continue; + + break; + } + return view; +} + +static +dns_fwdtable_t *dbus_mgr_get_fwdtable(void) +{ + dns_view_t *view = dbus_mgr_get_localhost_view(); + if( view != 0L ) + return view->fwdtable; + return 0L; +} + +static +dns_fwdtable_t *dbus_mgr_get_view_and_fwdtable( dns_view_t **viewp ) +{ + *viewp = dbus_mgr_get_localhost_view(); + if( *viewp != 0L ) + return (*viewp)->fwdtable; + return 0L; +} + +static int dbus_mgr_ifwdr_comparator( const void *p1, const void *p2 ) +{ + char n1buf[ DNS_NAME_FORMATSIZE ]="", *n1p=&(n1buf[0]), + n2buf[ DNS_NAME_FORMATSIZE ]="", *n2p=&(n2buf[0]); + dns_name_t *dn1; + dns_name_t *dn2; + DE_CONST(&(((const DBusMgrInitialFwdr*)p1)->dn), dn1); + DE_CONST(&(((const DBusMgrInitialFwdr*)p2)->dn), dn2); + dns_name_format(dn1, n1p, DNS_NAME_FORMATSIZE ); + dns_name_format(dn2, n2p, DNS_NAME_FORMATSIZE ); + return strcmp(n1buf, n2buf); +} + +static int dbus_mgr_dhc_if_comparator( const void *p1, const void *p2 ); + +static void dbus_mgr_record_initial_forwarder( dns_name_t *name, dns_forwarders_t *fwdr, void *mp ) +{ + ns_dbus_mgr_t *mgr = mp; + isc_sockaddr_t *sa, *nsa; + DBusMgrInitialFwdr *ifwdr; + + if( ISC_LIST_HEAD(fwdr->addrs) == 0L) + return; + + if( (ifwdr = isc_mem_get(mgr->mctx, sizeof(DBusMgrInitialFwdr))) == 0L) + return; + + ifwdr->fwdpolicy = fwdr->fwdpolicy; + + dns_name_init(&(ifwdr->dn), NULL); + if( dns_name_dupwithoffsets(name, mgr->mctx, &(ifwdr->dn)) != ISC_R_SUCCESS ) + goto namedup_err; + + ISC_LIST_INIT(ifwdr->sa); + + for( sa = ISC_LIST_HEAD(fwdr->addrs); + sa != 0L; + sa = ISC_LIST_NEXT(sa,link) + ) + { + nsa = isc_mem_get(mgr->mctx, sizeof(isc_sockaddr_t)); + if( nsa == 0L ) + goto nsa_err; + *nsa = *sa; + ISC_LINK_INIT(nsa, link); + ISC_LIST_APPEND(ifwdr->sa, nsa, link); + } + ISC_LINK_INIT(ifwdr, link); + tsearch( ifwdr, &(mgr->ifwdt), dbus_mgr_ifwdr_comparator); + + return; + +nsa_err: + while ( (sa = ISC_LIST_HEAD (ifwdr->sa)) != NULL) { + ISC_LIST_UNLINK (ifwdr->sa, sa, link); + isc_mem_put (mgr->mctx, sa, sizeof (*sa)); + } + +namedup_err: + isc_mem_put (mgr->mctx, ifwdr, sizeof (*ifwdr)); + + return; +} + +static isc_result_t +dbus_mgr_record_initial_fwdtable( ns_dbus_mgr_t *mgr ) +{ + dns_fwdtable_t *fwdtable = dbus_mgr_get_fwdtable(); + + if( fwdtable == 0L ) + return ISC_R_SUCCESS; /* no initial fwdtable */ + dns_fwdtable_foreach( fwdtable, dbus_mgr_record_initial_forwarder, mgr); + return ISC_R_SUCCESS; +} + +static void +dbus_mgr_free_initial_forwarder( void *p ) +{ + DBusMgrInitialFwdr *ifwdr = p; + isc_sockaddr_t *sa; + + dns_name_free(&(ifwdr->dn), ns_g_mctx); + for( sa = ISC_LIST_HEAD( ifwdr->sa ); + sa != 0L; + sa = ISC_LIST_HEAD( ifwdr->sa ) + ) + { + if( ISC_LINK_LINKED(sa, link) ) + ISC_LIST_UNLINK(ifwdr->sa, sa, link); + isc_mem_put(ns_g_mctx, sa, sizeof(isc_sockaddr_t)); + } + isc_mem_put(ns_g_mctx, ifwdr, sizeof(DBusMgrInitialFwdr)); +} + +static void +dbus_mgr_free_initial_fwdtable( ns_dbus_mgr_t *mgr ) +{ + tdestroy(mgr->ifwdt, dbus_mgr_free_initial_forwarder); + mgr->ifwdt = 0L; +} + +static void +dbus_mgr_log_forwarders( const char *pfx, dns_name_t *name, SockAddrList *saList) +{ + isc_sockaddr_t *sa; + char nameP[DNS_NAME_FORMATSIZE], addrP[128]; + int s=0; + dns_name_format(name, nameP, DNS_NAME_FORMATSIZE ); + for( sa = ISC_LIST_HEAD(*saList); + sa != 0L; + sa = ISC_LIST_NEXT(sa,link) + ) + { + isc_sockaddr_format(sa, addrP, 128); + dbus_mgr_log_info("%s zone %s server %d: %s", pfx, nameP, s++, addrP); + } +} + +static +isc_result_t dbus_mgr_set_forwarders +( + ns_dbus_mgr_t *mgr, + DNSNameList *nameList, + SockAddrList *saList, + dns_fwdpolicy_t fwdpolicy +) +{ + isc_result_t result = ISC_R_SUCCESS; + dns_fwdtable_t *fwdtable; + dns_view_t *view=0L; + dns_name_t *dnsName; + isc_sockaddr_t *sa, *nsa; + dns_forwarders_t *fwdr=0L; + + fwdtable = dbus_mgr_get_view_and_fwdtable(&view); + + if( fwdtable == 0L ) + { + if( ISC_LIST_HEAD(*saList) == 0L ) + return ISC_R_SUCCESS;/* deletion not required */ + + view = dbus_mgr_get_localhost_view(); + if( view == 0L ) + return ISC_R_NOPERM; /* if configuration does not allow localhost clients, + * then we really shouldn't be creating a forwarding table. + */ + result = isc_task_beginexclusive(mgr->task); + + if( result == ISC_R_SUCCESS ) + { + result = dns_fwdtable_create( mgr->mctx, &(view->fwdtable) ); + + isc_task_endexclusive(mgr->task); + + if( result != ISC_R_SUCCESS ) + return result; + + if( view->fwdtable == 0L ) + return ISC_R_NOMEMORY; + + if( isc_log_getdebuglevel(ns_g_lctx) >= 1 ) + dbus_mgr_log_info("Created forwarder table."); + } + } + + for( dnsName = ISC_LIST_HEAD(*nameList); + dnsName != NULL; + dnsName = ISC_LIST_NEXT(dnsName,link) + ) + { + fwdr = 0L; + if( ( dns_fwdtable_find_exact( fwdtable, dnsName, &fwdr ) != ISC_R_SUCCESS ) + ||( fwdr == 0L ) + ) + { + if( ISC_LIST_HEAD( *saList ) == 0L ) + continue; + /* no forwarders for name - add forwarders */ + + result = isc_task_beginexclusive(mgr->task); + + if( result == ISC_R_SUCCESS ) + { + result = dns_fwdtable_add( fwdtable, dnsName, + (isc_sockaddrlist_t*)saList, + fwdpolicy + ) ; + + if( view != 0L ) + dns_view_flushcache( view ); + + isc_task_endexclusive(mgr->task); + + if( result != ISC_R_SUCCESS ) + return result; + + if( isc_log_getdebuglevel(ns_g_lctx) >= 1 ) + dbus_mgr_log_forwarders("Created forwarder",dnsName, saList); + } + continue; + } + + if( ISC_LIST_HEAD( *saList ) == 0L ) + { /* empty forwarders list - delete forwarder entry */ + + if( isc_log_getdebuglevel(ns_g_lctx) >= 1 ) + dbus_mgr_log_forwarders("Deleting forwarder", dnsName, (SockAddrList*)&(fwdr->addrs)); + + result = isc_task_beginexclusive(mgr->task); + if( result == ISC_R_SUCCESS ) + { + result = dns_fwdtable_delete( fwdtable, dnsName ); + + if( view != 0L ) + dns_view_flushcache( view ); + + isc_task_endexclusive(mgr->task); + + if( result != ISC_R_SUCCESS ) + return result; + } + continue; + } + + result = isc_task_beginexclusive(mgr->task); + + if( result == ISC_R_SUCCESS ) + { + fwdr->fwdpolicy = fwdpolicy; + + if( isc_log_getdebuglevel(ns_g_lctx) >= 1 ) + dbus_mgr_log_forwarders("Removing forwarder", dnsName, (SockAddrList*)&(fwdr->addrs)); + + for( sa = ISC_LIST_HEAD(fwdr->addrs); + sa != 0L ; + sa = ISC_LIST_HEAD(fwdr->addrs) + ) + { + if( ISC_LINK_LINKED(sa, link) ) + ISC_LIST_UNLINK(fwdr->addrs, sa, link); + isc_mem_put(mgr->mctx, sa, sizeof(isc_sockaddr_t)); + } + + ISC_LIST_INIT( fwdr->addrs ); + + for( sa = ISC_LIST_HEAD(*saList); + sa != 0L; + sa = ISC_LIST_NEXT(sa,link) + ) + { + nsa = isc_mem_get(mgr->mctx, sizeof(isc_sockaddr_t)); + if( nsa == 0L ) + { + result = ISC_R_NOMEMORY; + break; + } + *nsa = *sa; + ISC_LINK_INIT( nsa, link ); + ISC_LIST_APPEND( fwdr->addrs, nsa, link ); + } + + if( view != 0L ) + dns_view_flushcache( view ); + + isc_task_endexclusive(mgr->task); + + if( isc_log_getdebuglevel(ns_g_lctx) >= 1 ) + dbus_mgr_log_forwarders("Added forwarder", dnsName, (SockAddrList*)&(fwdr->addrs)); + + }else + return result; + + } + return (result); +} + +static void +dbus_mgr_get_name_list +( + ns_dbus_mgr_t *mgr, + char *domains, + DNSNameList *nameList, + char *error_name, + char *error_message +) +{ + char *name, *endName, *endp; + dns_fixedname_t *fixedname; + dns_name_t *dnsName; + isc_buffer_t buffer; + isc_result_t result; + uint32_t total_length; + + total_length = strlen(domains); + endp = domains + total_length; + + ISC_LIST_INIT( *nameList ); + + for( name = domains + strspn(domains," \t\n"), + endName = name + strcspn(name," \t\n"); + (name < endp) && (endName <= endp); + name = endName + 1 + strspn(endName+1," \t\n"), + endName = name + strcspn(name," \t\n") + ) + { /* name loop */ + *endName = '\0'; + + isc_buffer_init( &buffer, name, endName - name ); + isc_buffer_add(&buffer, endName - name); + + fixedname = isc_mem_get( mgr->mctx, sizeof( dns_fixedname_t )); + + dns_fixedname_init(fixedname); + + dnsName = dns_fixedname_name(fixedname); + + result= dns_name_fromtext + ( dnsName, &buffer, ( *(endp-1) != '.') ? dns_rootname : NULL, ISC_FALSE, NULL + ); + + if( result != ISC_R_SUCCESS ) + { + sprintf(error_name, "com.redhat.named.InvalidArgument"); + sprintf(error_message,"Invalid DNS name initial argument: %s", name); + + isc_mem_put( mgr->mctx, fixedname, sizeof( dns_fixedname_t ) ); + + for( dnsName = ISC_LIST_HEAD( *nameList ); + (dnsName != 0L); + dnsName = ISC_LIST_HEAD( *nameList ) + ) + { + if( ISC_LINK_LINKED(dnsName,link) ) + ISC_LIST_DEQUEUE( *nameList, dnsName, link ); + isc_mem_put( mgr->mctx, dnsName, sizeof( dns_fixedname_t ) ); + } + ISC_LIST_INIT(*nameList); + return; + } + ISC_LINK_INIT(dnsName, link); + ISC_LIST_ENQUEUE( *nameList, dnsName, link ); + } +} + +static isc_result_t +dbus_mgr_get_sa_list +( + ns_dbus_mgr_t *mgr, + dbus_svc_MessageIterator iter, + SockAddrList *saList , + uint8_t *fwdpolicy, + char *error_name, + char *error_message +) +{ + DBUS_SVC dbus = mgr->dbus; + isc_sockaddr_t *nsSA=0L, *nsSA_Q=0L; + uint32_t argType = dbus_svc_message_next_arg_type( dbus, iter ), + length; + isc_result_t result; + in_port_t port; + char *ip; + uint8_t *iparray=0L; + + ISC_LIST_INIT(*saList); + + if( argType == TYPE_INVALID ) + return ISC_R_SUCCESS; /* address list "removal" */ + + do + { + switch( argType ) + { + case TYPE_UINT32: + + nsSA = isc_mem_get(mgr->mctx, sizeof(isc_sockaddr_t)); + if( nsSA != 0L ) + { + memset(nsSA,'\0', sizeof(isc_sockaddr_t)); + nsSA_Q = nsSA; + dbus_svc_message_next_arg(dbus, iter, &(nsSA->type.sin.sin_addr.s_addr)); + nsSA->type.sa.sa_family = AF_INET; + nsSA->length = sizeof( nsSA->type.sin ); + } + break; + + case TYPE_ARRAY: + + argType = dbus_svc_message_element_type( dbus, iter ); + if( argType == TYPE_BYTE ) + { + iparray = 0L; + length = 0; + + dbus_svc_message_get_elements(dbus, iter, &length, &iparray); + + if( iparray != 0L ) + { + if (length == sizeof( struct in_addr )) + { + nsSA = isc_mem_get(mgr->mctx, sizeof(isc_sockaddr_t)); + if( nsSA != 0L ) + { + memset(nsSA,'\0', sizeof(isc_sockaddr_t)); + nsSA_Q = nsSA; + + memcpy(&(nsSA->type.sin.sin_addr), iparray, sizeof( struct in_addr )); + nsSA->type.sa.sa_family = AF_INET; + nsSA->length = sizeof( nsSA->type.sin ); + } + }else + if (length == sizeof( struct in6_addr )) + { + nsSA = isc_mem_get(mgr->mctx, sizeof(isc_sockaddr_t)); + if( nsSA != 0L ) + { + memset(nsSA,'\0', sizeof(isc_sockaddr_t)); + nsSA_Q = nsSA; + + memcpy(&(nsSA->type.sin6.sin6_addr), iparray, sizeof( struct in6_addr )); + nsSA->type.sa.sa_family = AF_INET6; + nsSA->length = sizeof( nsSA->type.sin6 ); + } + } + } + } + break; + + case TYPE_STRING: + + ip = 0L; + dbus_svc_message_next_arg(dbus, iter, &(ip)); + if( ip != 0L ) + { + length = strlen(ip); + if( strspn(ip, "0123456789.") == length ) + { + nsSA = isc_mem_get(mgr->mctx, sizeof(isc_sockaddr_t)); + if( nsSA != 0L) + { + memset(nsSA,'\0', sizeof(isc_sockaddr_t)); + if( inet_pton( AF_INET, ip, &(nsSA->type.sin.sin_addr)) ) + { + nsSA->type.sa.sa_family = AF_INET; + nsSA->length = sizeof(nsSA->type.sin); + nsSA_Q = nsSA; + } + } + }else + if( strspn(ip, "0123456789AaBbCcDdEeFf:.") == length) + { + nsSA = isc_mem_get(mgr->mctx, sizeof(isc_sockaddr_t)); + if( nsSA != 0L ) + { + memset(nsSA,'\0', sizeof(isc_sockaddr_t)); + if( inet_pton( AF_INET6, ip, &(nsSA->type.sin6.sin6_addr)) ) + { + nsSA->type.sa.sa_family = AF_INET6; + nsSA->length = sizeof(nsSA->type.sin6); + nsSA_Q = nsSA; + } + } + } + } + break; + + case TYPE_UINT16: + + if( (nsSA == 0L) || (nsSA->type.sa.sa_family == AF_UNSPEC) ) + break; + else + if( nsSA->type.sa.sa_family == AF_INET ) + dbus_svc_message_next_arg(dbus, iter, &(nsSA->type.sin.sin_port)); + else + if( nsSA->type.sa.sa_family == AF_INET6 ) + dbus_svc_message_next_arg(dbus, iter, &(nsSA->type.sin6.sin6_port)); + break; + + case TYPE_BYTE: + + dbus_svc_message_next_arg(dbus, iter, fwdpolicy); + if(*fwdpolicy > dns_fwdpolicy_only) + *fwdpolicy = dns_fwdpolicy_only; + break; + + default: + + if(nsSA != 0L) + nsSA->type.sa.sa_family = AF_UNSPEC; + sprintf(error_message,"Unhandled argument type: %c", argType); + break; + } + + if( (nsSA != 0L) + &&(nsSA->type.sa.sa_family == AF_UNSPEC) + ) + { + sprintf(error_name, "com.redhat.named.InvalidArgument"); + if( error_message[0]=='\0') + { + if( nsSA == 0L ) + sprintf(error_message,"Missing IP Address Name Server argument"); + else + sprintf(error_message,"Bad IP Address Name Server argument"); + } + if( nsSA != 0L ) + isc_mem_put(mgr->mctx, nsSA, sizeof(isc_sockaddr_t)); + nsSA = 0L; + for( nsSA = ISC_LIST_HEAD( *saList ); + (nsSA != 0L); + nsSA = ISC_LIST_HEAD( *saList ) + ) + { + if(ISC_LINK_LINKED(nsSA, link)) + ISC_LIST_DEQUEUE( *saList, nsSA, link ); + isc_mem_put( mgr->mctx, nsSA, sizeof( isc_sockaddr_t ) ); + } + ISC_LIST_INIT(*saList); + return ISC_R_FAILURE; + } + + if( nsSA != 0L ) + { + if( nsSA->type.sin.sin_port == 0 ) + { + if( ns_g_port != 0L ) + nsSA->type.sin.sin_port = htons(ns_g_port); + else + { + result = ns_config_getport(ns_g_config, &(port) ); + if( result != ISC_R_SUCCESS ) + port = 53; + nsSA->type.sin.sin_port = htons( port ); + } + } + + if( nsSA_Q != 0L ) + { + ISC_LINK_INIT(nsSA,link); + ISC_LIST_ENQUEUE(*saList, nsSA, link); + nsSA_Q = 0L; + } + } + + argType = dbus_svc_message_next_arg_type( dbus, iter ); + + } while ( argType != TYPE_INVALID ); + + return ISC_R_SUCCESS; +} + +static void +dbus_mgr_handle_set_forwarders +( + ns_dbus_mgr_t *mgr, + DBUS_SVC dbus, + uint8_t reply_expected, + uint32_t serial, + const char *path, + const char *member, + const char *interface, + const char *sender, + dbus_svc_MessageHandle msg +) +{ + dbus_svc_MessageIterator iter; + char error_name[1024]="", error_message[1024]="", *domains=0L; + uint32_t argType, new_serial; + DNSNameList nameList; + dns_name_t *dnsName; + SockAddrList saList; + isc_sockaddr_t *nsSA; + isc_result_t result; + uint8_t fwdpolicy = dns_fwdpolicy_only; + + iter = dbus_svc_message_iterator_new( dbus, msg ); + + if( iter == 0L ) + { + if( reply_expected ) + { + sprintf(error_name, "com.redhat.named.InvalidArguments"); + sprintf(error_message,"SetForwarders requires DNS name and nameservers arguments."); + dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member, + TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID + ); + } + return; + } + + argType = dbus_svc_message_next_arg_type( dbus, iter ); + + if( argType != TYPE_STRING ) + { + if( reply_expected ) + { + sprintf(error_name, "com.redhat.named.InvalidArguments"); + sprintf(error_message,"SetForwarders requires DNS name string initial argument."); + dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member, + TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID + ); + } + return; + } + + dbus_svc_message_next_arg( dbus, iter, &domains ); + + if( ( domains == 0L ) || (*domains == '\0') ) + { + if( reply_expected ) + { + sprintf(error_name, "com.redhat.named.InvalidArguments"); + sprintf(error_message,"SetForwarders requires DNS name string initial argument."); + dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member, + TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID + ); + } + return; + } + + dbus_mgr_get_name_list( mgr, domains, &nameList, error_name, error_message ); + + if( error_name[0] != '\0' ) + { + if( reply_expected ) + { + dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member, + TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID + ); + } + return; + } + + if( ISC_LIST_HEAD( nameList ) == 0L ) + return; + + result = dbus_mgr_get_sa_list( mgr, iter, &saList , &fwdpolicy, error_name, error_message ); + + if( result == ISC_R_SUCCESS ) + { + result = dbus_mgr_set_forwarders( mgr, &nameList, &saList, fwdpolicy ); + + if( result != ISC_R_SUCCESS ) + { + if( reply_expected ) + { + sprintf(error_name, "com.redhat.named.Failure"); + sprintf(error_message, isc_result_totext(result)); + dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member, + TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID + ); + } + }else + if( reply_expected ) + dbus_svc_send( dbus, RETURN, serial, &new_serial, sender, path, interface, member, + TYPE_UINT32, &result, TYPE_INVALID + ); + }else + { + if( reply_expected ) + { + dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member, + TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID + ); + } + } + + for( dnsName = ISC_LIST_HEAD( nameList ); + (dnsName != 0L) ; + dnsName = ISC_LIST_HEAD( nameList ) + ) + { + if( ISC_LINK_LINKED(dnsName,link) ) + ISC_LIST_DEQUEUE( nameList, dnsName, link ); + isc_mem_put( mgr->mctx, dnsName, sizeof( dns_fixedname_t ) ); + } + + for( nsSA = ISC_LIST_HEAD(saList); + (nsSA != 0L) ; + nsSA = ISC_LIST_HEAD(saList) + ) + { + if( ISC_LINK_LINKED(nsSA,link) ) + ISC_LIST_DEQUEUE( saList, nsSA, link ); + isc_mem_put(mgr->mctx, nsSA, sizeof(isc_sockaddr_t)); + } +} + +static +int dbus_mgr_msg_append_dns_name +( DBUS_SVC dbus, + dbus_svc_MessageHandle msg, + dns_name_t *name +) +{ + char nameBuf[ DNS_NAME_FORMATSIZE ]="", *nameP=&(nameBuf[0]); + + dns_name_format(name, nameP, DNS_NAME_FORMATSIZE ); + + if( *nameP == '\0' ) + return 0; + + return dbus_svc_message_append_args( dbus, msg, TYPE_STRING, &nameP, TYPE_INVALID ) > 0; +} + +typedef enum dbmoi_e +{ + OUTPUT_BINARY, + OUTPUT_TEXT +} DBusMgrOutputInterface; + +static +int dbus_mgr_msg_append_forwarders +( DBUS_SVC dbus, + dbus_svc_MessageHandle msg, + dns_forwarders_t *fwdr, + DBusMgrOutputInterface outputType +) +{ + isc_sockaddr_t *sa; + char policyBuf[16]="", *pbp[1]={&(policyBuf[0])}, addressBuf[64]="", *abp[1]={&(addressBuf[0])}; + uint8_t *byteArray[1]; + + if( outputType == OUTPUT_BINARY ) + { + if(!dbus_svc_message_append_args + ( dbus, msg, + TYPE_BYTE, &(fwdr->fwdpolicy), + TYPE_INVALID + ) + ) return 0; + }else + if( outputType == OUTPUT_TEXT ) + { + sprintf(policyBuf,"%s", + (fwdr->fwdpolicy == dns_fwdpolicy_none) + ? "none" + : (fwdr->fwdpolicy == dns_fwdpolicy_first) + ? "first" + : "only" + ); + if(!dbus_svc_message_append_args + ( dbus, msg, + TYPE_STRING, pbp, + TYPE_INVALID + ) + ) return 0; + }else + return 0; + + for( sa = ISC_LIST_HEAD(fwdr->addrs); + sa != 0L; + sa = ISC_LIST_NEXT(sa, link) + ) + { + if( outputType == OUTPUT_BINARY ) + { + if( sa->type.sa.sa_family == AF_INET ) + { + if(!dbus_svc_message_append_args + ( dbus, msg, + TYPE_UINT32, &(sa->type.sin.sin_addr.s_addr), + TYPE_INVALID + ) + ) return 0; + + if(!dbus_svc_message_append_args + ( dbus, msg, + TYPE_UINT16, &(sa->type.sin.sin_port), + TYPE_INVALID + ) + ) return 0; + }else + if( sa->type.sa.sa_family == AF_INET6 ) + { + byteArray[0] = (uint8_t*)&(sa->type.sin6.sin6_addr); + if(!dbus_svc_message_append_args + ( dbus, msg, + TYPE_ARRAY, TYPE_BYTE, &byteArray, sizeof(struct in6_addr), + TYPE_INVALID + ) + ) return 0; + + if(!dbus_svc_message_append_args + ( dbus, msg, + TYPE_UINT16, &(sa->type.sin6.sin6_port), + TYPE_INVALID + ) + ) return 0; + }else + continue; + }else + if( outputType == OUTPUT_TEXT ) + { + if( sa->type.sa.sa_family == AF_INET ) + { + if( inet_ntop( AF_INET, &(sa->type.sin.sin_addr), addressBuf, sizeof(addressBuf)) == 0L ) + continue; + if(!dbus_svc_message_append_args + ( dbus, msg, + TYPE_STRING, abp, + TYPE_INVALID + ) + ) return 0; + sprintf(addressBuf, "%hu", ntohs( sa->type.sin.sin_port )); + if(!dbus_svc_message_append_args + ( dbus, msg, + TYPE_STRING, abp, + TYPE_INVALID + ) + ) return 0; + }else + if( sa->type.sa.sa_family == AF_INET6 ) + { + if( inet_ntop( AF_INET6, &(sa->type.sin6.sin6_addr), addressBuf, sizeof(addressBuf)) == 0L ) + continue; + if(!dbus_svc_message_append_args + ( dbus, msg, + TYPE_STRING, abp, + TYPE_INVALID + ) + ) return 0; + sprintf(addressBuf, "%hu", ntohs( sa->type.sin6.sin6_port )); + if(!dbus_svc_message_append_args + ( dbus, msg, + TYPE_STRING, abp, + TYPE_INVALID + ) + ) return 0; + }else + continue; + }else + return 0; + } + return 1; +} + +typedef struct dbm_m_s +{ + DBUS_SVC dbus; + dbus_svc_MessageHandle msg; + DBusMgrOutputInterface outputType; +} DBusMgrMsg; + +static +void forwarders_to_msg( dns_name_t *name, dns_forwarders_t *fwdr, void *mp ) +{ + DBusMgrMsg *m = mp; + + if( (fwdr == 0L) || (name == 0L) || (mp == 0L)) + return; + dbus_mgr_msg_append_dns_name ( m->dbus, m->msg, name ); + dbus_mgr_msg_append_forwarders( m->dbus, m->msg, fwdr, m->outputType ); +} + +static void +dbus_mgr_handle_list_forwarders +( + DBUS_SVC dbus, + uint8_t reply_expected, + uint32_t serial, + const char *path, + const char *member, + const char *interface, + const char *sender, + dbus_svc_MessageHandle msg +) +{ + char error_name[1024], error_message[1024]; + DBusMgrMsg m; + uint32_t new_serial; + dns_fwdtable_t *fwdtable = dbus_mgr_get_fwdtable(); + DBusMgrOutputInterface outputType = OUTPUT_BINARY; + uint32_t length = strlen(interface); + + if( !reply_expected ) + return; + + if( (length > 4) && (strcmp(interface + (length - 4), "text")==0)) + outputType = OUTPUT_TEXT; + + if( fwdtable == 0L ) + { + sprintf(error_name,"com.redhat.dbus.Failure"); + sprintf(error_message, "%s", isc_result_totext(ISC_R_NOPERM)); + dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member, + TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID + ); + return; + } + + msg = dbus_svc_new_message( dbus, RETURN, serial, sender, path, interface, member); + + m.dbus = dbus; + m.msg = msg; + m.outputType = outputType; + + if( msg == 0L ) + { + sprintf(error_name,"com.redhat.dbus.OutOfMemory"); + sprintf(error_message,"out of memory"); + dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member, + TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID + ); + } + + dns_fwdtable_foreach( fwdtable, forwarders_to_msg, &m ); + + dbus_svc_send_message( dbus, msg, &new_serial ); +} + +static void +dbus_mgr_handle_get_forwarders +( + DBUS_SVC dbus, + uint8_t reply_expected, + uint32_t serial, + const char *path, + const char *member, + const char *interface, + const char *sender, + dbus_svc_MessageHandle msg +) +{ + char error_name[1024], error_message[1024], *domain=0L; + isc_result_t result; + dns_fixedname_t fixedname; + dns_name_t *dnsName; + isc_buffer_t buffer; + uint32_t length, new_serial; + dns_fwdtable_t *fwdtable; + dns_forwarders_t *fwdr=0L; + dns_name_t *foundname; + dns_fixedname_t fixedFoundName; + DBusMgrOutputInterface outputType = OUTPUT_BINARY; + + if( !reply_expected ) + return; + + length = strlen(interface); + + if( (length > 4) && (strcmp(interface + (length - 4), "text")==0)) + outputType = OUTPUT_TEXT; + + if( (!dbus_svc_get_args( dbus, msg, TYPE_STRING, &domain, TYPE_INVALID)) + ||(domain == 0L) + ||(*domain == '\0') + ) + { + + sprintf(error_name,"com.redhat.dbus.InvalidArguments"); + sprintf(error_message,"domain name argument expected"); + dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member, + TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID + ); + return; + } + + length = strlen( domain ); + + isc_buffer_init( &buffer, domain, length); + + isc_buffer_add(&buffer, length); + + dns_fixedname_init(&fixedname); + + dnsName = dns_fixedname_name(&fixedname); + + result = dns_name_fromtext + ( dnsName, &buffer, dns_rootname, ISC_FALSE, NULL + ); + + if( result != ISC_R_SUCCESS ) + { + sprintf(error_name,"com.redhat.dbus.InvalidArguments"); + sprintf(error_message,"invalid domain name argument: %s", domain); + dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member, + TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID + ); + return; + } + + msg = dbus_svc_new_message( dbus, RETURN, serial, sender, path, interface, member); + + if( msg == 0L ) + { + sprintf(error_name,"com.redhat.dbus.OutOfMemory"); + sprintf(error_message,"out of memory"); + dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member, + TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID + ); + return; + } + + fwdtable = dbus_mgr_get_fwdtable(); + + if( fwdtable == 0L ) + { + sprintf(error_name,"com.redhat.dbus.Failure"); + sprintf(error_message, "%s", isc_result_totext(ISC_R_NOPERM)); + dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member, + TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID + ); + return; + } + + dns_fixedname_init(&fixedFoundName); + foundname = dns_fixedname_name(&fixedFoundName); + + if( ( dns_fwdtable_find_closest( fwdtable, dnsName, foundname, &fwdr ) == ISC_R_SUCCESS ) + &&( fwdr != 0L ) + ) + { + if( (!dbus_mgr_msg_append_dns_name( dbus, msg, foundname )) + ||(!dbus_mgr_msg_append_forwarders( dbus, msg, fwdr, outputType )) + ) + { + sprintf(error_name,"com.redhat.dbus.OutOfMemory"); + sprintf(error_message,"out of memory"); + dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member, + TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID + ); + return; + } + + }else + { + result = ISC_R_NOTFOUND; + if( outputType == OUTPUT_BINARY ) + { + dbus_svc_message_append_args( dbus, msg, + TYPE_UINT32, &(result), + TYPE_INVALID + ) ; + }else + { + sprintf(error_name,"com.redhat.dbus.NotFound"); + sprintf(error_message,"Not Found"); + dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member, + TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID + ); + return; + } + } + dbus_svc_send_message( dbus, msg, &new_serial ); +} + +static void +dbus_mgr_check_dhcdbd_state( ns_dbus_mgr_t *mgr, dbus_svc_MessageHandle msg ) +{ + DBUS_SVC dbus = mgr->dbus; + char *name_owned = 0L, + *old_owner = 0L, + *new_owner = 0L; + + if( !dbus_svc_get_args( dbus, msg, + TYPE_STRING, &name_owned, + TYPE_STRING, &old_owner, + TYPE_STRING, &new_owner, + TYPE_INVALID + ) + ) return; + + dbus_mgr_log_dbg("NameOwnerChanged: %s %s %s ( %s )", name_owned, old_owner, new_owner, mgr->dhcdbd_name); + + if( (name_owned == 0L) || (new_owner == 0L) || (old_owner == 0L) ) + return; + + if( strcmp( name_owned, "com.redhat.dhcp" ) == 0 ) + { + if( *new_owner == '\0' ) + { + isc_mem_put(mgr->mctx, mgr->dhcdbd_name, strlen(mgr->dhcdbd_name) + 1); + mgr->dhcdbd_name = 0L; + dbus_mgr_log_err("D-BUS dhcdbd subscription disabled."); + return; + } + if( (mgr->dhcdbd_name == 0L) + ||( strcmp( mgr->dhcdbd_name, new_owner) != 0 ) + ) + { + if( mgr->dhcdbd_name != 0L ) + { + isc_mem_put(mgr->mctx, mgr->dhcdbd_name, strlen(mgr->dhcdbd_name)+1); + mgr->dhcdbd_name = 0L; + } + mgr->dhcdbd_name = isc_mem_get(mgr->mctx, strlen(new_owner) + 1); + if( mgr->dhcdbd_name == 0L ) + return; + strcpy( mgr->dhcdbd_name, new_owner ); + dbus_mgr_subscribe_to_dhcdbd( mgr ); + } + }else + if( ( mgr->dhcdbd_name != 0L ) + && ( strcmp(mgr->dhcdbd_name, name_owned) == 0L ) + && ( *new_owner == '\0' ) + ) + { + isc_mem_put(mgr->mctx, mgr->dhcdbd_name, strlen(mgr->dhcdbd_name)); + mgr->dhcdbd_name = 0L; + dbus_mgr_log_err("D-BUS dhcdbd subscription disabled."); + } +} + +static int dbus_mgr_dhc_if_comparator( const void *p1, const void *p2 ) +{ + return( strcmp( ((const DHC_IF*)p1)->if_name, ((const DHC_IF*)p2)->if_name) ); +} + +static +dns_name_t *dbus_mgr_if_reverse_ip_name +( ns_dbus_mgr_t *mgr, + struct in_addr ip_address, + struct in_addr subnet_mask +) +{ + dns_name_t *dns_name =0L; + dns_fixedname_t *fixedname=0L; + char name [ DNS_NAME_FORMATSIZE ], *p; + uint32_t ip = (ntohl(ip_address.s_addr) & ntohl(subnet_mask.s_addr)), i; + isc_buffer_t buffer; + isc_result_t result; + + if( (ip == 0) || (ip == 0xffffffff) ) + return 0L; + + for(i = 8, p = name; (i < 32); i += 8) + if( ip & ( 0xff << i ) ) + p += sprintf(p, "%u.", (((ip & ( 0xff << i )) >> i ) & 0xff) ); + + if( p > name ) + { + p += sprintf(p, "in-addr.arpa"); + isc_buffer_init( &buffer, name, p - name ); + isc_buffer_add(&buffer, p - name); + + fixedname = isc_mem_get( mgr->mctx, sizeof( dns_fixedname_t )); + + dns_fixedname_init(fixedname); + + dns_name = dns_fixedname_name(fixedname); + + result= dns_name_fromtext + ( dns_name, &buffer, dns_rootname, ISC_FALSE, NULL + ); + + ISC_LINK_INIT(dns_name, link); + if( result == ISC_R_SUCCESS ) + return dns_name; + } + return 0L; +} + +static void +dbus_mgr_free_dhc( void *p ) +{ + DHC_IF *d_if = p; + dns_name_t *dn; + isc_sockaddr_t *sa; + + isc_mem_put( ns_g_mctx, d_if->if_name, strlen(d_if->if_name) + 1); + for( sa = ISC_LIST_HEAD( d_if->dns ); + sa != NULL; + sa = ISC_LIST_HEAD( d_if->dns ) + ) + { + if( ISC_LINK_LINKED( sa, link ) ) + ISC_LIST_UNLINK( d_if->dns, sa, link ); + isc_mem_put(ns_g_mctx, sa, sizeof(isc_sockaddr_t)); + } + for( dn = ISC_LIST_HEAD( d_if->dn ); + dn != NULL; + dn = ISC_LIST_HEAD( d_if->dn ) + ) + { + if( ISC_LINK_LINKED( dn, link ) ) + ISC_LIST_UNLINK( d_if->dn, dn, link ); + isc_mem_put( ns_g_mctx, dn, sizeof( dns_fixedname_t ) ); + } + isc_mem_put( ns_g_mctx, d_if, sizeof(DHC_IF)); +} + +static void +dbus_mgr_handle_dhcdbd_message +( + ns_dbus_mgr_t *mgr, + const char *path, + const char *member, + dbus_svc_MessageHandle msg +) +{ + DBUS_SVC dbus = mgr->dbus; + DHC_IF *d_if, *const*d_ifpp, dif; + DHC_State dhc_state; + char *if_name, *opt_name, error_name[1024]="", error_message[1024]=""; + uint8_t *value=0L; + uint32_t length; + isc_result_t result; + isc_sockaddr_t *sa = 0L; + dns_name_t *dn = 0L; + struct in_addr *ip; + in_port_t port; + char dnBuf[ DNS_NAME_FORMATSIZE ]; + isc_buffer_t buffer; + DBusMgrInitialFwdr *ifwdr, *const*ifwdpp, ifwd; + ISC_LIST(DBusMgrInitialFwdr) ifwdrList; + DNSNameList nameList; + dbus_mgr_log_dbg("Got dhcdbd message: %s %s %p", path, member, msg ); + + if( ( if_name = strrchr(path,'/') ) == 0L ) + { + dbus_mgr_log_err("bad path in dhcdbd message:", path); + return; + } + + ++if_name; + dif.if_name = if_name; + + if( ((d_ifpp=tfind( &dif, &(mgr->dhc_if), dbus_mgr_dhc_if_comparator)) == 0L) + ||((d_if = *d_ifpp) == 0L) + ) + { + d_if = isc_mem_get( mgr->mctx, sizeof(DHC_IF)); + if( d_if == 0L ) + { + dbus_mgr_log_err("out of memory"); + return; + } + memset(d_if, '\0', sizeof(DHC_IF)); + if((d_if->if_name = isc_mem_get( mgr->mctx, strlen(if_name) + 1)) == 0L) + { + dbus_mgr_log_err("out of memory"); + return; + } + strcpy(d_if->if_name, if_name); + d_if->dhc_state = DHC_INVALID; + d_if->previous_state = DHC_INVALID; + ISC_LIST_INIT( d_if->dn ); + ISC_LIST_INIT( d_if->dns ); + if( tsearch( d_if, &(mgr->dhc_if), dbus_mgr_dhc_if_comparator) == 0L ) + { + dbus_mgr_log_err("out of memory"); + return; + } + } + + if( strcmp(member, "reason") == 0 ) + { + if( (!dbus_svc_get_args( dbus, msg, + TYPE_STRING, &opt_name, + TYPE_ARRAY, TYPE_BYTE, &value, &length, + TYPE_INVALID + ) + ) + ||( value == 0L) + ||( length != sizeof(uint32_t)) + ||( *((uint32_t*)value) > DHC_END_OPTIONS) + ) + { + dbus_mgr_log_err("Invalid DHC reason value received from dhcdbd"); + return; + } + dhc_state = (DHC_State) *((uint32_t*)value); + dbus_mgr_log_dbg("reason: %d %d %d", dhc_state, d_if->dhc_state, d_if->previous_state); + switch( dhc_state ) + { + + case DHC_END_OPTIONS: + switch( d_if->dhc_state ) + { + case DHC_END_OPTIONS: + break; + + case DHC_RENEW: + case DHC_REBIND: + if( ( d_if->previous_state != DHC_INVALID ) + &&( d_if->previous_state != DHC_RELEASE ) + ) break; + /* DHC_RENEW means the same lease parameters were obtained. + * Only do configuration if we started up with existing dhclient + * which has now renewed - else we are already configured correctly. + */ + dbus_mgr_log_err("D-BUS: existing dhclient for interface %s RENEWed lease", if_name); + + case DHC_REBOOT: + case DHC_BOUND: + d_if->previous_state = d_if->dhc_state; + d_if->dhc_state = DHC_BOUND; + if( (dn = dbus_mgr_if_reverse_ip_name(mgr, d_if->ip, d_if->subnet_mask )) != 0L ) + { + ISC_LIST_APPEND(d_if->dn, dn, link ); + } + if( ( ISC_LIST_HEAD( d_if->dn ) != NULL ) + &&( ISC_LIST_HEAD( d_if->dns ) != NULL ) + ) + { + dbus_mgr_log_err("D-BUS: dhclient for interface %s acquired new lease - creating forwarders.", + if_name + ); + result = dbus_mgr_set_forwarders( mgr, &(d_if->dn), &(d_if->dns), dns_fwdpolicy_only ); + if( result != ISC_R_SUCCESS ) + { + dbus_mgr_log_err("D-BUS: forwarder configuration failed: %s", isc_result_totext(result)); + } + } + break; + + case DHC_STOP: + case DHC_TIMEOUT: + case DHC_FAIL: + case DHC_EXPIRE: + case DHC_RELEASE: + d_if->previous_state = d_if->dhc_state; + d_if->dhc_state = DHC_RELEASE; + if( ISC_LIST_HEAD( d_if->dn ) != NULL ) + { + dbus_mgr_log_err("D-BUS: dhclient for interface %s released lease - removing forwarders.", + if_name); + for( sa = ISC_LIST_HEAD( d_if->dns ); + sa != 0L; + sa = ISC_LIST_HEAD( d_if->dns ) + ) + { + if( ISC_LINK_LINKED( sa, link ) ) + ISC_LIST_UNLINK( d_if->dns, sa, link ); + isc_mem_put( mgr->mctx, sa, sizeof(isc_sockaddr_t)); + } + ISC_LIST_INIT( d_if->dns ); + ISC_LIST_INIT( ifwdrList ); + + for( dn = ISC_LIST_HEAD( d_if->dn ); + dn != 0L; + dn = ISC_LIST_NEXT( dn, link ) + ) + { + dns_name_init( &(ifwd.dn), NULL ); + isc_buffer_init( &buffer, dnBuf, DNS_NAME_FORMATSIZE); + dns_name_setbuffer( &(ifwd.dn), &buffer); + dns_name_copy(dn, &(ifwd.dn), NULL); + if( ((ifwdpp = tfind(&ifwd, &(mgr->ifwdt), dbus_mgr_ifwdr_comparator)) != 0L ) + &&((ifwdr = *ifwdpp) != 0L) + ) + { + ISC_LIST_APPEND( ifwdrList, ifwdr, link ); + } + } + + result = dbus_mgr_set_forwarders( mgr, &(d_if->dn), &(d_if->dns), dns_fwdpolicy_none ); + if( result != ISC_R_SUCCESS ) + { + dbus_mgr_log_err("D-BUS: removal of forwarders failed: %s", isc_result_totext(result)); + } + + for( dn = ISC_LIST_HEAD( d_if->dn ); + dn != 0L; + dn = ISC_LIST_HEAD( d_if->dn ) + ) + { + if( ISC_LINK_LINKED( dn, link ) ) + ISC_LIST_UNLINK( d_if->dn, dn, link ); + isc_mem_put( mgr->mctx, dn, sizeof( dns_fixedname_t ) ); + } + ISC_LIST_INIT( d_if->dn ); + + for( ifwdr = ISC_LIST_HEAD( ifwdrList ); + ifwdr != 0L; + ifwdr = ISC_LIST_HEAD( ifwdrList ) + ) + { + if( ISC_LINK_LINKED( ifwdr, link ) ) + ISC_LIST_UNLINK( ifwdrList, ifwdr, link ); + ISC_LINK_INIT(ifwdr, link); + ISC_LIST_INIT(nameList); + ISC_LINK_INIT(&(ifwdr->dn), link); + ISC_LIST_APPEND( nameList, &(ifwdr->dn), link ); + result = dbus_mgr_set_forwarders( mgr, &nameList, + &(ifwdr->sa), + ifwdr->fwdpolicy + ); + if( result != ISC_R_SUCCESS ) + { + dbus_mgr_log_err("D-BUS: restore of forwarders failed: %s", isc_result_totext(result)); + } + } + } + + case DHC_ABEND: + case DHC_END: + case DHC_NBI: + case DHC_PREINIT: + case DHC_MEDIUM: + case DHC_START: + case DHC_INVALID: + default: + break; + } + break; + + case DHC_BOUND: + case DHC_REBOOT: + case DHC_REBIND: + case DHC_RENEW: + case DHC_STOP: + case DHC_TIMEOUT: + case DHC_FAIL: + case DHC_EXPIRE: + case DHC_RELEASE: + d_if->previous_state = d_if->dhc_state; + d_if->dhc_state = dhc_state; + + case DHC_ABEND: + case DHC_END: + case DHC_NBI: + case DHC_PREINIT: + case DHC_MEDIUM: + case DHC_START: + case DHC_INVALID: + default: + break; + } + }else + if( strcmp( member, "domain_name" ) == 0 ) + { + if( (!dbus_svc_get_args( dbus, msg, + TYPE_STRING, &opt_name, + TYPE_ARRAY, TYPE_BYTE, &value, &length, + TYPE_INVALID + ) + ) + ||( value == 0L) + ||( length == 0) + ) + { + dbus_mgr_log_err("Invalid domain_name value received from dhcdbd"); + return; + } + dbus_mgr_log_dbg("domain-name %s", (char*)value); + dbus_mgr_get_name_list( mgr, (char*)value, &(d_if->dn), error_name, error_message ); + if( ( error_message[0] != '\0' ) || (ISC_LIST_HEAD(d_if->dn) == 0L )) + { + dbus_mgr_log_err("Bad domain_name value: %s", error_message ); + } + }else + if( strcmp( member, "domain_name_servers") == 0 ) + { + if( (!dbus_svc_get_args( dbus, msg, + TYPE_STRING, &opt_name, + TYPE_ARRAY, TYPE_BYTE, &value, &length, + TYPE_INVALID + ) + ) + ||( value == 0L) + ||( length == 0) + ) + { + dbus_mgr_log_err("Invalid domain_name_servers value received from dhcdbd"); + return; + } + for(ip = (struct in_addr*) value; ip < ((struct in_addr*)(value + length)); ip++) + { + dbus_mgr_log_dbg("domain-name-servers: %s", inet_ntop(AF_INET, value, error_name, 16)); + sa = isc_mem_get(mgr->mctx, sizeof(isc_sockaddr_t)); + memset(sa, '\0', sizeof(isc_sockaddr_t)); + sa->type.sin.sin_addr = *ip; + sa->type.sa.sa_family = AF_INET; + sa->length = sizeof(sa->type.sin); + result = ns_config_getport(ns_g_config, &(port) ); + if( result != ISC_R_SUCCESS ) + port = 53; + sa->type.sin.sin_port = htons( port ); + ISC_LIST_APPEND(d_if->dns, sa, link); + } + }else + if( strcmp(member, "ip_address") == 0) + { + if( (!dbus_svc_get_args( dbus, msg, + TYPE_STRING, &opt_name, + TYPE_ARRAY, TYPE_BYTE, &value, &length, + TYPE_INVALID + ) + ) + ||( value == 0L) + ||( length != sizeof(struct in_addr) ) + ) + { + dbus_mgr_log_err("Invalid ip_address value received from dhcdbd"); + return; + } + dbus_mgr_log_dbg("ip-address: %s", inet_ntop(AF_INET, value, error_name, 16)); + d_if->ip = *((struct in_addr*)value); + + }else + if( strcmp(member, "subnet_mask") == 0 ) + { + if( (!dbus_svc_get_args( dbus, msg, + TYPE_STRING, &opt_name, + TYPE_ARRAY, TYPE_BYTE, &value, &length, + TYPE_INVALID + ) + ) + ||( value == 0L) + ||( length != sizeof(struct in_addr) ) + ) + { + dbus_mgr_log_err("Invalid subnet_mask value received from dhcdbd"); + return; + } + dbus_mgr_log_dbg("subnet-mask: %s", inet_ntop(AF_INET, value, error_name, 16)); + d_if->subnet_mask = *((struct in_addr*)value); + } +} + +static +dbus_svc_HandlerResult +dbus_mgr_message_handler +( + DBusMsgHandlerArgs +) +{ + char error_name[1024], error_message[1024]; + ns_dbus_mgr_t *mgr = object; + uint32_t new_serial; + + if_suffix = prefix = suffix = prefixObject = 0L; + + dbus_mgr_log_dbg("D-BUS message: %u %u %u %s %s %s %s %s %s", + type, reply_expected, serial, destination, path, member, interface, sender, signature + ); + + if ( ( type == SIGNAL ) + &&( strcmp(path,"/org/freedesktop/DBus/Local") == 0 ) + ) + { + if( strcmp(member,"Disconnected") == 0 ) + dbus_mgr_dbus_shutdown_handler( mgr ); + }else + if( ( type == SIGNAL ) + &&( strcmp(path,"/org/freedesktop/DBus") == 0 ) + &&(strcmp(member,"NameOwnerChanged") == 0) + &&(strcmp(signature, "sss") == 0) + ) + { + dbus_mgr_check_dhcdbd_state( mgr, msg ); + }else + if( ( type == SIGNAL ) + &&( (sender != 0L) && (mgr->dhcdbd_name != 0L) && (strcmp(sender,mgr->dhcdbd_name) == 0)) + &&( strcmp(interface,"com.redhat.dhcp.subscribe.binary") == 0 ) + ) + { + dbus_mgr_handle_dhcdbd_message( mgr, path, member, msg ); + }else + if( (type == CALL) + &&( strcmp(destination, DBUSMGR_DESTINATION)==0) + &&( strcmp(path, DBUSMGR_OBJECT_PATH)==0) + ) + { + if( strcmp(member, "SetForwarders") == 0 ) + dbus_mgr_handle_set_forwarders + ( mgr, dbus, reply_expected, serial, path, member, interface, sender, msg ); + else + if( strcmp(member, "GetForwarders") == 0 ) + { + if( *signature != '\0' ) + dbus_mgr_handle_get_forwarders + ( dbus, reply_expected, serial, path, member, interface, sender, msg ); + else + dbus_mgr_handle_list_forwarders + ( dbus, reply_expected, serial, path, member, interface, sender, msg ); + }else + if( reply_expected ) + { + sprintf(error_name, "InvalidOperation"); + sprintf(error_message, "Unrecognized path / interface / member"); + dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member, + TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID + ); + } + } + return HANDLED; +} + +static void +dbus_mgr_read_watch_activated(isc_task_t *t, isc_event_t *ev) +{ + DBusMgrSocket *sfd = (DBusMgrSocket*)(ev->ev_arg); + t = t; + isc_mem_put(sfd->mgr->mctx, ev, ev->ev_size); + dbus_mgr_log_dbg("watch %d READ",sfd->fd); + isc_socket_fd_handle_reads( sfd->sock, sfd->ser ); + dbus_svc_handle_watch( sfd->mgr->dbus, sfd->fd, WATCH_ENABLE | WATCH_READ ); +} + +static void +dbus_mgr_write_watch_activated(isc_task_t *t, isc_event_t *ev) +{ + DBusMgrSocket *sfd = (DBusMgrSocket*)(ev->ev_arg); + t = t; + isc_mem_put(sfd->mgr->mctx, ev, ev->ev_size); + dbus_mgr_log_dbg("watch %d WRITE",sfd->fd); + isc_socket_fd_handle_writes( sfd->sock, sfd->ser ); + dbus_svc_handle_watch( sfd->mgr->dbus, sfd->fd, WATCH_ENABLE | WATCH_WRITE ); +} + +static void +dbus_mgr_watches_selected(isc_task_t *t, isc_event_t *ev) +{ + ns_dbus_mgr_t *mgr = (ns_dbus_mgr_t*)(ev->ev_arg); + t = t; + isc_mem_put(mgr->mctx, ev, ev->ev_size); + if( ( mgr->dbus == 0L ) || (mgr->sockets == 0L)) + { + return; + } + dbus_mgr_log_dbg("watches selected"); + dbus_svc_dispatch( mgr->dbus ); + dbus_mgr_log_dbg("dispatch complete"); +} + +static int dbus_mgr_socket_comparator( const void *p1, const void *p2 ) +{ + return( ( ((const DBusMgrSocket*)p1)->fd + == ((const DBusMgrSocket*)p2)->fd + ) ? 0 + : ( ((const DBusMgrSocket*)p1)->fd + > ((const DBusMgrSocket*)p2)->fd + ) ? 1 + : -1 + ); +} + +static void +dbus_mgr_watch_handler( int fd, dbus_svc_WatchFlags flags, void *mgrp ) +{ + ns_dbus_mgr_t *mgr = mgrp; + DBusMgrSocket sockFd, *sfd=0L, *const*spp=0L; + isc_result_t result=ISC_R_SUCCESS; + isc_socketevent_t *sev; + isc_event_t *pev[1]; + + if(mgr == 0L) + return; + + if( (flags & 7) == WATCH_ERROR ) + return; + + sockFd.fd = fd; + + dbus_mgr_log_dbg("watch handler: fd %d %d", fd, flags); + + if( ((spp = tfind( &sockFd, &(mgr->sockets), dbus_mgr_socket_comparator) ) == 0L ) + ||((sfd = *spp) == 0L ) + ) + { + if( ( flags & WATCH_ENABLE ) == 0 ) + return; + + sfd = isc_mem_get(mgr->mctx, sizeof(DBusMgrSocket)); + if( sfd == 0L ) + { + dbus_mgr_log_err("dbus_mgr: out of memory" ); + return; + } + sfd->fd = fd; + sfd->mgr = mgr; + sfd->ser = sfd->sew = sfd->sel = 0L; + + if( tsearch(sfd, &(mgr->sockets), dbus_mgr_socket_comparator) == 0L ) + { + dbus_mgr_log_err("dbus_mgr: out of memory" ); + isc_mem_put(mgr->mctx, sfd, sizeof(DBusMgrSocket)); + return; + } + sfd->sock = 0L; + result = isc_socket_create( mgr->socketmgr, fd, isc_sockettype_fd, &(sfd->sock) ); + if( result != ISC_R_SUCCESS ) + { + dbus_mgr_log_err("dbus_mgr: isc_socket_create failed: %s", + isc_result_totext(result) + ); + tdelete(sfd, &(mgr->sockets), dbus_mgr_socket_comparator); + isc_mem_put(mgr->mctx, sfd, sizeof(DBusMgrSocket)); + return; + } + } + + if( (flags & WATCH_ENABLE) == WATCH_ENABLE ) + { + if( (flags & WATCH_READ) == WATCH_READ ) + { + if( sfd->ser == 0L ) + { + sfd->ser = (isc_socketevent_t *) + isc_event_allocate + ( + mgr->mctx, mgr->task, + ISC_SOCKEVENT_READ_READY, + dbus_mgr_read_watch_activated, + sfd, + sizeof(isc_socketevent_t) + ); + + if( sfd->ser == 0L ) + { + dbus_mgr_log_err("dbus_mgr: out of memory" ); + tdelete(sfd, &(mgr->sockets), dbus_mgr_socket_comparator); + isc_mem_put(mgr->mctx, sfd, sizeof(DBusMgrSocket)); + return; + } + + sev = isc_socket_fd_handle_reads(sfd->sock, sfd->ser ); + + }else + { + sev = isc_socket_fd_handle_reads(sfd->sock, sfd->ser ); + } + } + if( (flags & WATCH_WRITE) == WATCH_WRITE ) + { + if( sfd->sew == 0L ) + { + sfd->sew = (isc_socketevent_t *) + isc_event_allocate + ( + mgr->mctx, mgr->task, + ISC_SOCKEVENT_WRITE_READY, + dbus_mgr_write_watch_activated, + sfd, + sizeof(isc_socketevent_t) + ); + if( sfd->sew == 0L ) + { + dbus_mgr_log_err("dbus_mgr: out of memory" ); + tdelete(sfd, &(mgr->sockets), dbus_mgr_socket_comparator); + isc_mem_put(mgr->mctx, sfd, sizeof(DBusMgrSocket)); + return; + } + + sev = isc_socket_fd_handle_writes(sfd->sock, sfd->sew ); + + }else + { + sev = isc_socket_fd_handle_writes(sfd->sock, sfd->sew ); + } + } + if( (sfd->ser != 0L) || (sfd->sew != 0L) ) + { + if( sfd->sel == 0L ) + { + sfd->sel = (isc_socketevent_t *) + isc_event_allocate + ( + mgr->mctx, mgr->task, + ISC_SOCKEVENT_SELECTED, + dbus_mgr_watches_selected, + mgr, + sizeof(isc_socketevent_t) + ); + if( sfd->sel == 0L ) + { + dbus_mgr_log_err("dbus_mgr: out of memory" ); + tdelete(sfd, &(mgr->sockets), dbus_mgr_socket_comparator); + isc_mem_put(mgr->mctx, sfd, sizeof(DBusMgrSocket)); + return; + } + + sev = isc_socket_fd_handle_selected(sfd->sock, sfd->sel ); + + }else + { + sev = isc_socket_fd_handle_selected(sfd->sock, sfd->sel); + } + } + }else + { + dbus_mgr_log_dbg("watch %d disabled",fd); + if(flags & WATCH_READ) + { + sev = isc_socket_fd_handle_reads( sfd->sock, 0L ); + if( sev != 0L ) + { + pev[0]=(isc_event_t*)sev; + isc_event_free(pev); + } + sfd->ser = 0L; + } + + if( flags & WATCH_WRITE ) + { + sev = isc_socket_fd_handle_writes( sfd->sock, 0L ); + if( sev != 0L ) + { + pev[0]=(isc_event_t*)sev; + isc_event_free(pev); + } + sfd->sew = 0L; + } + + if( (sfd->ser == 0L) && (sfd->sew == 0L) ) + { + sev = isc_socket_fd_handle_selected( sfd->sock, 0L ); + if( sev != 0L ) + { + pev[0]=(isc_event_t*)sev; + isc_event_free(pev); + } + sfd->sel = 0L; + + tdelete(sfd, &(mgr->sockets), dbus_mgr_socket_comparator); + + isc_mem_put(mgr->mctx, sfd, sizeof(DBusMgrSocket)); + } + } +} + +static +void dbus_mgr_close_socket( const void *p, const VISIT which, const int level) +{ + DBusMgrSocket *const*spp=p, *sfd; + isc_event_t *ev ; + int i = level ? 0 :1; + i &= i; + + if( (spp==0L) || ((sfd = *spp)==0L) + ||((which != leaf) && (which != postorder)) + ) return; + + if( sfd->ser != 0L ) + { + ev = (isc_event_t *)isc_socket_fd_handle_reads(sfd->sock, 0); + if( ev != 0L ) + isc_event_free((isc_event_t **)&ev); + sfd->ser = 0L; + } + + if( sfd->sew != 0L ) + { + ev = (isc_event_t *)isc_socket_fd_handle_writes(sfd->sock, 0); + if( ev != 0L ) + isc_event_free((isc_event_t **)&ev); + sfd->sew = 0L; + } + + if( sfd->sel != 0L ) + { + ev = (isc_event_t *)isc_socket_fd_handle_selected(sfd->sock, 0); + if( ev != 0L ) + isc_event_free((isc_event_t **)&ev); + sfd->sel = 0L; + dbus_mgr_log_dbg("CLOSED socket %d", sfd->fd); + } +} + +static +void dbus_mgr_destroy_socket( void *p ) +{ + DBusMgrSocket *sfd = p; + + isc_mem_put( sfd->mgr->mctx, sfd, sizeof(DBusMgrSocket) ); +} diff --git a/contrib/dbus/dbus_mgr.h b/contrib/dbus/dbus_mgr.h new file mode 100644 index 0000000..78be0d0 --- /dev/null +++ b/contrib/dbus/dbus_mgr.h @@ -0,0 +1,37 @@ +/* dbus_mgr.h + * + * named module to provide dynamic forwarding zones in + * response to D-BUS dhcp events + * + * Copyright(C) Jason Vas Dias, Red Hat Inc., 2005 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation at + * http://www.fsf.org/licensing/licenses/gpl.txt + * and included in this software distribution as the "LICENSE" file. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +extern isc_result_t +dbus_mgr_create +( isc_mem_t *mctx, + isc_taskmgr_t *taskmgr, + isc_socketmgr_t *socketmgr, + isc_timermgr_t *timermgr, + ns_dbus_mgr_t **dbus_mgr +); + +extern void +dbus_mgr_shutdown +( ns_dbus_mgr_t *dus_mgr_t +); + + + + + diff --git a/contrib/dbus/dbus_service.c b/contrib/dbus/dbus_service.c new file mode 100644 index 0000000..47d55d5 --- /dev/null +++ b/contrib/dbus/dbus_service.c @@ -0,0 +1,1161 @@ +/* dbus_service.c + * + * D-BUS Service Utilities + * + * Provides MINIMAL utilities for construction of D-BUS "Services". + * + * Copyright(C) Jason Vas Dias, Red Hat Inc., 2005 + * Modified by Adam Tkac, Red Hat Inc., 2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation at + * http://www.fsf.org/licensing/licenses/gpl.txt + * and included in this software distribution as the "LICENSE" file. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <sys/types.h> +#include <unistd.h> +#include <linux/limits.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/select.h> +#include <sys/wait.h> +#include <sys/ioctl.h> +#include <time.h> +#include <signal.h> +#include <syslog.h> +#include <fcntl.h> +#include <string.h> +extern size_t strnlen(const char *s, size_t maxlen); +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <ifaddrs.h> +#include <search.h> +#include <getopt.h> +typedef void (*__free_fn_t) (void *__nodep); +extern void tdestroy (void *__root, __free_fn_t __freefct); +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <errno.h> +#define DBUS_API_SUBJECT_TO_CHANGE "Very Annoying and Silly!" +#include <dbus/dbus.h> + +#include <named/dbus_service.h> +#include <isc/result.h> + +typedef struct dbcs_s +{ + DBusConnection *connection; + DBusDispatchStatus dispatchStatus; + uint32_t status; + dbus_svc_WatchHandler wh; + void * wh_arg; + const char * unique_name; + dbus_svc_MessageHandler mh; + void * def_mh_obj; + dbus_svc_MessageHandler mf; + void * def_mf_obj; + dbus_svc_ShutdownHandler sh; + void * sh_obj; + dbus_svc_ErrorHandler eh; + dbus_svc_ErrorHandler dh; + /*{ glibc b-trees: */ + void * roots; + void * timeouts; + void * watches; + void * filters; + /*}*/ + int n; + fd_set r_fds; + fd_set s_r_fds; + fd_set w_fds; + fd_set s_w_fds; + fd_set e_fds; + fd_set s_e_fds; + DBusMessage *currentMessage; + int rejectMessage; +} DBusConnectionState; + +typedef struct root_s +{ + char *path; + char *if_prefix; + DBUS_SVC cs; + dbus_svc_MessageHandler mh; + void *object; + void *tree; +} Root; + +typedef struct mhn_s +{ + char *path; + dbus_svc_MessageHandler mh; + void *object; +} MessageHandlerNode; + +typedef struct mfn_s +{ + DBusConnectionState *cs; + dbus_svc_MessageHandler mf; + void *obj; + int n_matches; + char **matches; +} MessageFilterNode; + +typedef struct dbto_s +{ + DBusTimeout *to; + DBusConnectionState *cs; + struct timeval tv; +} DBusConnectionTimeout; + +static void no_free( void *p){ p=0; } + +static int ptr_key_comparator( const void *p1, const void *p2 ) +{ + return + ( (p1 == p2) + ? 0 + :( (p1 > p2) + ? 1 + : -1 + ) + ); +} + +static DBusHandlerResult +default_message_filter +( DBusConnection *connection, + DBusMessage *message, + void *p +) +{ + DBusConnectionState *cs = p; + uint32_t type =dbus_message_get_type( message ), + serial =dbus_message_get_serial( message ); + uint8_t reply =dbus_message_get_no_reply( message )==0; + const char + *path = dbus_message_get_path( message ), + *dest = dbus_message_get_destination( message ), + *member = dbus_message_get_member( message ), + *interface=dbus_message_get_interface( message ), + *sender =dbus_message_get_sender( message ), + *signature=dbus_message_get_signature( message ); + connection = connection; + if(cs->mf) + return + (*(cs->mf))( cs, type, reply, serial, dest, path, member, interface, 0L, + sender, signature, message, 0L, 0L, 0L, cs->def_mf_obj + ) ; + return HANDLED; +} + +uint8_t +dbus_svc_add_filter +( DBusConnectionState *cs, dbus_svc_MessageHandler mh, void *obj, int n_matches, ... ) +{ + DBusError error; + va_list va; + char *m; + + va_start(va, n_matches ); + + cs->mf = mh; + cs->def_mf_obj = obj; + + if ( ! dbus_connection_add_filter (cs->connection, default_message_filter, cs, NULL)) + { + if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_add_filter: dbus_connection_add_filter failed"); + va_end(va); + return( 0 ); + } + + if( n_matches ) + { + memset(&error,'\0',sizeof(DBusError)); + dbus_error_init(&error); + while( n_matches-- ) + { + m = va_arg(va, char* ) ; + + dbus_bus_add_match(cs->connection, m, &error); + + if( dbus_error_is_set(&error)) + { + if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_add_filter: dbus_bus_add_match failed for %s: %s %s", + m, error.name, error.message + ); + va_end(va); + return(0); + } + } + } + va_end(va); + return( 1 ); +} + + +uint8_t +dbus_svc_get_args_va(DBusConnectionState *cs, DBusMessage* msg, dbus_svc_DataType firstType, va_list va) +{ + DBusError error; + memset(&error,'\0',sizeof(DBusError)); + dbus_error_init(&error); + if( (!dbus_message_get_args_valist(msg, &error, firstType, va)) || dbus_error_is_set(&error) ) + { + if( dbus_error_is_set(&error) ) + { + if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_get_args failed: %s %s",error.name, error.message); + dbus_error_free(&error); + }else + if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_get_args failed: dbus_message_get_args_valist failed"); + return( 0 ); + } + return( 1 ); +} + +uint8_t +dbus_svc_get_args(DBusConnectionState *cs, DBusMessage* msg, dbus_svc_DataType firstType, ...) +{ + va_list va; + uint8_t r; + va_start(va, firstType); + r = dbus_svc_get_args_va( cs, msg, firstType, va); + va_end(va); + return r; +} + +uint8_t +dbus_svc_send_va +( DBusConnectionState *cs, + dbus_svc_MessageType type, + int32_t reply_serial, + uint32_t *new_serial, + const char *destination, + const char *path, + const char *interface, + const char *member, + dbus_svc_DataType firstType, + va_list va +) +{ + DBusMessageIter iter; + char *e; + DBusMessage *msg = + dbus_svc_new_message + ( cs, + type, + reply_serial, + destination, + path, + interface, + member + ); + + if(msg == 0L) + { + if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_send: dbus_svc_new_message failed"); + return 0; + } + + if( type != DBUS_MESSAGE_TYPE_ERROR ) + { + if( !dbus_message_append_args_valist( msg, firstType, va ) ) + { + if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_send: dbus_message_append_args_valist failed"); + return 0; + } + }else + { + if( firstType == DBUS_TYPE_STRING ) + { + e = 0L; + e = va_arg( va, char* ); + if( (e == 0L) || !dbus_message_set_error_name( msg, e ) ) + { + if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_send: dbus_message_set_error_name failed"); + return 0; + } + firstType = va_arg(va, int); + if( firstType == DBUS_TYPE_STRING ) + { + e = 0L; + e = va_arg( va, char* ); + if( e == 0L ) + { + if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_send: NULL error message"); + return 0; + } + dbus_message_iter_init_append (msg, &iter); + if( !dbus_message_iter_append_basic + (&iter, DBUS_TYPE_STRING, &e) + ) + { + if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_send: dbus_message_iter_append_basic failed"); + return 0; + } + } + }else + { + if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_send: unhandled type for error name: %c", firstType); + return 0; + } + } + + if( !dbus_connection_send(cs->connection, msg, new_serial) ) + { + if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_send: dbus_message_send failed"); + return 0; + } + if( cs->dh != 0L ) (*(cs->dh))("Sending message"); + dbus_connection_flush(cs->connection); + return 1; +} + +uint8_t +dbus_svc_send +( DBusConnectionState *cs, + dbus_svc_MessageType type, + int32_t reply_serial, + uint32_t *new_serial, + const char *destination, + const char *path, + const char *interface, + const char *member, + dbus_svc_DataType firstType, + ... +) +{ + uint8_t r; + va_list va; + va_start(va, firstType); + r = dbus_svc_send_va(cs, type, reply_serial, new_serial, destination, path,interface,member,firstType,va); + va_end(va); + return ( r ) ; +} + +dbus_svc_MessageHandle +dbus_svc_new_message +( DBusConnectionState* cs, + dbus_svc_MessageType type, + int32_t reply_serial, + const char *destination, + const char *path, + const char *interface, + const char *member +) +{ + DBusMessage *msg = dbus_message_new(type); + + if( msg == 0L) + { + if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_new_message: dbus_message_set_reply_serial failed"); + return 0; + } + + if( reply_serial != -1 ) + { + if( !dbus_message_set_reply_serial(msg,reply_serial) ) + { + if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_new_message: dbus_message_set_reply_serial failed"); + return 0; + } + } + + if( (destination !=0L) && !dbus_message_set_destination(msg, destination) ) + { + if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_new_message: dbus_message_set_destination failed"); + return 0; + } + + if( !dbus_message_set_path(msg, path) ) + { + if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_new_message: dbus_message_set_path failed"); + return 0; + } + + if( ! dbus_message_set_interface(msg,interface) ) + { + if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_new_message: dbus_message_set_interface failed - %s", interface); + return 0; + } + + if( !dbus_message_set_member(msg,member) ) + { + if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_new_message: dbus_message_set_member failed"); + return 0; + } + + return msg; +} + +extern uint8_t +dbus_svc_send_message +( + DBusConnectionState *cs, + dbus_svc_MessageHandle msg, + uint32_t *new_serial +) +{ + if( !dbus_connection_send(cs->connection, msg, new_serial) ) + { + if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_send: dbus_message_send failed"); + return 0; + } + if( cs->dh != 0L ) (*(cs->dh))("Sending message"); + dbus_connection_flush(cs->connection); + return 1; +} + +uint8_t +dbus_svc_message_append_args(DBusConnectionState *cs, dbus_svc_MessageHandle msg, dbus_svc_DataType firstType, ...) +{ + va_list va; + va_start(va, firstType); + if( !dbus_message_append_args_valist( msg, firstType, va ) ) + { + if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_send: dbus_message_append_args failed"); + va_end(va); + return 0; + } + va_end(va); + return ( 1 ) ; +} + +dbus_svc_MessageHandle +dbus_svc_call +( DBusConnectionState *cs, + const char *destination, + const char *path, + const char *member, + const char *interface, + dbus_svc_DataType firstType, + ... +) +{ + DBusMessage *message=0L, *reply=0L; + va_list va; + DBusError error; + int reply_timeout=20000; + + va_start(va, firstType); + + memset(&error,'\0',sizeof(DBusError)); + dbus_error_init(&error); + + if(( message = + dbus_message_new_method_call + ( destination, + path, + interface, + member + ) + ) == 0L + ) + { + if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_call: dbus_message_new_method_call failed"); + va_end(va); + return(0L); + }; + + if( !dbus_message_append_args_valist( message, firstType, va ) ) + { + if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_call: dbus_message_append_args_valist failed"); + va_end(va); + return(0L); + } + + if((reply = + dbus_connection_send_with_reply_and_block + (cs->connection, + message, reply_timeout, + &error + ) + ) == 0L + ) + { + if( cs->eh != 0L ) (*(cs->eh))("dbus_svc_call: dbus_message_send_with_reply_and_block failed: %s %s", + error.name, error.message + ); + va_end(va); + return(0L); + } + va_end(va); + return reply; +} + +dbus_svc_MessageIterator +dbus_svc_message_iterator_new( DBusConnectionState *cs, DBusMessage *msg) +{ + DBusMessageIter *iter = malloc( sizeof(DBusMessageIter) ); + void *p =cs; + p++; + if( iter != 0L ) + { + if( !dbus_message_iter_init( msg, iter )) + { + free( iter ) ; + iter = 0L; + } + } + return iter; +} + +uint32_t +dbus_svc_message_next_arg_type( DBusConnectionState *cs, dbus_svc_MessageIterator iter ) +{ + void *p =cs; + p++; + return dbus_message_iter_get_arg_type( iter ); +} + +void +dbus_svc_message_next_arg( DBusConnectionState *cs, dbus_svc_MessageIterator iter, void *value ) +{ + void *p =cs; + p++; + dbus_message_iter_get_basic( iter, value ); + dbus_message_iter_next( iter ); +} + +uint32_t +dbus_svc_message_element_type(DBusConnectionState *cs , dbus_svc_MessageIterator iter) +{ + void *p =cs; + p++; + return dbus_message_iter_get_element_type(iter); +} + +void +dbus_svc_message_get_elements( DBusConnectionState *cs , dbus_svc_MessageIterator iter, uint32_t *n, void *array ) +{ + void *p =cs; + p++; + dbus_message_iter_get_fixed_array( iter, n, array); +} + +void dbus_svc_message_iterator_free( DBusConnectionState *cs, dbus_svc_MessageIterator iter ) +{ + void *p =cs; + p++; + free( iter ); +} + +uint8_t dbus_svc_message_type( DBusMessage *msg ) +{ + return dbus_message_get_type( msg ); +} + +static DBusConnectionState * +dbcs_new( DBusConnection *connection ) +{ + DBusConnectionState *dbcs = (DBusConnectionState *) malloc( sizeof(DBusConnectionState) ); + if ( dbcs ) + { + memset( dbcs, '\0', sizeof( DBusConnectionState )); + dbcs->connection = connection; + } + return(dbcs); +} + +static DBusConnectionTimeout * +timeout_new( DBusTimeout *timeout ) +{ + DBusConnectionTimeout *to = (DBusConnectionTimeout *) malloc ( sizeof(DBusConnectionTimeout) ); + if( to != 0L ) + { + to->to = timeout; + dbus_timeout_set_data(timeout, to, 0L); + if( dbus_timeout_get_enabled(timeout) ) + gettimeofday(&(to->tv),0L); + else + { + to->tv.tv_sec = 0 ; + to->tv.tv_usec = 0 ; + } + } + return( to ); +} + +static dbus_bool_t +add_timeout( DBusTimeout *timeout, void *csp ) +{ + DBusConnectionState *cs = csp; + DBusConnectionTimeout *to = timeout_new(timeout); + if( cs->dh != 0L ) (*(cs->dh))("add_timeout: %d", dbus_timeout_get_interval(timeout)); + to->cs = cs; + if ( to ) + { + if( tsearch((void*)to, &(cs->timeouts), ptr_key_comparator) != 0L ) + return TRUE; + } + if( cs->eh != 0L ) (*(cs->eh))("add_timeout: out of memory"); + return FALSE; +} + +static void +remove_timeout( DBusTimeout *timeout, void *csp ) +{ + DBusConnectionState *cs = csp; + DBusConnectionTimeout *to = dbus_timeout_get_data(timeout); + if( (to != 0L) && (to->to == timeout) ) + { + if( cs->dh != 0L ) (*(cs->dh))("remove_timeout: %d", dbus_timeout_get_interval(to->to)); + if( tdelete((const void*)to, &(cs->timeouts), ptr_key_comparator) != 0L ) + { + free(to); + }else + if( cs->eh != 0L ) (*(cs->eh))("remove_timeout: can't happen?!?: timeout data %p not found", to); + }else + if( cs->eh != 0L ) (*(cs->eh))("remove_timeout: can't happen?!?: timeout %p did not record data %p %p", + timeout, to, ((to != 0L) ? to->to : 0L) + ); +} + +static void +toggle_timeout( DBusTimeout *timeout, void *csp ) +{ + DBusConnectionState *cs = csp; + DBusConnectionTimeout **top = tfind( (const void*) dbus_timeout_get_data(timeout), + &(cs->timeouts), + ptr_key_comparator + ), + *to=0L; + if( (top != 0L) && ((to=*top) != 0L) && (to->to == timeout) ) + { + if( cs->dh != 0L ) (*(cs->dh))("toggle_timeout: %d", dbus_timeout_get_interval(to->to)); + if( dbus_timeout_get_enabled(timeout) ) + gettimeofday(&(to->tv),0L); + else + { + to->tv.tv_sec = 0 ; + to->tv.tv_usec = 0 ; + } + }else + if( cs->eh != 0L ) (*(cs->eh))("toggle_timeout: can't happen?!?: timeout %p %s %p %p", timeout, + ((to==0L) ? "did not record data" : "not found"), + to, ((to != 0L) ? to->to : 0L) + ); +} + +static void +process_timeout( const void *p, const VISIT which, const int level) +{ + DBusConnectionState *cs; + void * const *tpp = p; + DBusConnectionTimeout *to; + struct timeval tv; + float now, then, interval; + int l = level ? 1 : 0; + l=l; + + gettimeofday(&tv,0L); + + if( (tpp != 0L) && (*tpp != 0L) && ((which == postorder) || (which == leaf)) ) + { + to = (DBusConnectionTimeout*)*tpp; + cs = to->cs; + if ( !dbus_timeout_get_enabled(to->to) ) + return; + cs = dbus_timeout_get_data(to->to); + then = ((float)to->tv.tv_sec) + (((float)to->tv.tv_usec) / 1000000.0); + if( then != 0.0 ) + { + interval = ((float)dbus_timeout_get_interval(to->to)) / 1000.0; + now = ((float)tv.tv_sec) + (( (float)tv.tv_usec) / 1000000.0); + if( (now - then) >= interval ) + { + if( cs->dh != 0L ) (*(cs->dh))("handle_timeout: %d - %f %f %f", dbus_timeout_get_interval(to->to), then, now, interval); + dbus_timeout_handle( to->to ); + to->tv=tv; + } + }else + { + to->tv = tv; + } + } +} + +static void +process_timeouts ( DBusConnectionState *cs ) +{ + twalk( cs->timeouts, process_timeout ); +} + +static void +set_watch_fds( DBusWatch *watch, DBusConnectionState *cs ) +{ + uint8_t flags = dbus_watch_get_flags(watch); + int fd = dbus_watch_get_fd(watch); + + if ( cs->n <= fd ) + cs->n = fd + 1; + + if ( dbus_watch_get_enabled(watch) ) + { + if ( flags & DBUS_WATCH_READABLE ) + { + FD_SET(fd , &(cs->r_fds)); + if( cs->wh != 0L ) + (*(cs->wh))( fd, WATCH_ENABLE | WATCH_READ, cs->wh_arg ); + }else + { + FD_CLR(fd , &(cs->r_fds)); + if( cs->wh != 0L ) + (*(cs->wh))( fd, WATCH_READ, cs->wh_arg ); + } + + if ( flags & DBUS_WATCH_WRITABLE ) + { + FD_SET(fd , &(cs->w_fds)); + if( cs->wh != 0L ) + (*(cs->wh))( fd, WATCH_ENABLE | WATCH_WRITE, cs->wh_arg ); + }else + { + FD_CLR(fd , &(cs->w_fds)); + if( cs->wh != 0L ) + (*(cs->wh))( fd, WATCH_WRITE, cs->wh_arg ); + } + if ( flags & DBUS_WATCH_ERROR ) + { + FD_SET(fd , &(cs->e_fds)); + if( cs->wh != 0L ) + (*(cs->wh))( fd, WATCH_ENABLE | WATCH_ERROR, cs->wh_arg ); + }else + { + FD_CLR(fd , &(cs->e_fds)); + if( cs->wh != 0L ) + (*(cs->wh))( fd, WATCH_ERROR, cs->wh_arg ); + } + }else + { + if( FD_ISSET( fd, &(cs->r_fds)) ) + if( cs->wh != 0L ) + (*(cs->wh))( fd, WATCH_READ, cs->wh_arg ); + FD_CLR(fd , &(cs->r_fds)); + + if( FD_ISSET( fd, &(cs->w_fds)) ) + if( cs->wh != 0L ) + (*(cs->wh))( fd, WATCH_WRITE, cs->wh_arg ); + FD_CLR(fd , &(cs->w_fds)); + + if( FD_ISSET( fd, &(cs->e_fds)) ) + if( cs->wh != 0L ) + (*(cs->wh))( fd, WATCH_ERROR, cs->wh_arg ); + FD_CLR(fd , &(cs->e_fds)); + } +} + +static dbus_bool_t +add_watch ( DBusWatch *watch, void *csp ) +{ + DBusConnectionState *cs = csp; + + dbus_watch_set_data(watch, cs, no_free ); + if( cs->dh != 0L ) (*(cs->dh))("add_watch: %d", dbus_watch_get_fd(watch)); + if( tsearch((const void*)watch,&(cs->watches),ptr_key_comparator) == 0L ) + { + if( cs->eh != 0L ) (*(cs->eh))("add_watch: out of memory"); + return FALSE; + } + set_watch_fds(watch,cs); + return TRUE; +} + +static void +remove_watch ( DBusWatch *watch, void *csp ) +{ + DBusConnectionState *cs = csp; + int fd = dbus_watch_get_fd(watch); + if( tdelete((const void*)watch, &(cs->watches), ptr_key_comparator) == 0L ) + if( cs->eh != 0L ) (*(cs->eh))("remove_watch: can't happen?!?: watch not found"); + if( cs->dh != 0L ) (*(cs->dh))("remove_watch: %d", dbus_watch_get_fd(watch)); + FD_CLR(fd , &(cs->r_fds)); + FD_CLR(fd , &(cs->w_fds)); + FD_CLR(fd , &(cs->e_fds)); + if( cs->wh != 0L ) + (*(cs->wh))(dbus_watch_get_fd(watch), WATCH_READ | WATCH_WRITE | WATCH_ERROR, cs->wh_arg ); +} + +static void +toggle_watch ( DBusWatch *watch, void *csp ) +{ + DBusConnectionState *cs = csp; + if( cs->dh != 0L ) (*(cs->dh))("toggle_watch: %d", dbus_watch_get_fd(watch)); + set_watch_fds(watch,cs); +} + +static void +process_watch( const void *p, const VISIT which, const int level) +{ + void * const *wpp=p; + DBusWatch *w; + int fd; + uint8_t flags; + DBusConnectionState *cs; + int l = level ? 1 : 0; + l=l; + + if((wpp != 0L) && (*wpp != 0L) && ( (which == postorder) || (which == leaf) ) ) + { + w = (DBusWatch*)*wpp; + cs = dbus_watch_get_data( w ); + if( cs == 0 ) + return; + if( ! dbus_watch_get_enabled(w) ) + return; + fd = dbus_watch_get_fd( w ); + flags = dbus_watch_get_flags( w ); + if( cs->dh != 0L ) (*(cs->dh))("handle_watch: %d", dbus_watch_get_fd( w )); + if ( (flags & DBUS_WATCH_READABLE) && (FD_ISSET(fd, &(cs->s_r_fds))) ) + dbus_watch_handle(w, DBUS_WATCH_READABLE); + if ( (flags & DBUS_WATCH_WRITABLE) && (FD_ISSET(fd, &(cs->s_w_fds))) ) + dbus_watch_handle(w, DBUS_WATCH_READABLE); + if ( (flags & DBUS_WATCH_ERROR) && (FD_ISSET(fd, &(cs->s_e_fds))) ) + dbus_watch_handle(w, DBUS_WATCH_ERROR); + } +} + +static void +process_watches ( DBusConnectionState *cs ) +{ + twalk( cs->watches, process_watch ); +} + +void dbus_svc_handle_watch( DBusConnectionState *cs, int fd, dbus_svc_WatchFlags action ) +{ + switch( action & 7 ) + { + case WATCH_READ: + FD_SET(fd, &(cs->s_r_fds)); + break; + + case WATCH_WRITE: + FD_SET(fd, &(cs->s_w_fds)); + break; + + case WATCH_ERROR: + FD_SET(fd, &(cs->s_e_fds)); + break; + } +} + +static void +dispatch_status +( DBusConnection *connection, + DBusDispatchStatus new_status, + void *csp +) +{ + connection=connection; + DBusConnectionState *cs = csp; + cs->dispatchStatus = new_status; +} + +void +dbus_svc_main_loop( DBusConnectionState *cs, void (*idle_handler)(DBusConnectionState *) ) +{ + struct timeval timeout={0,200000}; + int n_fds; + + while( cs->status != SHUTDOWN ) + { + cs->s_r_fds = cs->r_fds; + cs->s_w_fds = cs->w_fds; + cs->s_e_fds = cs->e_fds; + + timeout.tv_sec = 0; + timeout.tv_usec= 200000; + + if ( (n_fds = select(cs->n, &(cs->s_r_fds), &(cs->s_w_fds), &(cs->s_e_fds), &timeout)) < 0 ) + { + if (errno != EINTR) + { + if( cs->eh != 0L ) (*(cs->eh))( "select failed: %d : %s", errno, strerror(errno)); + return; + } + } + + if( n_fds > 0 ) + process_watches(cs); + + process_timeouts(cs); + + if ( cs->dispatchStatus != DBUS_DISPATCH_COMPLETE ) + dbus_connection_dispatch( cs->connection ); + + if( idle_handler != 0L ) + (*idle_handler)(cs); + } +} + +void dbus_svc_dispatch(DBusConnectionState *cs) +{ + process_watches(cs); + + FD_ZERO(&(cs->s_r_fds)); + FD_ZERO(&(cs->s_w_fds)); + FD_ZERO(&(cs->s_e_fds)); + + process_timeouts(cs); + + while ( cs->dispatchStatus != DBUS_DISPATCH_COMPLETE ) + dbus_connection_dispatch( cs->connection ); +} + +void +dbus_svc_quit( DBusConnectionState *cs ) +{ + cs->status = SHUTDOWN; +} + +static isc_result_t +connection_setup +( DBusConnection *connection, + DBUS_SVC *dbus, + dbus_svc_WatchHandler wh, + dbus_svc_ErrorHandler eh, + dbus_svc_ErrorHandler dh, + void *wh_arg +) +{ + *dbus = dbcs_new( connection ); + + if ( *dbus == 0L ) + { + if(eh)(*(eh))("connection_setup: out of memory"); + goto fail; + } + (*dbus)->wh = wh; + (*dbus)->wh_arg = wh_arg; + (*dbus)->eh = eh; + (*dbus)->dh = dh; + + if (!dbus_connection_set_watch_functions + ( (*dbus)->connection, + add_watch, + remove_watch, + toggle_watch, + *dbus, + no_free + ) + ) + { + if( (*dbus)->eh != 0L ) (*((*dbus)->eh))("connection_setup: dbus_connection_set_watch_functions failed"); + goto fail; + } + + if (!dbus_connection_set_timeout_functions + ( connection, + add_timeout, + remove_timeout, + toggle_timeout, + *dbus, + no_free + ) + ) + { + if( (*dbus)->eh != 0L ) (*((*dbus)->eh))("connection_setup: dbus_connection_set_timeout_functions failed"); + goto fail; + } + + dbus_connection_set_dispatch_status_function + ( connection, + dispatch_status, + *dbus, + no_free + ); + + if (dbus_connection_get_dispatch_status (connection) != DBUS_DISPATCH_COMPLETE) + dbus_connection_ref(connection); + + return ISC_R_SUCCESS; + + fail: + if( *dbus != 0L ) + free(*dbus); + + dbus_connection_set_dispatch_status_function (connection, NULL, NULL, NULL); + dbus_connection_set_watch_functions (connection, NULL, NULL, NULL, NULL, NULL); + dbus_connection_set_timeout_functions (connection, NULL, NULL, NULL, NULL, NULL); + + return ISC_R_FAILURE; +} + +isc_result_t +dbus_svc_init +( + dbus_svc_DBUS_TYPE bus, + char *name, + DBUS_SVC *dbus, + dbus_svc_WatchHandler wh , + dbus_svc_ErrorHandler eh , + dbus_svc_ErrorHandler dh , + void *wh_arg +) +{ + DBusConnection *connection; + DBusError error; + char *session_bus_address=0L; + + memset(&error,'\0',sizeof(DBusError)); + + dbus_error_init(&error); + + switch( bus ) + { + /* DBUS_PRIVATE_* bus types are the only type which allow reconnection if the dbus-daemon is restarted + */ + case DBUS_PRIVATE_SYSTEM: + + if ( (connection = dbus_connection_open_private("unix:path=/var/run/dbus/system_bus_socket", &error)) == 0L ) + { + if(eh)(*eh)("dbus_svc_init failed: %s %s",error.name, error.message); + return ISC_R_FAILURE; + } + + if ( ! dbus_bus_register(connection,&error) ) + { + if(eh)(*eh)("dbus_bus_register failed: %s %s", error.name, error.message); + dbus_connection_close(connection); + free(connection); + return ISC_R_FAILURE; + } + break; + + case DBUS_PRIVATE_SESSION: + + session_bus_address = getenv("DBUS_SESSION_BUS_ADDRESS"); + if ( session_bus_address == 0L ) + { + if(eh)(*eh)("dbus_svc_init failed: DBUS_SESSION_BUS_ADDRESS environment variable not set"); + return ISC_R_FAILURE; + } + + if ( (connection = dbus_connection_open_private(session_bus_address, &error)) == 0L ) + { + if(eh)(*eh)("dbus_svc_init failed: %s %s",error.name, error.message); + return ISC_R_FAILURE; + } + + if ( ! dbus_bus_register(connection,&error) ) + { + if(eh)(*eh)("dbus_bus_register failed: %s %s", error.name, error.message); + dbus_connection_close(connection); + free(connection); + return ISC_R_FAILURE; + } + break; + + case DBUS_SYSTEM: + case DBUS_SESSION: + + if ( (connection = dbus_bus_get (bus, &error)) == 0L ) + { + if(eh)(*eh)("dbus_svc_init failed: %s %s",error.name, error.message); + return ISC_R_FAILURE; + } + break; + + default: + if(eh)(*eh)("dbus_svc_init failed: unknown bus type %d", bus); + return ISC_R_FAILURE; + } + + dbus_connection_set_exit_on_disconnect(connection, FALSE); + + if ( (connection_setup(connection, dbus, wh, eh, dh, wh_arg)) != ISC_R_SUCCESS) + { + if(eh)(*eh)("dbus_svc_init failed: connection_setup failed"); + return ISC_R_FAILURE; + } + + if( name == 0L ) + return ISC_R_SUCCESS; + + (*dbus)->unique_name = dbus_bus_get_unique_name(connection); + + switch + ( dbus_bus_request_name + ( connection, name, +#ifdef DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT + DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT , +#else + 0 , +#endif + &error + ) + ) + { + case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER: + break; + case DBUS_REQUEST_NAME_REPLY_EXISTS: + case DBUS_REQUEST_NAME_REPLY_IN_QUEUE: + case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER: + if(eh)(*eh)("dbus_svc_init: dbus_bus_request_name failed: Name already registered"); + goto give_up; + default: + if(eh)(*eh)("dbus_svc_init: dbus_bus_request_name failed: %s %s", error.name, error.message); + goto give_up; + } + return ISC_R_SUCCESS; + + give_up: + dbus_connection_close( connection ); + dbus_connection_unref( connection ); + if( *dbus ) + { + dbus_connection_set_dispatch_status_function (connection, NULL, NULL, NULL); + dbus_connection_set_watch_functions (connection, NULL, NULL, NULL, NULL, NULL); + dbus_connection_set_timeout_functions (connection, NULL, NULL, NULL, NULL, NULL); + free(*dbus); + } + return ISC_R_FAILURE; +} + +const char *dbus_svc_unique_name(DBusConnectionState *cs) +{ + return cs->unique_name; +} + +void +dbus_svc_shutdown ( DBusConnectionState *cs ) +{ + if (!dbus_connection_set_watch_functions + ( cs->connection, + NULL, NULL, NULL, NULL, NULL + ) + ) if( cs->eh != 0L ) (*(cs->eh))("connection_shutdown: dbus_connection_set_watch_functions: No Memory." + "Setting watch functions to NULL failed." + ); + + if (!dbus_connection_set_timeout_functions + ( cs->connection, + NULL, NULL, NULL, NULL, NULL + ) + ) if( cs->eh != 0L ) (*(cs->eh))("connection_shutdown: dbus_connection_set_timeout_functions: No Memory." + "Setting timeout functions to NULL failed." + ); + + dbus_connection_set_dispatch_status_function (cs->connection, NULL, NULL, NULL); + + tdestroy( cs->timeouts, free); + cs->timeouts=0L; + tdestroy( cs->watches, no_free); + cs->watches=0L; + + dbus_connection_close( cs->connection ); + dbus_connection_unref( cs->connection ); + + free( cs ); +} diff --git a/contrib/dbus/dbus_service.h b/contrib/dbus/dbus_service.h new file mode 100644 index 0000000..d8a21f1 --- /dev/null +++ b/contrib/dbus/dbus_service.h @@ -0,0 +1,287 @@ +/* D-BUS Service Utilities + * + * Provides utilities for construction of D-BUS "Services" + * + * Copyright(C) Jason Vas Dias, Red Hat Inc., 2005 + * Modified by Adam Tkac, Red Hat Inc., 2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation at + * http://www.fsf.org/licensing/licenses/gpl.txt + * and included in this software distribution as the "LICENSE" file. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef D_BUS_SERVER_UTILITIES_H +#define D_BUS_SERVER_UTILITIES_H + +#include <stdint.h> +#include <stdarg.h> +#include <isc/types.h> + +typedef struct dbcs_s* DBUS_SVC; + +typedef enum +{ HANDLED, NOT_HANDLED, HANDLED_NOW +} dbus_svc_HandlerResult; + +typedef enum +{ INVALID, CALL, RETURN, ERROR, SIGNAL +} dbus_svc_MessageType; + +typedef enum +{ + DBUS_SESSION, + DBUS_SYSTEM, + DBUS_STARTER, + DBUS_PRIVATE_SYSTEM, + DBUS_PRIVATE_SESSION +} dbus_svc_DBUS_TYPE; + +typedef enum /* D-BUS Protocol Type Codes / Signature Chars */ +{ + TYPE_INVALID = (int)'\0', + TYPE_BYTE = (int)'y', + TYPE_BOOLEAN = (int)'b', + TYPE_INT16 = (int)'n', + TYPE_UINT16 = (int)'q', + TYPE_INT32 = (int)'i', + TYPE_UINT32 = (int)'u', + TYPE_INT64 = (int)'x', + TYPE_UINT64 = (int)'t', + TYPE_DOUBLE = (int)'d', + TYPE_STRING = (int)'s', + TYPE_OBJECT_PATH =(int)'o', + TYPE_SIGNATURE= (int)'g', + TYPE_ARRAY = (int)'a', + TYPE_VARIANT = (int)'v', + TYPE_STRUCT = (int)'r', + TYPE_DICT_ENTRY = (int)'e', + STRUCT_BEGIN = (int)'(', + STRUCT_END = (int)')', + DICT_ENTRY_BEGIN =(int)'{', + DICT_ENTRY_END =(int)'}' +} dbus_svc_DataType; + +typedef struct DBusMessage* dbus_svc_MessageHandle; + +typedef int +(*dbus_svc_ErrorHandler) +( const char *errorFmt, ... +); /* Error Handler function prototype - handle FATAL errors from D-BUS calls */ + +typedef enum +{ + WATCH_ENABLE = 8, + WATCH_ERROR = 4, + WATCH_WRITE = 2, + WATCH_READ = 1 +} dbus_svc_WatchFlags; + +typedef void (*dbus_svc_WatchHandler)( int, dbus_svc_WatchFlags, void *arg ); + +typedef dbus_svc_HandlerResult +(*dbus_svc_MessageHandler) +( DBUS_SVC dbus, + dbus_svc_MessageType type, + uint8_t reply_expected, /* 1 / 0 */ + uint32_t serial, /* serial number of message; needed to reply */ + const char *destination, /* D-BUS connection name / destination */ + const char *path, /* D-BUS Object Path */ + const char *member, /* D-BUS Object Member */ + const char *interface, /* D-BUS Object interface */ + const char *if_suffix, /* remainder of interface prefixed by ifPrefix */ + const char *sender, /* Senders' connection destination */ + const char *signature, /* Signature String composed of Type Codes */ + dbus_svc_MessageHandle msg,/* Message pointer: call dbus_svc_get_args(msg,...) to get data */ + const char *prefix, /* If non-null, this is the root prefix for this sub-path message */ + const char *suffix, /* If non-null, this is the suffix of this sub-path message */ + void *prefixObject, /* If non-null, this is the object that was registered for the prefix */ + void *object /* If non-null, this is the object that was registered for the complete path */ +); /* Message Handler function prototype */ + +#define DBusMsgHandlerArgs \ + DBUS_SVC dbus, \ + dbus_svc_MessageType type, \ + uint8_t reply_expected, \ + uint32_t serial, \ + const char *destination, \ + const char *path, \ + const char *member, \ + const char *interface, \ + const char *if_suffix, \ + const char *sender, \ + const char *signature, \ + dbus_svc_MessageHandle msg, \ + const char *prefix, \ + const char *suffix, \ + void *prefixObject, \ + void *object + +#define SHUTDOWN 255 + +extern isc_result_t dbus_svc_init +( dbus_svc_DBUS_TYPE bus, + char *name, /* name to register with D-BUS */ + DBUS_SVC *dbus, /* dbus handle */ + dbus_svc_WatchHandler wh, /* optional handler for watch events */ + dbus_svc_ErrorHandler eh, /* optional error log message handler */ + dbus_svc_ErrorHandler dh, /* optional debug / info log message handler */ + void *wh_arg /* optional watch handler arg */ +); +/* + * Obtains connection to DBUS_BUS_STARTER and registers "name". + * "eh" will be called for all errors from this server session. + */ + +/* EITHER : + * pass a NULL WatchHandler to dbus_svc_init and use dbus_svc_main_loop + * OR: + * supply a valid WatchHandler, and call dbus_svc_handle_watch when + * select() returns the watch fd as ready for the watch action, and + * call dbus_svc_dispatch when all watches have been handled. + */ + + +uint8_t +dbus_svc_add_filter +( DBUS_SVC, dbus_svc_MessageHandler mh, void *obj, int n_matches, ... ); +/* + * Registers SINGLE message handler to handle ALL messages, adding match rules + */ + +void dbus_svc_main_loop( DBUS_SVC, void (*idle_handler)(DBUS_SVC) ); + +void dbus_svc_handle_watch( DBUS_SVC, int watch_fd, dbus_svc_WatchFlags action); + +void dbus_svc_dispatch( DBUS_SVC ); + +/* + * Enter message processing loop. + * If "idle_handler" is non-null, it will be called once per iteration of loop. + */ + +const char *dbus_svc_unique_name( DBUS_SVC ); +/* + * Returns connection "unique" (socket) name + */ + +void dbus_svc_quit( DBUS_SVC ); +/* + * Exit message processing loop + */ + +void dbus_svc_shutdown( DBUS_SVC ); +/* + * Close connections and clean up. + * DBUS_SVC pointer is invalid after this. + */ + +uint8_t +dbus_svc_get_args( DBUS_SVC, dbus_svc_MessageHandle, dbus_svc_DataType, ... ); +/* get arguments from message */ + +uint8_t +dbus_svc_get_args_va( DBUS_SVC, dbus_svc_MessageHandle, dbus_svc_DataType, va_list ); +/* get arguments from message */ + + +typedef void (*dbus_svc_ShutdownHandler) ( DBUS_SVC, void * ); +uint8_t +dbus_svc_add_shutdown_filter +( + DBUS_SVC, dbus_svc_ShutdownHandler sh, void *obj +); +/* Registers a filter for D-BUS shutdown event. + * Cannot be used in conjunction with dbus_svc_add_message_filter. + */ + +uint8_t +dbus_svc_remove_message_filter +( DBUS_SVC, dbus_svc_MessageHandler mh); +/* Unregisters the message filter */ + +uint8_t +dbus_svc_send +( DBUS_SVC, + dbus_svc_MessageType type, + int32_t reply_serial, + uint32_t *new_serial, + const char *destination, + const char *path, + const char *member, + const char *interface, + dbus_svc_DataType firstType, + ... /* pointer, { (dbus_svc_DataType, pointer )...} */ +); /* sends messages / replies to "destination" */ + +uint8_t +dbus_svc_send_va +( DBUS_SVC cs, + dbus_svc_MessageType type, + int32_t reply_serial, + uint32_t *new_serial, + const char *destination, + const char *path, + const char *member, + const char *interface, + dbus_svc_DataType firstType, + va_list va +); /* sends messages / replies to "destination" */ + +dbus_svc_MessageHandle +dbus_svc_call +( DBUS_SVC cs, + const char *destination, + const char *path, + const char *member, + const char *interface, + dbus_svc_DataType firstType, + ... +); /* constructs message, sends it, returns reply */ + +dbus_svc_MessageHandle +dbus_svc_new_message +( DBUS_SVC cs, + dbus_svc_MessageType type, + int32_t reply_serial, + const char *destination, + const char *path, + const char *interface, + const char *member +); + +uint8_t +dbus_svc_send_message(DBUS_SVC , dbus_svc_MessageHandle , uint32_t * ); + +uint8_t +dbus_svc_message_append_args( DBUS_SVC , dbus_svc_MessageHandle, dbus_svc_DataType, ...); + +typedef struct DBusMessageIter *dbus_svc_MessageIterator; + +dbus_svc_MessageIterator +dbus_svc_message_iterator_new( DBUS_SVC, dbus_svc_MessageHandle ); + +uint32_t +dbus_svc_message_next_arg_type( DBUS_SVC, dbus_svc_MessageIterator ); + +void +dbus_svc_message_next_arg( DBUS_SVC, dbus_svc_MessageIterator, void * ); + +uint32_t +dbus_svc_message_element_type( DBUS_SVC, dbus_svc_MessageIterator ); + +void +dbus_svc_message_get_elements( DBUS_SVC, dbus_svc_MessageIterator, uint32_t *n, void *array ); + +uint8_t dbus_svc_message_type( dbus_svc_MessageHandle ); + +void dbus_svc_message_iterator_free( DBUS_SVC, dbus_svc_MessageIterator ); + +#endif diff --git a/contrib/dbus/named-dbus-system.conf b/contrib/dbus/named-dbus-system.conf new file mode 100644 index 0000000..2cb99bd --- /dev/null +++ b/contrib/dbus/named-dbus-system.conf @@ -0,0 +1,20 @@ +<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> +<busconfig> + <servicedir>/usr/share/dbus-1/services</servicedir> + <policy user="named"> + <allow own="com.redhat.named"/> + <allow send_interface="com.redhat.named"/> + <allow send_destination="com.redhat.named"/> + </policy> + <policy user="root"> + <allow send_interface="com.redhat.named"/> + <allow send_destination="com.redhat.named"/> + </policy> + <policy context="default"> + <deny own="com.redhat.named"/> + <deny send_destination="com.redhat.named"/> + <deny send_interface="com.redhat.named"/> + </policy> +</busconfig> + diff --git a/contrib/dbus/named-dbus.service b/contrib/dbus/named-dbus.service new file mode 100644 index 0000000..ddf40e7 --- /dev/null +++ b/contrib/dbus/named-dbus.service @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=com.redhat.named +Exec=/usr/sbin/named |