summaryrefslogtreecommitdiffstats
path: root/contrib/dbus
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/dbus')
-rwxr-xr-xcontrib/dbus/GetForwarders31
-rw-r--r--contrib/dbus/INSTALL9
-rw-r--r--contrib/dbus/Makefile.9.3.2b120
-rw-r--r--contrib/dbus/Makefile.9.3.3rc220
-rw-r--r--contrib/dbus/README.DBUS259
-rwxr-xr-xcontrib/dbus/SetForwarders52
-rw-r--r--contrib/dbus/bind-9.3.2b1-dbus.patch713
-rw-r--r--contrib/dbus/bind-9.3.3rc2-dbus.patch778
-rw-r--r--contrib/dbus/dbus_mgr.c2458
-rw-r--r--contrib/dbus/dbus_mgr.h37
-rw-r--r--contrib/dbus/dbus_service.c1161
-rw-r--r--contrib/dbus/dbus_service.h287
-rw-r--r--contrib/dbus/named-dbus-system.conf20
-rw-r--r--contrib/dbus/named-dbus.service3
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