]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
1972. [contrib] DBUS dynamic forwarders integation from
authorMark Andrews <marka@isc.org>
Mon, 23 Jan 2006 04:53:34 +0000 (04:53 +0000)
committerMark Andrews <marka@isc.org>
Mon, 23 Jan 2006 04:53:34 +0000 (04:53 +0000)
                        Jason Vas Dias <jvdias@redhat.com>.

13 files changed:
CHANGES
contrib/dbus/GetForwarders [new file with mode: 0755]
contrib/dbus/INSTALL [new file with mode: 0644]
contrib/dbus/Makefile [new file with mode: 0644]
contrib/dbus/README.DBUS [new file with mode: 0644]
contrib/dbus/SetForwarders [new file with mode: 0755]
contrib/dbus/bind-9.3.2b1-dbus.patch [new file with mode: 0644]
contrib/dbus/dbus_mgr.c [new file with mode: 0644]
contrib/dbus/dbus_mgr.h [new file with mode: 0644]
contrib/dbus/dbus_service.c [new file with mode: 0644]
contrib/dbus/dbus_service.h [new file with mode: 0644]
contrib/dbus/named-dbus-system.conf [new file with mode: 0644]
contrib/dbus/named-dbus.service [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
index 8306502fd40eb8f30ee5e4ca5005d429dd313d19..919c00091b83c589184a9225e61bcaa835929b4f 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+1972.  [contrib]       DBUS dynamic forwarders integation from
+                       Jason Vas Dias <jvdias@redhat.com>.
+
 1971.  [port]          linux: make detection of missing IF_NAMESIZE more
                         robust. [RT #15443]
 
diff --git a/contrib/dbus/GetForwarders b/contrib/dbus/GetForwarders
new file mode 100755 (executable)
index 0000000..838706d
--- /dev/null
@@ -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 (file)
index 0000000..2ad526e
--- /dev/null
@@ -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 b/contrib/dbus/Makefile
new file mode 100644 (file)
index 0000000..6285034
--- /dev/null
@@ -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/README.DBUS b/contrib/dbus/README.DBUS
new file mode 100644 (file)
index 0000000..8c5c73f
--- /dev/null
@@ -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 (executable)
index 0000000..8ee4ce1
--- /dev/null
@@ -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 (file)
index 0000000..cdf50d6
--- /dev/null
@@ -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/dbus_mgr.c b/contrib/dbus/dbus_mgr.c
new file mode 100644 (file)
index 0000000..832c0ca
--- /dev/null
@@ -0,0 +1,2441 @@
+/* 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
+ *
+ *  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 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( 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;
+
+    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;
+    }
+
+    mgr->dbus = 
+       dbus_svc_init
+       (   DBUS_PRIVATE_SYSTEM,
+           destination,
+           dbus_mgr_watch_handler,
+           0L, 0L,
+           mgr
+       );
+
+    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 )
+       return;
+
+    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 ) 
+           return;
+       *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);
+} 
+
+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 (file)
index 0000000..78be0d0
--- /dev/null
@@ -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 (file)
index 0000000..85965d8
--- /dev/null
@@ -0,0 +1,1149 @@
+/*  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
+ *
+ *  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>
+
+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);
+           }
+       }
+    }
+    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");
+       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);
+    }
+    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 DBusConnectionState *
+connection_setup 
+(   DBusConnection *connection,  
+    dbus_svc_WatchHandler wh, 
+    dbus_svc_ErrorHandler eh, 
+    dbus_svc_ErrorHandler dh,
+    void *wh_arg
+)
+{
+    DBusConnectionState *cs = dbcs_new( connection );
+    
+    if ( cs == 0L )
+    {
+       if(eh)(*(eh))("connection_setup: out of memory");
+       goto fail;
+    }
+    cs->wh = wh;
+    cs->wh_arg = wh_arg;
+    cs->eh = eh;
+    cs->dh = dh;
+
+    if (!dbus_connection_set_watch_functions 
+        (    cs->connection,
+             add_watch,
+             remove_watch,
+             toggle_watch,
+             cs,
+             no_free
+         )
+       )
+    {
+       if( cs->eh != 0L ) (*(cs->eh))("connection_setup: dbus_connection_set_watch_functions failed");
+       goto fail; 
+    }
+      
+    if (!dbus_connection_set_timeout_functions 
+        (    connection,
+             add_timeout,
+             remove_timeout,
+             toggle_timeout,
+             cs, 
+             no_free
+        )
+       )
+    {
+       if( cs->eh != 0L ) (*(cs->eh))("connection_setup: dbus_connection_set_timeout_functions failed");
+       goto fail;
+    }
+
+    dbus_connection_set_dispatch_status_function 
+    (   connection, 
+       dispatch_status, 
+       cs, 
+       no_free
+    ); 
+
+    if (dbus_connection_get_dispatch_status (connection) != DBUS_DISPATCH_COMPLETE)
+       dbus_connection_ref(connection);    
+    
+    return cs;
+  
+ fail:
+    if( cs != 0L )
+       free(cs);
+  
+    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 0L;
+}
+
+DBusConnectionState *
+dbus_svc_init
+(
+    dbus_svc_DBUS_TYPE    bus,
+    char                  *name, 
+    dbus_svc_WatchHandler wh ,
+    dbus_svc_ErrorHandler eh ,
+    dbus_svc_ErrorHandler dh ,
+    void *wh_arg
+)
+{
+    DBusConnection       *connection;
+    DBusError            error;
+    DBusConnectionState  *cs;
+    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 ( 0L );
+       }
+
+       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 ( 0L );
+       }
+       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 ( 0L );
+       }
+
+       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 ( 0L );
+       }
+
+       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 ( 0L );
+       }
+       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 ( 0L );
+       }
+       break;
+
+    default:
+       if(eh)(*eh)("dbus_svc_init failed: unknown bus type %d", bus);
+       return ( 0L );
+    }
+    
+    dbus_connection_set_exit_on_disconnect(connection, FALSE);
+
+    if ( (cs = connection_setup(connection, wh, eh, dh, wh_arg)) == 0L )
+    {
+       if(eh)(*eh)("dbus_svc_init failed: connection_setup failed");
+       return( 0L );
+    }
+
+    if( name == 0L )
+       return( cs );
+    
+    cs->unique_name = dbus_bus_get_unique_name(connection);
+
+    switch
+       (   dbus_bus_request_name 
+           (   connection, name, DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT , &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 ( cs );
+
+ give_up:
+    dbus_connection_close( connection );
+    dbus_connection_unref( connection );
+    if( cs )
+    {
+       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(cs);    
+    }
+    return ( 0L );
+}
+
+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 (file)
index 0000000..69e7fac
--- /dev/null
@@ -0,0 +1,284 @@
+/*  D-BUS Service Utilities
+ *  
+ *  Provides utilities for construction of D-BUS "Services"  
+ *
+ *  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.
+ * 
+ */
+
+#ifndef D_BUS_SERVER_UTILITIES_H
+#define D_BUS_SERVER_UTILITIES_H
+
+#include <stdint.h>
+#include <stdarg.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  DBUS_SVC dbus_svc_init
+( dbus_svc_DBUS_TYPE bus, 
+  char *name,                         /* name to register with D-BUS */
+  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 (file)
index 0000000..2cb99bd
--- /dev/null
@@ -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 (file)
index 0000000..ddf40e7
--- /dev/null
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=com.redhat.named
+Exec=/usr/sbin/named