summaryrefslogtreecommitdiffstats
path: root/contrib/dbus/dbus_mgr.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/dbus/dbus_mgr.c')
-rw-r--r--contrib/dbus/dbus_mgr.c2458
1 files changed, 2458 insertions, 0 deletions
diff --git a/contrib/dbus/dbus_mgr.c b/contrib/dbus/dbus_mgr.c
new file mode 100644
index 0000000..b744790
--- /dev/null
+++ b/contrib/dbus/dbus_mgr.c
@@ -0,0 +1,2458 @@
+/* dbus_mgr.c
+ *
+ * named module to provide dynamic forwarding zones in
+ * response to D-BUS dhcp events or commands.
+ *
+ * Copyright(C) Jason Vas Dias, Red Hat Inc., 2005
+ * Modified by Adam Tkac, Red Hat Inc., 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation at
+ * http://www.fsf.org/licensing/licenses/gpl.txt
+ * and included in this software distribution as the "LICENSE" file.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <config.h>
+#include <isc/types.h>
+#include <isc/net.h>
+#include <isc/mem.h>
+#include <isc/magic.h>
+#include <isc/list.h>
+#include <isc/task.h>
+#include <isc/event.h>
+#include <isc/socket.h>
+#include <isc/timer.h>
+#include <isc/netaddr.h>
+#include <isc/sockaddr.h>
+#include <isc/buffer.h>
+#include <isc/log.h>
+
+#include <dns/name.h>
+#include <dns/acl.h>
+#include <dns/fixedname.h>
+#include <dns/view.h>
+#include <dns/forward.h>
+
+#include <named/types.h>
+#include <named/config.h>
+#include <named/server.h>
+#include <named/globals.h>
+#include <named/log.h>
+
+#include <named/dbus_service.h>
+#include <named/dbus_mgr.h>
+
+#include <string.h>
+#include <search.h>
+
+typedef void (*__free_fn_t) (void *__nodep);
+extern void tdestroy (void *__root, __free_fn_t __freefct);
+extern void free(void*);
+
+#ifdef ISC_USE_INTERNAL_MALLOC
+# if ISC_USE_INTERNAL_MALLOC
+# error dbus_mgr cannot be used if ISC_USE_INTERNAL_MALLOC==1
+# endif
+#endif
+
+#define DBUSMGR_DESTINATION "com.redhat.named"
+#define DBUSMGR_OBJECT_PATH "/com/redhat/named"
+#define DBUSMGR_INTERFACE "com.redhat.named"
+
+#define DBUSMGR_MAGIC ISC_MAGIC('D', 'B', 'U', 'S')
+
+struct ns_dbus_mgr
+{
+ unsigned int magic;
+ isc_mem_t * mctx; /* Memory context. */
+ isc_taskmgr_t * taskmgr; /* Task manager. */
+ isc_socketmgr_t * socketmgr; /* Socket manager. */
+ isc_timermgr_t * timermgr; /* Timer manager. */
+ isc_task_t * task; /* task */
+ isc_timer_t * timer; /* dbus_init retry */
+ void * sockets; /* dbus fd tree */
+ void * dhc_if; /* dhcp interface tree */
+ void * ifwdt; /* initial forwarder tree */
+ char * dhcdbd_name; /* dhcdbd destination */
+ DBUS_SVC dbus; /* dbus handle */
+};
+
+typedef
+struct dbus_mgr_sock_s
+{
+ int fd;
+ struct ns_dbus_mgr *mgr;
+ isc_socket_t *sock;
+ isc_socketevent_t *ser;
+ isc_socketevent_t *sew;
+ isc_socketevent_t *sel;
+} DBusMgrSocket;
+
+typedef
+enum dhc_state_e
+{
+ DHC_NBI, /* no broadcast interfaces found */
+ DHC_PREINIT, /* configuration started */
+ DHC_BOUND, /* lease obtained */
+ DHC_RENEW, /* lease renewed */
+ DHC_REBOOT, /* have valid lease, but now obtained a different one */
+ DHC_REBIND, /* new, different lease */
+ DHC_STOP, /* remove old lease */
+ DHC_MEDIUM, /* media selection begun */
+ DHC_TIMEOUT, /* timed out contacting DHCP server */
+ DHC_FAIL, /* all attempts to contact server timed out, sleeping */
+ DHC_EXPIRE, /* lease has expired, renewing */
+ DHC_RELEASE, /* releasing lease */
+ DHC_START, /* sent when dhclient started OK */
+ DHC_ABEND, /* dhclient exited abnormally */
+ DHC_END, /* dhclient exited normally */
+ DHC_END_OPTIONS, /* last option in subscription sent */
+ DHC_INVALID=255
+} DHC_State;
+
+typedef ISC_LIST(dns_name_t) DNSNameList;
+
+typedef ISC_LIST(isc_sockaddr_t) SockAddrList;
+
+typedef struct dbm_fwdr_s
+{
+ dns_fwdpolicy_t fwdpolicy;
+ dns_name_t dn;
+ SockAddrList sa;
+ ISC_LINK( struct dbm_fwdr_s ) link;
+} DBusMgrInitialFwdr;
+
+typedef
+struct dhc_if_s
+{
+ char *if_name;
+ DHC_State dhc_state;
+ DHC_State previous_state;
+ struct in_addr ip;
+ struct in_addr subnet_mask;
+ DNSNameList dn;
+ SockAddrList dns;
+} DHC_IF;
+
+static void
+dbus_mgr_watch_handler( int fd, dbus_svc_WatchFlags flags, void *mgrp );
+
+static
+dbus_svc_HandlerResult
+dbus_mgr_message_handler
+(
+ DBusMsgHandlerArgs
+);
+
+static
+void dbus_mgr_close_socket( const void *p, const VISIT which, const int level);
+
+static
+void dbus_mgr_destroy_socket( void *p );
+
+static
+void dbus_mgr_free_dhc( void *p );
+
+static void
+dbus_mgr_watches_selected(isc_task_t *t, isc_event_t *ev);
+
+static isc_result_t
+dbus_mgr_init_dbus(ns_dbus_mgr_t *);
+
+static isc_result_t
+dbus_mgr_record_initial_fwdtable(ns_dbus_mgr_t *);
+
+static
+dns_fwdtable_t *dbus_mgr_get_fwdtable(void);
+
+static void
+dbus_mgr_free_initial_fwdtable(ns_dbus_mgr_t *);
+
+static
+uint8_t dbus_mgr_subscribe_to_dhcdbd( ns_dbus_mgr_t * );
+
+static
+void dbus_mgr_dbus_shutdown_handler ( ns_dbus_mgr_t * );
+
+static
+int dbus_mgr_log_err( const char *fmt, ...)
+{
+ va_list va;
+ va_start(va, fmt);
+ isc_log_vwrite(ns_g_lctx,
+ NS_LOGCATEGORY_DBUS,
+ NS_LOGMODULE_DBUS,
+ ISC_LOG_NOTICE,
+ fmt, va
+ );
+ va_end(va);
+ return 0;
+}
+
+static
+int dbus_mgr_log_dbg( const char *fmt, ...)
+{
+ va_list va;
+ va_start(va, fmt);
+ isc_log_vwrite(ns_g_lctx,
+ NS_LOGCATEGORY_DBUS,
+ NS_LOGMODULE_DBUS,
+ ISC_LOG_DEBUG(80),
+ fmt, va
+ );
+ va_end(va);
+ return 0;
+}
+
+static
+int dbus_mgr_log_info( const char *fmt, ...)
+{
+ va_list va;
+ va_start(va, fmt);
+ isc_log_vwrite(ns_g_lctx,
+ NS_LOGCATEGORY_DBUS,
+ NS_LOGMODULE_DBUS,
+ ISC_LOG_DEBUG(1),
+ fmt, va
+ );
+ va_end(va);
+ return 0;
+}
+
+isc_result_t
+dbus_mgr_create
+( isc_mem_t *mctx,
+ isc_taskmgr_t *taskmgr,
+ isc_socketmgr_t *socketmgr,
+ isc_timermgr_t *timermgr,
+ ns_dbus_mgr_t **dbus_mgr
+)
+{
+ isc_result_t result;
+ ns_dbus_mgr_t *mgr;
+
+ *dbus_mgr = 0L;
+
+ mgr = isc_mem_get(mctx, sizeof(*mgr));
+ if (mgr == NULL)
+ return (ISC_R_NOMEMORY);
+
+ mgr->magic = DBUSMGR_MAGIC;
+ mgr->mctx = mctx;
+ mgr->taskmgr = taskmgr;
+ mgr->socketmgr = socketmgr;
+ mgr->timermgr = timermgr;
+ mgr->task = 0L;
+ mgr->sockets = 0L;
+ mgr->timer = 0L;
+ mgr->dhc_if = 0L;
+ mgr->ifwdt = 0L;
+ mgr->dhcdbd_name = 0L;
+
+ if( (result = isc_task_create( taskmgr, 100, &(mgr->task)))
+ != ISC_R_SUCCESS
+ ) goto cleanup_mgr;
+
+ isc_task_setname( mgr->task, "dbusmgr", mgr );
+
+ mgr->dbus = 0L;
+
+ if( (result = dbus_mgr_record_initial_fwdtable( mgr ))
+ != ISC_R_SUCCESS
+ ) goto cleanup_mgr;
+
+ if( (result = dbus_mgr_init_dbus( mgr ))
+ != ISC_R_SUCCESS
+ ) goto cleanup_mgr;
+
+ *dbus_mgr = mgr;
+
+ return ISC_R_SUCCESS;
+
+ cleanup_mgr:
+ if ( dbus_mgr_get_fwdtable() != NULL)
+ dbus_mgr_free_initial_fwdtable (mgr);
+ if( mgr->task != 0L )
+ isc_task_detach(&(mgr->task));
+ isc_mem_put(mctx, mgr, sizeof(*mgr));
+ return (result);
+}
+
+static isc_result_t
+dbus_mgr_init_dbus(ns_dbus_mgr_t * mgr)
+{
+ char destination[]=DBUSMGR_DESTINATION;
+ isc_result_t result;
+
+ if( mgr->sockets != 0L )
+ {
+ isc_task_purgerange(mgr->task, 0L, ISC_SOCKEVENT_READ_READY, ISC_SOCKEVENT_SELECTED, 0L);
+ twalk(mgr->sockets, dbus_mgr_close_socket);
+ tdestroy(mgr->sockets, dbus_mgr_destroy_socket);
+ mgr->sockets = 0L;
+ }
+
+ if( mgr->dbus != 0L )
+ {
+ dbus_svc_shutdown(mgr->dbus);
+ mgr->dbus = 0L;
+ }
+
+ result = dbus_svc_init(DBUS_PRIVATE_SYSTEM, destination, &mgr->dbus,
+ dbus_mgr_watch_handler, 0L, 0L, mgr);
+
+ if(result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ if( mgr->dbus == 0L )
+ {
+ if( mgr->timer == 0L)
+ {
+ isc_task_purgerange(mgr->task, 0L, ISC_SOCKEVENT_READ_READY, ISC_SOCKEVENT_SELECTED, 0L);
+ if( mgr->sockets != 0L )
+ {
+ twalk(mgr->sockets, dbus_mgr_close_socket);
+ tdestroy(mgr->sockets, dbus_mgr_destroy_socket);
+ mgr->sockets = 0L;
+ }
+ dbus_mgr_dbus_shutdown_handler ( mgr );
+ return ISC_R_SUCCESS;
+ }
+ goto cleanup;
+ }
+
+ if( !dbus_svc_add_filter
+ ( mgr->dbus, dbus_mgr_message_handler, mgr, 4,
+ "type=signal,path=/org/freedesktop/DBus,member=NameOwnerChanged",
+ "type=signal,path=/org/freedesktop/DBus/Local,member=Disconnected",
+ "type=signal,interface=com.redhat.dhcp.subscribe.binary",
+ "type=method_call,destination=com.redhat.named,path=/com/redhat/named"
+ )
+ )
+ {
+ dbus_mgr_log_err( "dbus_svc_add_filter failed" );
+ goto cleanup;
+ }
+
+ if( mgr->timer != 0L )
+ {
+ isc_timer_reset(mgr->timer,
+ isc_timertype_inactive,
+ NULL, NULL, ISC_TRUE
+ );
+ }
+
+ if( !dbus_mgr_subscribe_to_dhcdbd( mgr ) )
+ dbus_mgr_log_err("D-BUS dhcdbd subscription disabled.");
+
+ dbus_mgr_log_err("D-BUS service enabled.");
+ return ISC_R_SUCCESS;
+
+ cleanup:
+ isc_task_purgerange(mgr->task, 0L, ISC_SOCKEVENT_READ_READY, ISC_SOCKEVENT_SELECTED, 0L);
+ twalk(mgr->sockets, dbus_mgr_close_socket);
+ tdestroy(mgr->sockets, dbus_mgr_destroy_socket);
+ mgr->sockets = 0L;
+ if( mgr->dbus )
+ {
+ dbus_svc_shutdown(mgr->dbus);
+ mgr->dbus = 0L;
+ }
+ return ISC_R_FAILURE;
+}
+
+static
+uint8_t dbus_mgr_subscribe_to_dhcdbd( ns_dbus_mgr_t *mgr )
+{
+ DBUS_SVC dbus = mgr->dbus;
+ char subs[1024], path[1024],
+ dhcdbd_destination[]="com.redhat.dhcp", *ddp[1]={ &(dhcdbd_destination[0]) },
+ *dhcdbd_name=0L;
+ const char *options[] = { "reason", "ip-address", "subnet-mask",
+ "domain-name", "domain-name-servers"
+ };
+ dbus_svc_MessageHandle msg;
+ int i, n_opts = 5;
+
+ if( mgr->dhcdbd_name == 0L )
+ {
+ msg = dbus_svc_call
+ ( dbus,
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "GetNameOwner",
+ "org.freedesktop.DBus",
+ TYPE_STRING, &ddp,
+ TYPE_INVALID
+ );
+ if( msg == 0L )
+ return 0;
+
+ if( !dbus_svc_get_args(dbus, msg,
+ TYPE_STRING, &(dhcdbd_name),
+ TYPE_INVALID
+ )
+ ) return 0;
+
+ mgr->dhcdbd_name = isc_mem_get(mgr->mctx, strlen(dhcdbd_name) + 1);
+ if( mgr->dhcdbd_name == 0L )
+ return 0;
+
+ strcpy(mgr->dhcdbd_name, dhcdbd_name);
+
+ }
+
+ sprintf(path,"/com/redhat/dhcp/subscribe");
+ sprintf(subs,"com.redhat.dhcp.binary");
+
+ for(i = 0; i < n_opts; i++)
+ {
+ msg = dbus_svc_call
+ ( dbus,
+ "com.redhat.dhcp",
+ path,
+ "binary",
+ subs,
+ TYPE_STRING, &(options[i]),
+ TYPE_INVALID
+ );
+ if(msg == 0L)
+ return 0;
+ if ( dbus_svc_message_type( msg ) == ERROR )
+ return 0;
+ }
+ dbus_mgr_log_err("D-BUS dhcdbd subscription enabled.");
+ return 1;
+}
+
+void
+dbus_mgr_shutdown
+( ns_dbus_mgr_t *mgr
+)
+{
+ if( mgr->timer != 0L )
+ isc_timer_detach(&(mgr->timer));
+ if( mgr->dbus != 0L )
+ {
+ isc_task_purgerange(mgr->task, 0L, ISC_SOCKEVENT_READ_READY, ISC_SOCKEVENT_SELECTED, 0L);
+ if( mgr->sockets != 0L )
+ {
+ twalk(mgr->sockets, dbus_mgr_close_socket);
+ tdestroy(mgr->sockets, dbus_mgr_destroy_socket);
+ mgr->sockets = 0L;
+ }
+ dbus_svc_shutdown(mgr->dbus);
+ }
+ if( mgr->dhc_if != 0L )
+ tdestroy(mgr->dhc_if, dbus_mgr_free_dhc);
+ if( mgr->dhcdbd_name != 0L )
+ isc_mem_put(mgr->mctx, mgr->dhcdbd_name, strlen(mgr->dhcdbd_name) + 1);
+ isc_task_detach(&(mgr->task));
+ dbus_mgr_free_initial_fwdtable(mgr);
+ isc_mem_put(mgr->mctx, mgr, sizeof(ns_dbus_mgr_t));
+}
+
+static
+void dbus_mgr_restart_dbus(isc_task_t *t, isc_event_t *ev)
+{
+ ns_dbus_mgr_t *mgr = (ns_dbus_mgr_t*)(ev->ev_arg) ;
+ t=t;
+ isc_event_free(&ev);
+ dbus_mgr_log_dbg("attempting to connect to D-BUS");
+ dbus_mgr_init_dbus( mgr );
+}
+
+static
+void dbus_mgr_handle_dbus_shutdown_event(isc_task_t *t, isc_event_t *ev)
+{
+ ns_dbus_mgr_t *mgr = ev->ev_arg;
+ isc_time_t tick={10,0};
+ isc_interval_t tock={10,0};
+ DBUS_SVC dbus = mgr->dbus;
+ t = t;
+
+ mgr->dbus = 0L;
+
+ isc_event_free(&ev);
+
+ if ( dbus != 0L )
+ {
+ isc_task_purgerange(mgr->task, 0L, ISC_SOCKEVENT_READ_READY, ISC_SOCKEVENT_SELECTED, 0L);
+ if( mgr->sockets != 0L )
+ {
+ twalk(mgr->sockets, dbus_mgr_close_socket);
+ tdestroy(mgr->sockets, dbus_mgr_destroy_socket);
+ mgr->sockets = 0L;
+ }
+ dbus_svc_shutdown(dbus);
+ }
+
+ dbus_mgr_log_err( "D-BUS service disabled." );
+
+ if( mgr->timer != 0L )
+ {
+ isc_timer_reset(mgr->timer,
+ isc_timertype_ticker,
+ &tick, &tock, ISC_TRUE
+ );
+ }else
+ if( isc_timer_create
+ ( mgr->timermgr,
+ isc_timertype_ticker,
+ &tick, &tock,
+ mgr->task,
+ dbus_mgr_restart_dbus,
+ mgr,
+ &(mgr->timer)
+ ) != ISC_R_SUCCESS
+ )
+ {
+ dbus_mgr_log_err( "D-BUS service cannot be restored." );
+ }
+}
+
+static
+void dbus_mgr_dbus_shutdown_handler ( ns_dbus_mgr_t *mgr )
+{
+ isc_event_t *dbus_shutdown_event =
+ isc_event_allocate
+ ( mgr->mctx,
+ mgr->task,
+ 1,
+ dbus_mgr_handle_dbus_shutdown_event,
+ mgr,
+ sizeof(isc_event_t)
+ );
+ if( dbus_shutdown_event != 0L )
+ {
+ isc_task_purgerange(mgr->task, 0L, ISC_SOCKEVENT_READ_READY, ISC_SOCKEVENT_SELECTED, 0L);
+ isc_task_send( mgr->task, &dbus_shutdown_event );
+ }else
+ dbus_mgr_log_err("unable to allocate dbus shutdown event");
+}
+
+static
+dns_view_t *dbus_mgr_get_localhost_view(void)
+{
+ dns_view_t *view;
+ isc_netaddr_t localhost = { AF_INET, { { htonl( ( 127 << 24 ) | 1 ) } }, 0 };
+ int match;
+
+ for (view = ISC_LIST_HEAD(ns_g_server->viewlist);
+ view != NULL;
+ view = ISC_LIST_NEXT(view, link)
+ )
+ {
+ /* return first view matching "localhost" source and dest */
+
+ if(( (view->matchclients != 0L ) /* 0L: accept "any" */
+ &&(( dns_acl_match( &localhost,
+ NULL, /* unsigned queries */
+ view->matchclients,
+ &(ns_g_server->aclenv),
+ &match,
+ NULL /* no match list */
+ ) != ISC_R_SUCCESS
+ ) || (match <= 0)
+ )
+ )
+ ||( (view->matchdestinations != 0L ) /* 0L: accept "any" */
+ &&(( dns_acl_match( &localhost,
+ NULL, /* unsigned queries */
+ view->matchdestinations,
+ &(ns_g_server->aclenv),
+ &match,
+ NULL /* no match list */
+ ) != ISC_R_SUCCESS
+ ) || (match <= 0)
+ )
+ )
+ ) continue;
+
+ break;
+ }
+ return view;
+}
+
+static
+dns_fwdtable_t *dbus_mgr_get_fwdtable(void)
+{
+ dns_view_t *view = dbus_mgr_get_localhost_view();
+ if( view != 0L )
+ return view->fwdtable;
+ return 0L;
+}
+
+static
+dns_fwdtable_t *dbus_mgr_get_view_and_fwdtable( dns_view_t **viewp )
+{
+ *viewp = dbus_mgr_get_localhost_view();
+ if( *viewp != 0L )
+ return (*viewp)->fwdtable;
+ return 0L;
+}
+
+static int dbus_mgr_ifwdr_comparator( const void *p1, const void *p2 )
+{
+ char n1buf[ DNS_NAME_FORMATSIZE ]="", *n1p=&(n1buf[0]),
+ n2buf[ DNS_NAME_FORMATSIZE ]="", *n2p=&(n2buf[0]);
+ dns_name_t *dn1;
+ dns_name_t *dn2;
+ DE_CONST(&(((const DBusMgrInitialFwdr*)p1)->dn), dn1);
+ DE_CONST(&(((const DBusMgrInitialFwdr*)p2)->dn), dn2);
+ dns_name_format(dn1, n1p, DNS_NAME_FORMATSIZE );
+ dns_name_format(dn2, n2p, DNS_NAME_FORMATSIZE );
+ return strcmp(n1buf, n2buf);
+}
+
+static int dbus_mgr_dhc_if_comparator( const void *p1, const void *p2 );
+
+static void dbus_mgr_record_initial_forwarder( dns_name_t *name, dns_forwarders_t *fwdr, void *mp )
+{
+ ns_dbus_mgr_t *mgr = mp;
+ isc_sockaddr_t *sa, *nsa;
+ DBusMgrInitialFwdr *ifwdr;
+
+ if( ISC_LIST_HEAD(fwdr->addrs) == 0L)
+ return;
+
+ if( (ifwdr = isc_mem_get(mgr->mctx, sizeof(DBusMgrInitialFwdr))) == 0L)
+ return;
+
+ ifwdr->fwdpolicy = fwdr->fwdpolicy;
+
+ dns_name_init(&(ifwdr->dn), NULL);
+ if( dns_name_dupwithoffsets(name, mgr->mctx, &(ifwdr->dn)) != ISC_R_SUCCESS )
+ goto namedup_err;
+
+ ISC_LIST_INIT(ifwdr->sa);
+
+ for( sa = ISC_LIST_HEAD(fwdr->addrs);
+ sa != 0L;
+ sa = ISC_LIST_NEXT(sa,link)
+ )
+ {
+ nsa = isc_mem_get(mgr->mctx, sizeof(isc_sockaddr_t));
+ if( nsa == 0L )
+ goto nsa_err;
+ *nsa = *sa;
+ ISC_LINK_INIT(nsa, link);
+ ISC_LIST_APPEND(ifwdr->sa, nsa, link);
+ }
+ ISC_LINK_INIT(ifwdr, link);
+ tsearch( ifwdr, &(mgr->ifwdt), dbus_mgr_ifwdr_comparator);
+
+ return;
+
+nsa_err:
+ while ( (sa = ISC_LIST_HEAD (ifwdr->sa)) != NULL) {
+ ISC_LIST_UNLINK (ifwdr->sa, sa, link);
+ isc_mem_put (mgr->mctx, sa, sizeof (*sa));
+ }
+
+namedup_err:
+ isc_mem_put (mgr->mctx, ifwdr, sizeof (*ifwdr));
+
+ return;
+}
+
+static isc_result_t
+dbus_mgr_record_initial_fwdtable( ns_dbus_mgr_t *mgr )
+{
+ dns_fwdtable_t *fwdtable = dbus_mgr_get_fwdtable();
+
+ if( fwdtable == 0L )
+ return ISC_R_SUCCESS; /* no initial fwdtable */
+ dns_fwdtable_foreach( fwdtable, dbus_mgr_record_initial_forwarder, mgr);
+ return ISC_R_SUCCESS;
+}
+
+static void
+dbus_mgr_free_initial_forwarder( void *p )
+{
+ DBusMgrInitialFwdr *ifwdr = p;
+ isc_sockaddr_t *sa;
+
+ dns_name_free(&(ifwdr->dn), ns_g_mctx);
+ for( sa = ISC_LIST_HEAD( ifwdr->sa );
+ sa != 0L;
+ sa = ISC_LIST_HEAD( ifwdr->sa )
+ )
+ {
+ if( ISC_LINK_LINKED(sa, link) )
+ ISC_LIST_UNLINK(ifwdr->sa, sa, link);
+ isc_mem_put(ns_g_mctx, sa, sizeof(isc_sockaddr_t));
+ }
+ isc_mem_put(ns_g_mctx, ifwdr, sizeof(DBusMgrInitialFwdr));
+}
+
+static void
+dbus_mgr_free_initial_fwdtable( ns_dbus_mgr_t *mgr )
+{
+ tdestroy(mgr->ifwdt, dbus_mgr_free_initial_forwarder);
+ mgr->ifwdt = 0L;
+}
+
+static void
+dbus_mgr_log_forwarders( const char *pfx, dns_name_t *name, SockAddrList *saList)
+{
+ isc_sockaddr_t *sa;
+ char nameP[DNS_NAME_FORMATSIZE], addrP[128];
+ int s=0;
+ dns_name_format(name, nameP, DNS_NAME_FORMATSIZE );
+ for( sa = ISC_LIST_HEAD(*saList);
+ sa != 0L;
+ sa = ISC_LIST_NEXT(sa,link)
+ )
+ {
+ isc_sockaddr_format(sa, addrP, 128);
+ dbus_mgr_log_info("%s zone %s server %d: %s", pfx, nameP, s++, addrP);
+ }
+}
+
+static
+isc_result_t dbus_mgr_set_forwarders
+(
+ ns_dbus_mgr_t *mgr,
+ DNSNameList *nameList,
+ SockAddrList *saList,
+ dns_fwdpolicy_t fwdpolicy
+)
+{
+ isc_result_t result = ISC_R_SUCCESS;
+ dns_fwdtable_t *fwdtable;
+ dns_view_t *view=0L;
+ dns_name_t *dnsName;
+ isc_sockaddr_t *sa, *nsa;
+ dns_forwarders_t *fwdr=0L;
+
+ fwdtable = dbus_mgr_get_view_and_fwdtable(&view);
+
+ if( fwdtable == 0L )
+ {
+ if( ISC_LIST_HEAD(*saList) == 0L )
+ return ISC_R_SUCCESS;/* deletion not required */
+
+ view = dbus_mgr_get_localhost_view();
+ if( view == 0L )
+ return ISC_R_NOPERM; /* if configuration does not allow localhost clients,
+ * then we really shouldn't be creating a forwarding table.
+ */
+ result = isc_task_beginexclusive(mgr->task);
+
+ if( result == ISC_R_SUCCESS )
+ {
+ result = dns_fwdtable_create( mgr->mctx, &(view->fwdtable) );
+
+ isc_task_endexclusive(mgr->task);
+
+ if( result != ISC_R_SUCCESS )
+ return result;
+
+ if( view->fwdtable == 0L )
+ return ISC_R_NOMEMORY;
+
+ if( isc_log_getdebuglevel(ns_g_lctx) >= 1 )
+ dbus_mgr_log_info("Created forwarder table.");
+ }
+ }
+
+ for( dnsName = ISC_LIST_HEAD(*nameList);
+ dnsName != NULL;
+ dnsName = ISC_LIST_NEXT(dnsName,link)
+ )
+ {
+ fwdr = 0L;
+ if( ( dns_fwdtable_find_exact( fwdtable, dnsName, &fwdr ) != ISC_R_SUCCESS )
+ ||( fwdr == 0L )
+ )
+ {
+ if( ISC_LIST_HEAD( *saList ) == 0L )
+ continue;
+ /* no forwarders for name - add forwarders */
+
+ result = isc_task_beginexclusive(mgr->task);
+
+ if( result == ISC_R_SUCCESS )
+ {
+ result = dns_fwdtable_add( fwdtable, dnsName,
+ (isc_sockaddrlist_t*)saList,
+ fwdpolicy
+ ) ;
+
+ if( view != 0L )
+ dns_view_flushcache( view );
+
+ isc_task_endexclusive(mgr->task);
+
+ if( result != ISC_R_SUCCESS )
+ return result;
+
+ if( isc_log_getdebuglevel(ns_g_lctx) >= 1 )
+ dbus_mgr_log_forwarders("Created forwarder",dnsName, saList);
+ }
+ continue;
+ }
+
+ if( ISC_LIST_HEAD( *saList ) == 0L )
+ { /* empty forwarders list - delete forwarder entry */
+
+ if( isc_log_getdebuglevel(ns_g_lctx) >= 1 )
+ dbus_mgr_log_forwarders("Deleting forwarder", dnsName, (SockAddrList*)&(fwdr->addrs));
+
+ result = isc_task_beginexclusive(mgr->task);
+ if( result == ISC_R_SUCCESS )
+ {
+ result = dns_fwdtable_delete( fwdtable, dnsName );
+
+ if( view != 0L )
+ dns_view_flushcache( view );
+
+ isc_task_endexclusive(mgr->task);
+
+ if( result != ISC_R_SUCCESS )
+ return result;
+ }
+ continue;
+ }
+
+ result = isc_task_beginexclusive(mgr->task);
+
+ if( result == ISC_R_SUCCESS )
+ {
+ fwdr->fwdpolicy = fwdpolicy;
+
+ if( isc_log_getdebuglevel(ns_g_lctx) >= 1 )
+ dbus_mgr_log_forwarders("Removing forwarder", dnsName, (SockAddrList*)&(fwdr->addrs));
+
+ for( sa = ISC_LIST_HEAD(fwdr->addrs);
+ sa != 0L ;
+ sa = ISC_LIST_HEAD(fwdr->addrs)
+ )
+ {
+ if( ISC_LINK_LINKED(sa, link) )
+ ISC_LIST_UNLINK(fwdr->addrs, sa, link);
+ isc_mem_put(mgr->mctx, sa, sizeof(isc_sockaddr_t));
+ }
+
+ ISC_LIST_INIT( fwdr->addrs );
+
+ for( sa = ISC_LIST_HEAD(*saList);
+ sa != 0L;
+ sa = ISC_LIST_NEXT(sa,link)
+ )
+ {
+ nsa = isc_mem_get(mgr->mctx, sizeof(isc_sockaddr_t));
+ if( nsa == 0L )
+ {
+ result = ISC_R_NOMEMORY;
+ break;
+ }
+ *nsa = *sa;
+ ISC_LINK_INIT( nsa, link );
+ ISC_LIST_APPEND( fwdr->addrs, nsa, link );
+ }
+
+ if( view != 0L )
+ dns_view_flushcache( view );
+
+ isc_task_endexclusive(mgr->task);
+
+ if( isc_log_getdebuglevel(ns_g_lctx) >= 1 )
+ dbus_mgr_log_forwarders("Added forwarder", dnsName, (SockAddrList*)&(fwdr->addrs));
+
+ }else
+ return result;
+
+ }
+ return (result);
+}
+
+static void
+dbus_mgr_get_name_list
+(
+ ns_dbus_mgr_t *mgr,
+ char *domains,
+ DNSNameList *nameList,
+ char *error_name,
+ char *error_message
+)
+{
+ char *name, *endName, *endp;
+ dns_fixedname_t *fixedname;
+ dns_name_t *dnsName;
+ isc_buffer_t buffer;
+ isc_result_t result;
+ uint32_t total_length;
+
+ total_length = strlen(domains);
+ endp = domains + total_length;
+
+ ISC_LIST_INIT( *nameList );
+
+ for( name = domains + strspn(domains," \t\n"),
+ endName = name + strcspn(name," \t\n");
+ (name < endp) && (endName <= endp);
+ name = endName + 1 + strspn(endName+1," \t\n"),
+ endName = name + strcspn(name," \t\n")
+ )
+ { /* name loop */
+ *endName = '\0';
+
+ isc_buffer_init( &buffer, name, endName - name );
+ isc_buffer_add(&buffer, endName - name);
+
+ fixedname = isc_mem_get( mgr->mctx, sizeof( dns_fixedname_t ));
+
+ dns_fixedname_init(fixedname);
+
+ dnsName = dns_fixedname_name(fixedname);
+
+ result= dns_name_fromtext
+ ( dnsName, &buffer, ( *(endp-1) != '.') ? dns_rootname : NULL, ISC_FALSE, NULL
+ );
+
+ if( result != ISC_R_SUCCESS )
+ {
+ sprintf(error_name, "com.redhat.named.InvalidArgument");
+ sprintf(error_message,"Invalid DNS name initial argument: %s", name);
+
+ isc_mem_put( mgr->mctx, fixedname, sizeof( dns_fixedname_t ) );
+
+ for( dnsName = ISC_LIST_HEAD( *nameList );
+ (dnsName != 0L);
+ dnsName = ISC_LIST_HEAD( *nameList )
+ )
+ {
+ if( ISC_LINK_LINKED(dnsName,link) )
+ ISC_LIST_DEQUEUE( *nameList, dnsName, link );
+ isc_mem_put( mgr->mctx, dnsName, sizeof( dns_fixedname_t ) );
+ }
+ ISC_LIST_INIT(*nameList);
+ return;
+ }
+ ISC_LINK_INIT(dnsName, link);
+ ISC_LIST_ENQUEUE( *nameList, dnsName, link );
+ }
+}
+
+static isc_result_t
+dbus_mgr_get_sa_list
+(
+ ns_dbus_mgr_t *mgr,
+ dbus_svc_MessageIterator iter,
+ SockAddrList *saList ,
+ uint8_t *fwdpolicy,
+ char *error_name,
+ char *error_message
+)
+{
+ DBUS_SVC dbus = mgr->dbus;
+ isc_sockaddr_t *nsSA=0L, *nsSA_Q=0L;
+ uint32_t argType = dbus_svc_message_next_arg_type( dbus, iter ),
+ length;
+ isc_result_t result;
+ in_port_t port;
+ char *ip;
+ uint8_t *iparray=0L;
+
+ ISC_LIST_INIT(*saList);
+
+ if( argType == TYPE_INVALID )
+ return ISC_R_SUCCESS; /* address list "removal" */
+
+ do
+ {
+ switch( argType )
+ {
+ case TYPE_UINT32:
+
+ nsSA = isc_mem_get(mgr->mctx, sizeof(isc_sockaddr_t));
+ if( nsSA != 0L )
+ {
+ memset(nsSA,'\0', sizeof(isc_sockaddr_t));
+ nsSA_Q = nsSA;
+ dbus_svc_message_next_arg(dbus, iter, &(nsSA->type.sin.sin_addr.s_addr));
+ nsSA->type.sa.sa_family = AF_INET;
+ nsSA->length = sizeof( nsSA->type.sin );
+ }
+ break;
+
+ case TYPE_ARRAY:
+
+ argType = dbus_svc_message_element_type( dbus, iter );
+ if( argType == TYPE_BYTE )
+ {
+ iparray = 0L;
+ length = 0;
+
+ dbus_svc_message_get_elements(dbus, iter, &length, &iparray);
+
+ if( iparray != 0L )
+ {
+ if (length == sizeof( struct in_addr ))
+ {
+ nsSA = isc_mem_get(mgr->mctx, sizeof(isc_sockaddr_t));
+ if( nsSA != 0L )
+ {
+ memset(nsSA,'\0', sizeof(isc_sockaddr_t));
+ nsSA_Q = nsSA;
+
+ memcpy(&(nsSA->type.sin.sin_addr), iparray, sizeof( struct in_addr ));
+ nsSA->type.sa.sa_family = AF_INET;
+ nsSA->length = sizeof( nsSA->type.sin );
+ }
+ }else
+ if (length == sizeof( struct in6_addr ))
+ {
+ nsSA = isc_mem_get(mgr->mctx, sizeof(isc_sockaddr_t));
+ if( nsSA != 0L )
+ {
+ memset(nsSA,'\0', sizeof(isc_sockaddr_t));
+ nsSA_Q = nsSA;
+
+ memcpy(&(nsSA->type.sin6.sin6_addr), iparray, sizeof( struct in6_addr ));
+ nsSA->type.sa.sa_family = AF_INET6;
+ nsSA->length = sizeof( nsSA->type.sin6 );
+ }
+ }
+ }
+ }
+ break;
+
+ case TYPE_STRING:
+
+ ip = 0L;
+ dbus_svc_message_next_arg(dbus, iter, &(ip));
+ if( ip != 0L )
+ {
+ length = strlen(ip);
+ if( strspn(ip, "0123456789.") == length )
+ {
+ nsSA = isc_mem_get(mgr->mctx, sizeof(isc_sockaddr_t));
+ if( nsSA != 0L)
+ {
+ memset(nsSA,'\0', sizeof(isc_sockaddr_t));
+ if( inet_pton( AF_INET, ip, &(nsSA->type.sin.sin_addr)) )
+ {
+ nsSA->type.sa.sa_family = AF_INET;
+ nsSA->length = sizeof(nsSA->type.sin);
+ nsSA_Q = nsSA;
+ }
+ }
+ }else
+ if( strspn(ip, "0123456789AaBbCcDdEeFf:.") == length)
+ {
+ nsSA = isc_mem_get(mgr->mctx, sizeof(isc_sockaddr_t));
+ if( nsSA != 0L )
+ {
+ memset(nsSA,'\0', sizeof(isc_sockaddr_t));
+ if( inet_pton( AF_INET6, ip, &(nsSA->type.sin6.sin6_addr)) )
+ {
+ nsSA->type.sa.sa_family = AF_INET6;
+ nsSA->length = sizeof(nsSA->type.sin6);
+ nsSA_Q = nsSA;
+ }
+ }
+ }
+ }
+ break;
+
+ case TYPE_UINT16:
+
+ if( (nsSA == 0L) || (nsSA->type.sa.sa_family == AF_UNSPEC) )
+ break;
+ else
+ if( nsSA->type.sa.sa_family == AF_INET )
+ dbus_svc_message_next_arg(dbus, iter, &(nsSA->type.sin.sin_port));
+ else
+ if( nsSA->type.sa.sa_family == AF_INET6 )
+ dbus_svc_message_next_arg(dbus, iter, &(nsSA->type.sin6.sin6_port));
+ break;
+
+ case TYPE_BYTE:
+
+ dbus_svc_message_next_arg(dbus, iter, fwdpolicy);
+ if(*fwdpolicy > dns_fwdpolicy_only)
+ *fwdpolicy = dns_fwdpolicy_only;
+ break;
+
+ default:
+
+ if(nsSA != 0L)
+ nsSA->type.sa.sa_family = AF_UNSPEC;
+ sprintf(error_message,"Unhandled argument type: %c", argType);
+ break;
+ }
+
+ if( (nsSA != 0L)
+ &&(nsSA->type.sa.sa_family == AF_UNSPEC)
+ )
+ {
+ sprintf(error_name, "com.redhat.named.InvalidArgument");
+ if( error_message[0]=='\0')
+ {
+ if( nsSA == 0L )
+ sprintf(error_message,"Missing IP Address Name Server argument");
+ else
+ sprintf(error_message,"Bad IP Address Name Server argument");
+ }
+ if( nsSA != 0L )
+ isc_mem_put(mgr->mctx, nsSA, sizeof(isc_sockaddr_t));
+ nsSA = 0L;
+ for( nsSA = ISC_LIST_HEAD( *saList );
+ (nsSA != 0L);
+ nsSA = ISC_LIST_HEAD( *saList )
+ )
+ {
+ if(ISC_LINK_LINKED(nsSA, link))
+ ISC_LIST_DEQUEUE( *saList, nsSA, link );
+ isc_mem_put( mgr->mctx, nsSA, sizeof( isc_sockaddr_t ) );
+ }
+ ISC_LIST_INIT(*saList);
+ return ISC_R_FAILURE;
+ }
+
+ if( nsSA != 0L )
+ {
+ if( nsSA->type.sin.sin_port == 0 )
+ {
+ if( ns_g_port != 0L )
+ nsSA->type.sin.sin_port = htons(ns_g_port);
+ else
+ {
+ result = ns_config_getport(ns_g_config, &(port) );
+ if( result != ISC_R_SUCCESS )
+ port = 53;
+ nsSA->type.sin.sin_port = htons( port );
+ }
+ }
+
+ if( nsSA_Q != 0L )
+ {
+ ISC_LINK_INIT(nsSA,link);
+ ISC_LIST_ENQUEUE(*saList, nsSA, link);
+ nsSA_Q = 0L;
+ }
+ }
+
+ argType = dbus_svc_message_next_arg_type( dbus, iter );
+
+ } while ( argType != TYPE_INVALID );
+
+ return ISC_R_SUCCESS;
+}
+
+static void
+dbus_mgr_handle_set_forwarders
+(
+ ns_dbus_mgr_t *mgr,
+ DBUS_SVC dbus,
+ uint8_t reply_expected,
+ uint32_t serial,
+ const char *path,
+ const char *member,
+ const char *interface,
+ const char *sender,
+ dbus_svc_MessageHandle msg
+)
+{
+ dbus_svc_MessageIterator iter;
+ char error_name[1024]="", error_message[1024]="", *domains=0L;
+ uint32_t argType, new_serial;
+ DNSNameList nameList;
+ dns_name_t *dnsName;
+ SockAddrList saList;
+ isc_sockaddr_t *nsSA;
+ isc_result_t result;
+ uint8_t fwdpolicy = dns_fwdpolicy_only;
+
+ iter = dbus_svc_message_iterator_new( dbus, msg );
+
+ if( iter == 0L )
+ {
+ if( reply_expected )
+ {
+ sprintf(error_name, "com.redhat.named.InvalidArguments");
+ sprintf(error_message,"SetForwarders requires DNS name and nameservers arguments.");
+ dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
+ TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
+ );
+ }
+ return;
+ }
+
+ argType = dbus_svc_message_next_arg_type( dbus, iter );
+
+ if( argType != TYPE_STRING )
+ {
+ if( reply_expected )
+ {
+ sprintf(error_name, "com.redhat.named.InvalidArguments");
+ sprintf(error_message,"SetForwarders requires DNS name string initial argument.");
+ dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
+ TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
+ );
+ }
+ return;
+ }
+
+ dbus_svc_message_next_arg( dbus, iter, &domains );
+
+ if( ( domains == 0L ) || (*domains == '\0') )
+ {
+ if( reply_expected )
+ {
+ sprintf(error_name, "com.redhat.named.InvalidArguments");
+ sprintf(error_message,"SetForwarders requires DNS name string initial argument.");
+ dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
+ TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
+ );
+ }
+ return;
+ }
+
+ dbus_mgr_get_name_list( mgr, domains, &nameList, error_name, error_message );
+
+ if( error_name[0] != '\0' )
+ {
+ if( reply_expected )
+ {
+ dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
+ TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
+ );
+ }
+ return;
+ }
+
+ if( ISC_LIST_HEAD( nameList ) == 0L )
+ return;
+
+ result = dbus_mgr_get_sa_list( mgr, iter, &saList , &fwdpolicy, error_name, error_message );
+
+ if( result == ISC_R_SUCCESS )
+ {
+ result = dbus_mgr_set_forwarders( mgr, &nameList, &saList, fwdpolicy );
+
+ if( result != ISC_R_SUCCESS )
+ {
+ if( reply_expected )
+ {
+ sprintf(error_name, "com.redhat.named.Failure");
+ sprintf(error_message, isc_result_totext(result));
+ dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
+ TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
+ );
+ }
+ }else
+ if( reply_expected )
+ dbus_svc_send( dbus, RETURN, serial, &new_serial, sender, path, interface, member,
+ TYPE_UINT32, &result, TYPE_INVALID
+ );
+ }else
+ {
+ if( reply_expected )
+ {
+ dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
+ TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
+ );
+ }
+ }
+
+ for( dnsName = ISC_LIST_HEAD( nameList );
+ (dnsName != 0L) ;
+ dnsName = ISC_LIST_HEAD( nameList )
+ )
+ {
+ if( ISC_LINK_LINKED(dnsName,link) )
+ ISC_LIST_DEQUEUE( nameList, dnsName, link );
+ isc_mem_put( mgr->mctx, dnsName, sizeof( dns_fixedname_t ) );
+ }
+
+ for( nsSA = ISC_LIST_HEAD(saList);
+ (nsSA != 0L) ;
+ nsSA = ISC_LIST_HEAD(saList)
+ )
+ {
+ if( ISC_LINK_LINKED(nsSA,link) )
+ ISC_LIST_DEQUEUE( saList, nsSA, link );
+ isc_mem_put(mgr->mctx, nsSA, sizeof(isc_sockaddr_t));
+ }
+}
+
+static
+int dbus_mgr_msg_append_dns_name
+( DBUS_SVC dbus,
+ dbus_svc_MessageHandle msg,
+ dns_name_t *name
+)
+{
+ char nameBuf[ DNS_NAME_FORMATSIZE ]="", *nameP=&(nameBuf[0]);
+
+ dns_name_format(name, nameP, DNS_NAME_FORMATSIZE );
+
+ if( *nameP == '\0' )
+ return 0;
+
+ return dbus_svc_message_append_args( dbus, msg, TYPE_STRING, &nameP, TYPE_INVALID ) > 0;
+}
+
+typedef enum dbmoi_e
+{
+ OUTPUT_BINARY,
+ OUTPUT_TEXT
+} DBusMgrOutputInterface;
+
+static
+int dbus_mgr_msg_append_forwarders
+( DBUS_SVC dbus,
+ dbus_svc_MessageHandle msg,
+ dns_forwarders_t *fwdr,
+ DBusMgrOutputInterface outputType
+)
+{
+ isc_sockaddr_t *sa;
+ char policyBuf[16]="", *pbp[1]={&(policyBuf[0])}, addressBuf[64]="", *abp[1]={&(addressBuf[0])};
+ uint8_t *byteArray[1];
+
+ if( outputType == OUTPUT_BINARY )
+ {
+ if(!dbus_svc_message_append_args
+ ( dbus, msg,
+ TYPE_BYTE, &(fwdr->fwdpolicy),
+ TYPE_INVALID
+ )
+ ) return 0;
+ }else
+ if( outputType == OUTPUT_TEXT )
+ {
+ sprintf(policyBuf,"%s",
+ (fwdr->fwdpolicy == dns_fwdpolicy_none)
+ ? "none"
+ : (fwdr->fwdpolicy == dns_fwdpolicy_first)
+ ? "first"
+ : "only"
+ );
+ if(!dbus_svc_message_append_args
+ ( dbus, msg,
+ TYPE_STRING, pbp,
+ TYPE_INVALID
+ )
+ ) return 0;
+ }else
+ return 0;
+
+ for( sa = ISC_LIST_HEAD(fwdr->addrs);
+ sa != 0L;
+ sa = ISC_LIST_NEXT(sa, link)
+ )
+ {
+ if( outputType == OUTPUT_BINARY )
+ {
+ if( sa->type.sa.sa_family == AF_INET )
+ {
+ if(!dbus_svc_message_append_args
+ ( dbus, msg,
+ TYPE_UINT32, &(sa->type.sin.sin_addr.s_addr),
+ TYPE_INVALID
+ )
+ ) return 0;
+
+ if(!dbus_svc_message_append_args
+ ( dbus, msg,
+ TYPE_UINT16, &(sa->type.sin.sin_port),
+ TYPE_INVALID
+ )
+ ) return 0;
+ }else
+ if( sa->type.sa.sa_family == AF_INET6 )
+ {
+ byteArray[0] = (uint8_t*)&(sa->type.sin6.sin6_addr);
+ if(!dbus_svc_message_append_args
+ ( dbus, msg,
+ TYPE_ARRAY, TYPE_BYTE, &byteArray, sizeof(struct in6_addr),
+ TYPE_INVALID
+ )
+ ) return 0;
+
+ if(!dbus_svc_message_append_args
+ ( dbus, msg,
+ TYPE_UINT16, &(sa->type.sin6.sin6_port),
+ TYPE_INVALID
+ )
+ ) return 0;
+ }else
+ continue;
+ }else
+ if( outputType == OUTPUT_TEXT )
+ {
+ if( sa->type.sa.sa_family == AF_INET )
+ {
+ if( inet_ntop( AF_INET, &(sa->type.sin.sin_addr), addressBuf, sizeof(addressBuf)) == 0L )
+ continue;
+ if(!dbus_svc_message_append_args
+ ( dbus, msg,
+ TYPE_STRING, abp,
+ TYPE_INVALID
+ )
+ ) return 0;
+ sprintf(addressBuf, "%hu", ntohs( sa->type.sin.sin_port ));
+ if(!dbus_svc_message_append_args
+ ( dbus, msg,
+ TYPE_STRING, abp,
+ TYPE_INVALID
+ )
+ ) return 0;
+ }else
+ if( sa->type.sa.sa_family == AF_INET6 )
+ {
+ if( inet_ntop( AF_INET6, &(sa->type.sin6.sin6_addr), addressBuf, sizeof(addressBuf)) == 0L )
+ continue;
+ if(!dbus_svc_message_append_args
+ ( dbus, msg,
+ TYPE_STRING, abp,
+ TYPE_INVALID
+ )
+ ) return 0;
+ sprintf(addressBuf, "%hu", ntohs( sa->type.sin6.sin6_port ));
+ if(!dbus_svc_message_append_args
+ ( dbus, msg,
+ TYPE_STRING, abp,
+ TYPE_INVALID
+ )
+ ) return 0;
+ }else
+ continue;
+ }else
+ return 0;
+ }
+ return 1;
+}
+
+typedef struct dbm_m_s
+{
+ DBUS_SVC dbus;
+ dbus_svc_MessageHandle msg;
+ DBusMgrOutputInterface outputType;
+} DBusMgrMsg;
+
+static
+void forwarders_to_msg( dns_name_t *name, dns_forwarders_t *fwdr, void *mp )
+{
+ DBusMgrMsg *m = mp;
+
+ if( (fwdr == 0L) || (name == 0L) || (mp == 0L))
+ return;
+ dbus_mgr_msg_append_dns_name ( m->dbus, m->msg, name );
+ dbus_mgr_msg_append_forwarders( m->dbus, m->msg, fwdr, m->outputType );
+}
+
+static void
+dbus_mgr_handle_list_forwarders
+(
+ DBUS_SVC dbus,
+ uint8_t reply_expected,
+ uint32_t serial,
+ const char *path,
+ const char *member,
+ const char *interface,
+ const char *sender,
+ dbus_svc_MessageHandle msg
+)
+{
+ char error_name[1024], error_message[1024];
+ DBusMgrMsg m;
+ uint32_t new_serial;
+ dns_fwdtable_t *fwdtable = dbus_mgr_get_fwdtable();
+ DBusMgrOutputInterface outputType = OUTPUT_BINARY;
+ uint32_t length = strlen(interface);
+
+ if( !reply_expected )
+ return;
+
+ if( (length > 4) && (strcmp(interface + (length - 4), "text")==0))
+ outputType = OUTPUT_TEXT;
+
+ if( fwdtable == 0L )
+ {
+ sprintf(error_name,"com.redhat.dbus.Failure");
+ sprintf(error_message, "%s", isc_result_totext(ISC_R_NOPERM));
+ dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
+ TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
+ );
+ return;
+ }
+
+ msg = dbus_svc_new_message( dbus, RETURN, serial, sender, path, interface, member);
+
+ m.dbus = dbus;
+ m.msg = msg;
+ m.outputType = outputType;
+
+ if( msg == 0L )
+ {
+ sprintf(error_name,"com.redhat.dbus.OutOfMemory");
+ sprintf(error_message,"out of memory");
+ dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
+ TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
+ );
+ }
+
+ dns_fwdtable_foreach( fwdtable, forwarders_to_msg, &m );
+
+ dbus_svc_send_message( dbus, msg, &new_serial );
+}
+
+static void
+dbus_mgr_handle_get_forwarders
+(
+ DBUS_SVC dbus,
+ uint8_t reply_expected,
+ uint32_t serial,
+ const char *path,
+ const char *member,
+ const char *interface,
+ const char *sender,
+ dbus_svc_MessageHandle msg
+)
+{
+ char error_name[1024], error_message[1024], *domain=0L;
+ isc_result_t result;
+ dns_fixedname_t fixedname;
+ dns_name_t *dnsName;
+ isc_buffer_t buffer;
+ uint32_t length, new_serial;
+ dns_fwdtable_t *fwdtable;
+ dns_forwarders_t *fwdr=0L;
+ dns_name_t *foundname;
+ dns_fixedname_t fixedFoundName;
+ DBusMgrOutputInterface outputType = OUTPUT_BINARY;
+
+ if( !reply_expected )
+ return;
+
+ length = strlen(interface);
+
+ if( (length > 4) && (strcmp(interface + (length - 4), "text")==0))
+ outputType = OUTPUT_TEXT;
+
+ if( (!dbus_svc_get_args( dbus, msg, TYPE_STRING, &domain, TYPE_INVALID))
+ ||(domain == 0L)
+ ||(*domain == '\0')
+ )
+ {
+
+ sprintf(error_name,"com.redhat.dbus.InvalidArguments");
+ sprintf(error_message,"domain name argument expected");
+ dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
+ TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
+ );
+ return;
+ }
+
+ length = strlen( domain );
+
+ isc_buffer_init( &buffer, domain, length);
+
+ isc_buffer_add(&buffer, length);
+
+ dns_fixedname_init(&fixedname);
+
+ dnsName = dns_fixedname_name(&fixedname);
+
+ result = dns_name_fromtext
+ ( dnsName, &buffer, dns_rootname, ISC_FALSE, NULL
+ );
+
+ if( result != ISC_R_SUCCESS )
+ {
+ sprintf(error_name,"com.redhat.dbus.InvalidArguments");
+ sprintf(error_message,"invalid domain name argument: %s", domain);
+ dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
+ TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
+ );
+ return;
+ }
+
+ msg = dbus_svc_new_message( dbus, RETURN, serial, sender, path, interface, member);
+
+ if( msg == 0L )
+ {
+ sprintf(error_name,"com.redhat.dbus.OutOfMemory");
+ sprintf(error_message,"out of memory");
+ dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
+ TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
+ );
+ return;
+ }
+
+ fwdtable = dbus_mgr_get_fwdtable();
+
+ if( fwdtable == 0L )
+ {
+ sprintf(error_name,"com.redhat.dbus.Failure");
+ sprintf(error_message, "%s", isc_result_totext(ISC_R_NOPERM));
+ dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
+ TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
+ );
+ return;
+ }
+
+ dns_fixedname_init(&fixedFoundName);
+ foundname = dns_fixedname_name(&fixedFoundName);
+
+ if( ( dns_fwdtable_find_closest( fwdtable, dnsName, foundname, &fwdr ) == ISC_R_SUCCESS )
+ &&( fwdr != 0L )
+ )
+ {
+ if( (!dbus_mgr_msg_append_dns_name( dbus, msg, foundname ))
+ ||(!dbus_mgr_msg_append_forwarders( dbus, msg, fwdr, outputType ))
+ )
+ {
+ sprintf(error_name,"com.redhat.dbus.OutOfMemory");
+ sprintf(error_message,"out of memory");
+ dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
+ TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
+ );
+ return;
+ }
+
+ }else
+ {
+ result = ISC_R_NOTFOUND;
+ if( outputType == OUTPUT_BINARY )
+ {
+ dbus_svc_message_append_args( dbus, msg,
+ TYPE_UINT32, &(result),
+ TYPE_INVALID
+ ) ;
+ }else
+ {
+ sprintf(error_name,"com.redhat.dbus.NotFound");
+ sprintf(error_message,"Not Found");
+ dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
+ TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
+ );
+ return;
+ }
+ }
+ dbus_svc_send_message( dbus, msg, &new_serial );
+}
+
+static void
+dbus_mgr_check_dhcdbd_state( ns_dbus_mgr_t *mgr, dbus_svc_MessageHandle msg )
+{
+ DBUS_SVC dbus = mgr->dbus;
+ char *name_owned = 0L,
+ *old_owner = 0L,
+ *new_owner = 0L;
+
+ if( !dbus_svc_get_args( dbus, msg,
+ TYPE_STRING, &name_owned,
+ TYPE_STRING, &old_owner,
+ TYPE_STRING, &new_owner,
+ TYPE_INVALID
+ )
+ ) return;
+
+ dbus_mgr_log_dbg("NameOwnerChanged: %s %s %s ( %s )", name_owned, old_owner, new_owner, mgr->dhcdbd_name);
+
+ if( (name_owned == 0L) || (new_owner == 0L) || (old_owner == 0L) )
+ return;
+
+ if( strcmp( name_owned, "com.redhat.dhcp" ) == 0 )
+ {
+ if( *new_owner == '\0' )
+ {
+ isc_mem_put(mgr->mctx, mgr->dhcdbd_name, strlen(mgr->dhcdbd_name) + 1);
+ mgr->dhcdbd_name = 0L;
+ dbus_mgr_log_err("D-BUS dhcdbd subscription disabled.");
+ return;
+ }
+ if( (mgr->dhcdbd_name == 0L)
+ ||( strcmp( mgr->dhcdbd_name, new_owner) != 0 )
+ )
+ {
+ if( mgr->dhcdbd_name != 0L )
+ {
+ isc_mem_put(mgr->mctx, mgr->dhcdbd_name, strlen(mgr->dhcdbd_name)+1);
+ mgr->dhcdbd_name = 0L;
+ }
+ mgr->dhcdbd_name = isc_mem_get(mgr->mctx, strlen(new_owner) + 1);
+ if( mgr->dhcdbd_name == 0L )
+ return;
+ strcpy( mgr->dhcdbd_name, new_owner );
+ dbus_mgr_subscribe_to_dhcdbd( mgr );
+ }
+ }else
+ if( ( mgr->dhcdbd_name != 0L )
+ && ( strcmp(mgr->dhcdbd_name, name_owned) == 0L )
+ && ( *new_owner == '\0' )
+ )
+ {
+ isc_mem_put(mgr->mctx, mgr->dhcdbd_name, strlen(mgr->dhcdbd_name));
+ mgr->dhcdbd_name = 0L;
+ dbus_mgr_log_err("D-BUS dhcdbd subscription disabled.");
+ }
+}
+
+static int dbus_mgr_dhc_if_comparator( const void *p1, const void *p2 )
+{
+ return( strcmp( ((const DHC_IF*)p1)->if_name, ((const DHC_IF*)p2)->if_name) );
+}
+
+static
+dns_name_t *dbus_mgr_if_reverse_ip_name
+( ns_dbus_mgr_t *mgr,
+ struct in_addr ip_address,
+ struct in_addr subnet_mask
+)
+{
+ dns_name_t *dns_name =0L;
+ dns_fixedname_t *fixedname=0L;
+ char name [ DNS_NAME_FORMATSIZE ], *p;
+ uint32_t ip = (ntohl(ip_address.s_addr) & ntohl(subnet_mask.s_addr)), i;
+ isc_buffer_t buffer;
+ isc_result_t result;
+
+ if( (ip == 0) || (ip == 0xffffffff) )
+ return 0L;
+
+ for(i = 8, p = name; (i < 32); i += 8)
+ if( ip & ( 0xff << i ) )
+ p += sprintf(p, "%u.", (((ip & ( 0xff << i )) >> i ) & 0xff) );
+
+ if( p > name )
+ {
+ p += sprintf(p, "in-addr.arpa");
+ isc_buffer_init( &buffer, name, p - name );
+ isc_buffer_add(&buffer, p - name);
+
+ fixedname = isc_mem_get( mgr->mctx, sizeof( dns_fixedname_t ));
+
+ dns_fixedname_init(fixedname);
+
+ dns_name = dns_fixedname_name(fixedname);
+
+ result= dns_name_fromtext
+ ( dns_name, &buffer, dns_rootname, ISC_FALSE, NULL
+ );
+
+ ISC_LINK_INIT(dns_name, link);
+ if( result == ISC_R_SUCCESS )
+ return dns_name;
+ }
+ return 0L;
+}
+
+static void
+dbus_mgr_free_dhc( void *p )
+{
+ DHC_IF *d_if = p;
+ dns_name_t *dn;
+ isc_sockaddr_t *sa;
+
+ isc_mem_put( ns_g_mctx, d_if->if_name, strlen(d_if->if_name) + 1);
+ for( sa = ISC_LIST_HEAD( d_if->dns );
+ sa != NULL;
+ sa = ISC_LIST_HEAD( d_if->dns )
+ )
+ {
+ if( ISC_LINK_LINKED( sa, link ) )
+ ISC_LIST_UNLINK( d_if->dns, sa, link );
+ isc_mem_put(ns_g_mctx, sa, sizeof(isc_sockaddr_t));
+ }
+ for( dn = ISC_LIST_HEAD( d_if->dn );
+ dn != NULL;
+ dn = ISC_LIST_HEAD( d_if->dn )
+ )
+ {
+ if( ISC_LINK_LINKED( dn, link ) )
+ ISC_LIST_UNLINK( d_if->dn, dn, link );
+ isc_mem_put( ns_g_mctx, dn, sizeof( dns_fixedname_t ) );
+ }
+ isc_mem_put( ns_g_mctx, d_if, sizeof(DHC_IF));
+}
+
+static void
+dbus_mgr_handle_dhcdbd_message
+(
+ ns_dbus_mgr_t *mgr,
+ const char *path,
+ const char *member,
+ dbus_svc_MessageHandle msg
+)
+{
+ DBUS_SVC dbus = mgr->dbus;
+ DHC_IF *d_if, *const*d_ifpp, dif;
+ DHC_State dhc_state;
+ char *if_name, *opt_name, error_name[1024]="", error_message[1024]="";
+ uint8_t *value=0L;
+ uint32_t length;
+ isc_result_t result;
+ isc_sockaddr_t *sa = 0L;
+ dns_name_t *dn = 0L;
+ struct in_addr *ip;
+ in_port_t port;
+ char dnBuf[ DNS_NAME_FORMATSIZE ];
+ isc_buffer_t buffer;
+ DBusMgrInitialFwdr *ifwdr, *const*ifwdpp, ifwd;
+ ISC_LIST(DBusMgrInitialFwdr) ifwdrList;
+ DNSNameList nameList;
+ dbus_mgr_log_dbg("Got dhcdbd message: %s %s %p", path, member, msg );
+
+ if( ( if_name = strrchr(path,'/') ) == 0L )
+ {
+ dbus_mgr_log_err("bad path in dhcdbd message:", path);
+ return;
+ }
+
+ ++if_name;
+ dif.if_name = if_name;
+
+ if( ((d_ifpp=tfind( &dif, &(mgr->dhc_if), dbus_mgr_dhc_if_comparator)) == 0L)
+ ||((d_if = *d_ifpp) == 0L)
+ )
+ {
+ d_if = isc_mem_get( mgr->mctx, sizeof(DHC_IF));
+ if( d_if == 0L )
+ {
+ dbus_mgr_log_err("out of memory");
+ return;
+ }
+ memset(d_if, '\0', sizeof(DHC_IF));
+ if((d_if->if_name = isc_mem_get( mgr->mctx, strlen(if_name) + 1)) == 0L)
+ {
+ dbus_mgr_log_err("out of memory");
+ return;
+ }
+ strcpy(d_if->if_name, if_name);
+ d_if->dhc_state = DHC_INVALID;
+ d_if->previous_state = DHC_INVALID;
+ ISC_LIST_INIT( d_if->dn );
+ ISC_LIST_INIT( d_if->dns );
+ if( tsearch( d_if, &(mgr->dhc_if), dbus_mgr_dhc_if_comparator) == 0L )
+ {
+ dbus_mgr_log_err("out of memory");
+ return;
+ }
+ }
+
+ if( strcmp(member, "reason") == 0 )
+ {
+ if( (!dbus_svc_get_args( dbus, msg,
+ TYPE_STRING, &opt_name,
+ TYPE_ARRAY, TYPE_BYTE, &value, &length,
+ TYPE_INVALID
+ )
+ )
+ ||( value == 0L)
+ ||( length != sizeof(uint32_t))
+ ||( *((uint32_t*)value) > DHC_END_OPTIONS)
+ )
+ {
+ dbus_mgr_log_err("Invalid DHC reason value received from dhcdbd");
+ return;
+ }
+ dhc_state = (DHC_State) *((uint32_t*)value);
+ dbus_mgr_log_dbg("reason: %d %d %d", dhc_state, d_if->dhc_state, d_if->previous_state);
+ switch( dhc_state )
+ {
+
+ case DHC_END_OPTIONS:
+ switch( d_if->dhc_state )
+ {
+ case DHC_END_OPTIONS:
+ break;
+
+ case DHC_RENEW:
+ case DHC_REBIND:
+ if( ( d_if->previous_state != DHC_INVALID )
+ &&( d_if->previous_state != DHC_RELEASE )
+ ) break;
+ /* DHC_RENEW means the same lease parameters were obtained.
+ * Only do configuration if we started up with existing dhclient
+ * which has now renewed - else we are already configured correctly.
+ */
+ dbus_mgr_log_err("D-BUS: existing dhclient for interface %s RENEWed lease", if_name);
+
+ case DHC_REBOOT:
+ case DHC_BOUND:
+ d_if->previous_state = d_if->dhc_state;
+ d_if->dhc_state = DHC_BOUND;
+ if( (dn = dbus_mgr_if_reverse_ip_name(mgr, d_if->ip, d_if->subnet_mask )) != 0L )
+ {
+ ISC_LIST_APPEND(d_if->dn, dn, link );
+ }
+ if( ( ISC_LIST_HEAD( d_if->dn ) != NULL )
+ &&( ISC_LIST_HEAD( d_if->dns ) != NULL )
+ )
+ {
+ dbus_mgr_log_err("D-BUS: dhclient for interface %s acquired new lease - creating forwarders.",
+ if_name
+ );
+ result = dbus_mgr_set_forwarders( mgr, &(d_if->dn), &(d_if->dns), dns_fwdpolicy_only );
+ if( result != ISC_R_SUCCESS )
+ {
+ dbus_mgr_log_err("D-BUS: forwarder configuration failed: %s", isc_result_totext(result));
+ }
+ }
+ break;
+
+ case DHC_STOP:
+ case DHC_TIMEOUT:
+ case DHC_FAIL:
+ case DHC_EXPIRE:
+ case DHC_RELEASE:
+ d_if->previous_state = d_if->dhc_state;
+ d_if->dhc_state = DHC_RELEASE;
+ if( ISC_LIST_HEAD( d_if->dn ) != NULL )
+ {
+ dbus_mgr_log_err("D-BUS: dhclient for interface %s released lease - removing forwarders.",
+ if_name);
+ for( sa = ISC_LIST_HEAD( d_if->dns );
+ sa != 0L;
+ sa = ISC_LIST_HEAD( d_if->dns )
+ )
+ {
+ if( ISC_LINK_LINKED( sa, link ) )
+ ISC_LIST_UNLINK( d_if->dns, sa, link );
+ isc_mem_put( mgr->mctx, sa, sizeof(isc_sockaddr_t));
+ }
+ ISC_LIST_INIT( d_if->dns );
+ ISC_LIST_INIT( ifwdrList );
+
+ for( dn = ISC_LIST_HEAD( d_if->dn );
+ dn != 0L;
+ dn = ISC_LIST_NEXT( dn, link )
+ )
+ {
+ dns_name_init( &(ifwd.dn), NULL );
+ isc_buffer_init( &buffer, dnBuf, DNS_NAME_FORMATSIZE);
+ dns_name_setbuffer( &(ifwd.dn), &buffer);
+ dns_name_copy(dn, &(ifwd.dn), NULL);
+ if( ((ifwdpp = tfind(&ifwd, &(mgr->ifwdt), dbus_mgr_ifwdr_comparator)) != 0L )
+ &&((ifwdr = *ifwdpp) != 0L)
+ )
+ {
+ ISC_LIST_APPEND( ifwdrList, ifwdr, link );
+ }
+ }
+
+ result = dbus_mgr_set_forwarders( mgr, &(d_if->dn), &(d_if->dns), dns_fwdpolicy_none );
+ if( result != ISC_R_SUCCESS )
+ {
+ dbus_mgr_log_err("D-BUS: removal of forwarders failed: %s", isc_result_totext(result));
+ }
+
+ for( dn = ISC_LIST_HEAD( d_if->dn );
+ dn != 0L;
+ dn = ISC_LIST_HEAD( d_if->dn )
+ )
+ {
+ if( ISC_LINK_LINKED( dn, link ) )
+ ISC_LIST_UNLINK( d_if->dn, dn, link );
+ isc_mem_put( mgr->mctx, dn, sizeof( dns_fixedname_t ) );
+ }
+ ISC_LIST_INIT( d_if->dn );
+
+ for( ifwdr = ISC_LIST_HEAD( ifwdrList );
+ ifwdr != 0L;
+ ifwdr = ISC_LIST_HEAD( ifwdrList )
+ )
+ {
+ if( ISC_LINK_LINKED( ifwdr, link ) )
+ ISC_LIST_UNLINK( ifwdrList, ifwdr, link );
+ ISC_LINK_INIT(ifwdr, link);
+ ISC_LIST_INIT(nameList);
+ ISC_LINK_INIT(&(ifwdr->dn), link);
+ ISC_LIST_APPEND( nameList, &(ifwdr->dn), link );
+ result = dbus_mgr_set_forwarders( mgr, &nameList,
+ &(ifwdr->sa),
+ ifwdr->fwdpolicy
+ );
+ if( result != ISC_R_SUCCESS )
+ {
+ dbus_mgr_log_err("D-BUS: restore of forwarders failed: %s", isc_result_totext(result));
+ }
+ }
+ }
+
+ case DHC_ABEND:
+ case DHC_END:
+ case DHC_NBI:
+ case DHC_PREINIT:
+ case DHC_MEDIUM:
+ case DHC_START:
+ case DHC_INVALID:
+ default:
+ break;
+ }
+ break;
+
+ case DHC_BOUND:
+ case DHC_REBOOT:
+ case DHC_REBIND:
+ case DHC_RENEW:
+ case DHC_STOP:
+ case DHC_TIMEOUT:
+ case DHC_FAIL:
+ case DHC_EXPIRE:
+ case DHC_RELEASE:
+ d_if->previous_state = d_if->dhc_state;
+ d_if->dhc_state = dhc_state;
+
+ case DHC_ABEND:
+ case DHC_END:
+ case DHC_NBI:
+ case DHC_PREINIT:
+ case DHC_MEDIUM:
+ case DHC_START:
+ case DHC_INVALID:
+ default:
+ break;
+ }
+ }else
+ if( strcmp( member, "domain_name" ) == 0 )
+ {
+ if( (!dbus_svc_get_args( dbus, msg,
+ TYPE_STRING, &opt_name,
+ TYPE_ARRAY, TYPE_BYTE, &value, &length,
+ TYPE_INVALID
+ )
+ )
+ ||( value == 0L)
+ ||( length == 0)
+ )
+ {
+ dbus_mgr_log_err("Invalid domain_name value received from dhcdbd");
+ return;
+ }
+ dbus_mgr_log_dbg("domain-name %s", (char*)value);
+ dbus_mgr_get_name_list( mgr, (char*)value, &(d_if->dn), error_name, error_message );
+ if( ( error_message[0] != '\0' ) || (ISC_LIST_HEAD(d_if->dn) == 0L ))
+ {
+ dbus_mgr_log_err("Bad domain_name value: %s", error_message );
+ }
+ }else
+ if( strcmp( member, "domain_name_servers") == 0 )
+ {
+ if( (!dbus_svc_get_args( dbus, msg,
+ TYPE_STRING, &opt_name,
+ TYPE_ARRAY, TYPE_BYTE, &value, &length,
+ TYPE_INVALID
+ )
+ )
+ ||( value == 0L)
+ ||( length == 0)
+ )
+ {
+ dbus_mgr_log_err("Invalid domain_name_servers value received from dhcdbd");
+ return;
+ }
+ for(ip = (struct in_addr*) value; ip < ((struct in_addr*)(value + length)); ip++)
+ {
+ dbus_mgr_log_dbg("domain-name-servers: %s", inet_ntop(AF_INET, value, error_name, 16));
+ sa = isc_mem_get(mgr->mctx, sizeof(isc_sockaddr_t));
+ memset(sa, '\0', sizeof(isc_sockaddr_t));
+ sa->type.sin.sin_addr = *ip;
+ sa->type.sa.sa_family = AF_INET;
+ sa->length = sizeof(sa->type.sin);
+ result = ns_config_getport(ns_g_config, &(port) );
+ if( result != ISC_R_SUCCESS )
+ port = 53;
+ sa->type.sin.sin_port = htons( port );
+ ISC_LIST_APPEND(d_if->dns, sa, link);
+ }
+ }else
+ if( strcmp(member, "ip_address") == 0)
+ {
+ if( (!dbus_svc_get_args( dbus, msg,
+ TYPE_STRING, &opt_name,
+ TYPE_ARRAY, TYPE_BYTE, &value, &length,
+ TYPE_INVALID
+ )
+ )
+ ||( value == 0L)
+ ||( length != sizeof(struct in_addr) )
+ )
+ {
+ dbus_mgr_log_err("Invalid ip_address value received from dhcdbd");
+ return;
+ }
+ dbus_mgr_log_dbg("ip-address: %s", inet_ntop(AF_INET, value, error_name, 16));
+ d_if->ip = *((struct in_addr*)value);
+
+ }else
+ if( strcmp(member, "subnet_mask") == 0 )
+ {
+ if( (!dbus_svc_get_args( dbus, msg,
+ TYPE_STRING, &opt_name,
+ TYPE_ARRAY, TYPE_BYTE, &value, &length,
+ TYPE_INVALID
+ )
+ )
+ ||( value == 0L)
+ ||( length != sizeof(struct in_addr) )
+ )
+ {
+ dbus_mgr_log_err("Invalid subnet_mask value received from dhcdbd");
+ return;
+ }
+ dbus_mgr_log_dbg("subnet-mask: %s", inet_ntop(AF_INET, value, error_name, 16));
+ d_if->subnet_mask = *((struct in_addr*)value);
+ }
+}
+
+static
+dbus_svc_HandlerResult
+dbus_mgr_message_handler
+(
+ DBusMsgHandlerArgs
+)
+{
+ char error_name[1024], error_message[1024];
+ ns_dbus_mgr_t *mgr = object;
+ uint32_t new_serial;
+
+ if_suffix = prefix = suffix = prefixObject = 0L;
+
+ dbus_mgr_log_dbg("D-BUS message: %u %u %u %s %s %s %s %s %s",
+ type, reply_expected, serial, destination, path, member, interface, sender, signature
+ );
+
+ if ( ( type == SIGNAL )
+ &&( strcmp(path,"/org/freedesktop/DBus/Local") == 0 )
+ )
+ {
+ if( strcmp(member,"Disconnected") == 0 )
+ dbus_mgr_dbus_shutdown_handler( mgr );
+ }else
+ if( ( type == SIGNAL )
+ &&( strcmp(path,"/org/freedesktop/DBus") == 0 )
+ &&(strcmp(member,"NameOwnerChanged") == 0)
+ &&(strcmp(signature, "sss") == 0)
+ )
+ {
+ dbus_mgr_check_dhcdbd_state( mgr, msg );
+ }else
+ if( ( type == SIGNAL )
+ &&( (sender != 0L) && (mgr->dhcdbd_name != 0L) && (strcmp(sender,mgr->dhcdbd_name) == 0))
+ &&( strcmp(interface,"com.redhat.dhcp.subscribe.binary") == 0 )
+ )
+ {
+ dbus_mgr_handle_dhcdbd_message( mgr, path, member, msg );
+ }else
+ if( (type == CALL)
+ &&( strcmp(destination, DBUSMGR_DESTINATION)==0)
+ &&( strcmp(path, DBUSMGR_OBJECT_PATH)==0)
+ )
+ {
+ if( strcmp(member, "SetForwarders") == 0 )
+ dbus_mgr_handle_set_forwarders
+ ( mgr, dbus, reply_expected, serial, path, member, interface, sender, msg );
+ else
+ if( strcmp(member, "GetForwarders") == 0 )
+ {
+ if( *signature != '\0' )
+ dbus_mgr_handle_get_forwarders
+ ( dbus, reply_expected, serial, path, member, interface, sender, msg );
+ else
+ dbus_mgr_handle_list_forwarders
+ ( dbus, reply_expected, serial, path, member, interface, sender, msg );
+ }else
+ if( reply_expected )
+ {
+ sprintf(error_name, "InvalidOperation");
+ sprintf(error_message, "Unrecognized path / interface / member");
+ dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
+ TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
+ );
+ }
+ }
+ return HANDLED;
+}
+
+static void
+dbus_mgr_read_watch_activated(isc_task_t *t, isc_event_t *ev)
+{
+ DBusMgrSocket *sfd = (DBusMgrSocket*)(ev->ev_arg);
+ t = t;
+ isc_mem_put(sfd->mgr->mctx, ev, ev->ev_size);
+ dbus_mgr_log_dbg("watch %d READ",sfd->fd);
+ isc_socket_fd_handle_reads( sfd->sock, sfd->ser );
+ dbus_svc_handle_watch( sfd->mgr->dbus, sfd->fd, WATCH_ENABLE | WATCH_READ );
+}
+
+static void
+dbus_mgr_write_watch_activated(isc_task_t *t, isc_event_t *ev)
+{
+ DBusMgrSocket *sfd = (DBusMgrSocket*)(ev->ev_arg);
+ t = t;
+ isc_mem_put(sfd->mgr->mctx, ev, ev->ev_size);
+ dbus_mgr_log_dbg("watch %d WRITE",sfd->fd);
+ isc_socket_fd_handle_writes( sfd->sock, sfd->ser );
+ dbus_svc_handle_watch( sfd->mgr->dbus, sfd->fd, WATCH_ENABLE | WATCH_WRITE );
+}
+
+static void
+dbus_mgr_watches_selected(isc_task_t *t, isc_event_t *ev)
+{
+ ns_dbus_mgr_t *mgr = (ns_dbus_mgr_t*)(ev->ev_arg);
+ t = t;
+ isc_mem_put(mgr->mctx, ev, ev->ev_size);
+ if( ( mgr->dbus == 0L ) || (mgr->sockets == 0L))
+ {
+ return;
+ }
+ dbus_mgr_log_dbg("watches selected");
+ dbus_svc_dispatch( mgr->dbus );
+ dbus_mgr_log_dbg("dispatch complete");
+}
+
+static int dbus_mgr_socket_comparator( const void *p1, const void *p2 )
+{
+ return( ( ((const DBusMgrSocket*)p1)->fd
+ == ((const DBusMgrSocket*)p2)->fd
+ ) ? 0
+ : ( ((const DBusMgrSocket*)p1)->fd
+ > ((const DBusMgrSocket*)p2)->fd
+ ) ? 1
+ : -1
+ );
+}
+
+static void
+dbus_mgr_watch_handler( int fd, dbus_svc_WatchFlags flags, void *mgrp )
+{
+ ns_dbus_mgr_t *mgr = mgrp;
+ DBusMgrSocket sockFd, *sfd=0L, *const*spp=0L;
+ isc_result_t result=ISC_R_SUCCESS;
+ isc_socketevent_t *sev;
+ isc_event_t *pev[1];
+
+ if(mgr == 0L)
+ return;
+
+ if( (flags & 7) == WATCH_ERROR )
+ return;
+
+ sockFd.fd = fd;
+
+ dbus_mgr_log_dbg("watch handler: fd %d %d", fd, flags);
+
+ if( ((spp = tfind( &sockFd, &(mgr->sockets), dbus_mgr_socket_comparator) ) == 0L )
+ ||((sfd = *spp) == 0L )
+ )
+ {
+ if( ( flags & WATCH_ENABLE ) == 0 )
+ return;
+
+ sfd = isc_mem_get(mgr->mctx, sizeof(DBusMgrSocket));
+ if( sfd == 0L )
+ {
+ dbus_mgr_log_err("dbus_mgr: out of memory" );
+ return;
+ }
+ sfd->fd = fd;
+ sfd->mgr = mgr;
+ sfd->ser = sfd->sew = sfd->sel = 0L;
+
+ if( tsearch(sfd, &(mgr->sockets), dbus_mgr_socket_comparator) == 0L )
+ {
+ dbus_mgr_log_err("dbus_mgr: out of memory" );
+ isc_mem_put(mgr->mctx, sfd, sizeof(DBusMgrSocket));
+ return;
+ }
+ sfd->sock = 0L;
+ result = isc_socket_create( mgr->socketmgr, fd, isc_sockettype_fd, &(sfd->sock) );
+ if( result != ISC_R_SUCCESS )
+ {
+ dbus_mgr_log_err("dbus_mgr: isc_socket_create failed: %s",
+ isc_result_totext(result)
+ );
+ tdelete(sfd, &(mgr->sockets), dbus_mgr_socket_comparator);
+ isc_mem_put(mgr->mctx, sfd, sizeof(DBusMgrSocket));
+ return;
+ }
+ }
+
+ if( (flags & WATCH_ENABLE) == WATCH_ENABLE )
+ {
+ if( (flags & WATCH_READ) == WATCH_READ )
+ {
+ if( sfd->ser == 0L )
+ {
+ sfd->ser = (isc_socketevent_t *)
+ isc_event_allocate
+ (
+ mgr->mctx, mgr->task,
+ ISC_SOCKEVENT_READ_READY,
+ dbus_mgr_read_watch_activated,
+ sfd,
+ sizeof(isc_socketevent_t)
+ );
+
+ if( sfd->ser == 0L )
+ {
+ dbus_mgr_log_err("dbus_mgr: out of memory" );
+ tdelete(sfd, &(mgr->sockets), dbus_mgr_socket_comparator);
+ isc_mem_put(mgr->mctx, sfd, sizeof(DBusMgrSocket));
+ return;
+ }
+
+ sev = isc_socket_fd_handle_reads(sfd->sock, sfd->ser );
+
+ }else
+ {
+ sev = isc_socket_fd_handle_reads(sfd->sock, sfd->ser );
+ }
+ }
+ if( (flags & WATCH_WRITE) == WATCH_WRITE )
+ {
+ if( sfd->sew == 0L )
+ {
+ sfd->sew = (isc_socketevent_t *)
+ isc_event_allocate
+ (
+ mgr->mctx, mgr->task,
+ ISC_SOCKEVENT_WRITE_READY,
+ dbus_mgr_write_watch_activated,
+ sfd,
+ sizeof(isc_socketevent_t)
+ );
+ if( sfd->sew == 0L )
+ {
+ dbus_mgr_log_err("dbus_mgr: out of memory" );
+ tdelete(sfd, &(mgr->sockets), dbus_mgr_socket_comparator);
+ isc_mem_put(mgr->mctx, sfd, sizeof(DBusMgrSocket));
+ return;
+ }
+
+ sev = isc_socket_fd_handle_writes(sfd->sock, sfd->sew );
+
+ }else
+ {
+ sev = isc_socket_fd_handle_writes(sfd->sock, sfd->sew );
+ }
+ }
+ if( (sfd->ser != 0L) || (sfd->sew != 0L) )
+ {
+ if( sfd->sel == 0L )
+ {
+ sfd->sel = (isc_socketevent_t *)
+ isc_event_allocate
+ (
+ mgr->mctx, mgr->task,
+ ISC_SOCKEVENT_SELECTED,
+ dbus_mgr_watches_selected,
+ mgr,
+ sizeof(isc_socketevent_t)
+ );
+ if( sfd->sel == 0L )
+ {
+ dbus_mgr_log_err("dbus_mgr: out of memory" );
+ tdelete(sfd, &(mgr->sockets), dbus_mgr_socket_comparator);
+ isc_mem_put(mgr->mctx, sfd, sizeof(DBusMgrSocket));
+ return;
+ }
+
+ sev = isc_socket_fd_handle_selected(sfd->sock, sfd->sel );
+
+ }else
+ {
+ sev = isc_socket_fd_handle_selected(sfd->sock, sfd->sel);
+ }
+ }
+ }else
+ {
+ dbus_mgr_log_dbg("watch %d disabled",fd);
+ if(flags & WATCH_READ)
+ {
+ sev = isc_socket_fd_handle_reads( sfd->sock, 0L );
+ if( sev != 0L )
+ {
+ pev[0]=(isc_event_t*)sev;
+ isc_event_free(pev);
+ }
+ sfd->ser = 0L;
+ }
+
+ if( flags & WATCH_WRITE )
+ {
+ sev = isc_socket_fd_handle_writes( sfd->sock, 0L );
+ if( sev != 0L )
+ {
+ pev[0]=(isc_event_t*)sev;
+ isc_event_free(pev);
+ }
+ sfd->sew = 0L;
+ }
+
+ if( (sfd->ser == 0L) && (sfd->sew == 0L) )
+ {
+ sev = isc_socket_fd_handle_selected( sfd->sock, 0L );
+ if( sev != 0L )
+ {
+ pev[0]=(isc_event_t*)sev;
+ isc_event_free(pev);
+ }
+ sfd->sel = 0L;
+
+ tdelete(sfd, &(mgr->sockets), dbus_mgr_socket_comparator);
+
+ isc_mem_put(mgr->mctx, sfd, sizeof(DBusMgrSocket));
+ }
+ }
+}
+
+static
+void dbus_mgr_close_socket( const void *p, const VISIT which, const int level)
+{
+ DBusMgrSocket *const*spp=p, *sfd;
+ isc_event_t *ev ;
+ int i = level ? 0 :1;
+ i &= i;
+
+ if( (spp==0L) || ((sfd = *spp)==0L)
+ ||((which != leaf) && (which != postorder))
+ ) return;
+
+ if( sfd->ser != 0L )
+ {
+ ev = (isc_event_t *)isc_socket_fd_handle_reads(sfd->sock, 0);
+ if( ev != 0L )
+ isc_event_free((isc_event_t **)&ev);
+ sfd->ser = 0L;
+ }
+
+ if( sfd->sew != 0L )
+ {
+ ev = (isc_event_t *)isc_socket_fd_handle_writes(sfd->sock, 0);
+ if( ev != 0L )
+ isc_event_free((isc_event_t **)&ev);
+ sfd->sew = 0L;
+ }
+
+ if( sfd->sel != 0L )
+ {
+ ev = (isc_event_t *)isc_socket_fd_handle_selected(sfd->sock, 0);
+ if( ev != 0L )
+ isc_event_free((isc_event_t **)&ev);
+ sfd->sel = 0L;
+ dbus_mgr_log_dbg("CLOSED socket %d", sfd->fd);
+ }
+}
+
+static
+void dbus_mgr_destroy_socket( void *p )
+{
+ DBusMgrSocket *sfd = p;
+
+ isc_mem_put( sfd->mgr->mctx, sfd, sizeof(DBusMgrSocket) );
+}