1/* dbus_mgr.c
2 *
3 *  named module to provide dynamic forwarding zones in
4 *  response to D-BUS dhcp events or commands.
5 *
6 *  Copyright(C) Jason Vas Dias, Red Hat Inc., 2005
7 *  Modified by Adam Tkac, Red Hat Inc., 2007
8 *
9 *  This program is free software; you can redistribute it and/or modify
10 *  it under the terms of the GNU General Public License as published by
11 *  the Free Software Foundation at
12 *           http://www.fsf.org/licensing/licenses/gpl.txt
13 *  and included in this software distribution as the "LICENSE" file.
14 *
15 *  This program is distributed in the hope that it will be useful,
16 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 *  GNU General Public License for more details.
19 */
20#include <config.h>
21#include <isc/types.h>
22#include <isc/net.h>
23#include <isc/mem.h>
24#include <isc/magic.h>
25#include <isc/list.h>
26#include <isc/task.h>
27#include <isc/event.h>
28#include <isc/socket.h>
29#include <isc/timer.h>
30#include <isc/netaddr.h>
31#include <isc/sockaddr.h>
32#include <isc/buffer.h>
33#include <isc/log.h>
34
35#include <dns/name.h>
36#include <dns/acl.h>
37#include <dns/fixedname.h>
38#include <dns/view.h>
39#include <dns/forward.h>
40
41#include <named/types.h>
42#include <named/config.h>
43#include <named/server.h>
44#include <named/globals.h>
45#include <named/log.h>
46
47#include <named/dbus_service.h>
48#include <named/dbus_mgr.h>
49
50#include <string.h>
51#include <search.h>
52
53typedef void (*__free_fn_t) (void *__nodep);
54extern void tdestroy (void *__root, __free_fn_t __freefct);
55extern void free(void*);
56
57#ifdef ISC_USE_INTERNAL_MALLOC
58#  if  ISC_USE_INTERNAL_MALLOC
59#      error dbus_mgr cannot be used if ISC_USE_INTERNAL_MALLOC==1
60#  endif
61#endif
62
63#define DBUSMGR_DESTINATION  "com.redhat.named"
64#define DBUSMGR_OBJECT_PATH "/com/redhat/named"
65#define DBUSMGR_INTERFACE    "com.redhat.named"
66
67#define DBUSMGR_MAGIC	ISC_MAGIC('D', 'B', 'U', 'S')
68
69struct ns_dbus_mgr
70{
71    unsigned int        magic;
72    isc_mem_t         *	mctx;		/* Memory context. */
73    isc_taskmgr_t     * taskmgr;	/* Task manager.   */
74    isc_socketmgr_t   *	socketmgr;	/* Socket manager. */
75    isc_timermgr_t    *	timermgr;	/* Timer manager.  */
76    isc_task_t        * task;           /* task            */
77    isc_timer_t       * timer;          /* dbus_init retry */
78    void              * sockets;        /* dbus fd tree    */
79    void              * dhc_if;         /* dhcp interface tree */
80    void              * ifwdt;          /* initial forwarder tree */
81    char              * dhcdbd_name;    /* dhcdbd destination  */
82    DBUS_SVC            dbus;	        /* dbus handle */
83};
84
85typedef
86struct dbus_mgr_sock_s
87{
88    int fd;
89    struct ns_dbus_mgr *mgr;
90    isc_socket_t *sock;
91    isc_socketevent_t *ser;
92    isc_socketevent_t *sew;
93    isc_socketevent_t *sel;
94} DBusMgrSocket;
95
96typedef
97enum dhc_state_e
98{
99   DHC_NBI,         	/* no broadcast interfaces found */
100   DHC_PREINIT, 	/* configuration started   */
101   DHC_BOUND, 		/* lease obtained          */
102   DHC_RENEW, 		/* lease renewed           */
103   DHC_REBOOT,	        /* have valid lease, but now obtained a different one */
104   DHC_REBIND, 		/* new, different lease */
105   DHC_STOP,  		/* remove old lease */
106   DHC_MEDIUM, 		/* media selection begun */
107   DHC_TIMEOUT, 	/* timed out contacting DHCP server */
108   DHC_FAIL, 		/* all attempts to contact server timed out, sleeping */
109   DHC_EXPIRE, 		/* lease has expired, renewing */
110   DHC_RELEASE, 	/* releasing lease */
111   DHC_START,           /* sent when dhclient started OK */
112   DHC_ABEND,  		/* dhclient exited abnormally    */
113   DHC_END, 		/* dhclient exited normally      */
114   DHC_END_OPTIONS,     /* last option in subscription sent */
115   DHC_INVALID=255
116} DHC_State;
117
118typedef ISC_LIST(dns_name_t) DNSNameList;
119
120typedef ISC_LIST(isc_sockaddr_t) SockAddrList;
121
122typedef struct dbm_fwdr_s
123{
124    dns_fwdpolicy_t fwdpolicy;
125    dns_name_t       dn;
126    SockAddrList     sa;
127    ISC_LINK( struct dbm_fwdr_s ) link;
128} DBusMgrInitialFwdr;
129
130typedef
131struct dhc_if_s
132{
133    char           *if_name;
134    DHC_State      dhc_state;
135    DHC_State      previous_state;
136    struct in_addr ip;
137    struct in_addr subnet_mask;
138    DNSNameList    dn;
139    SockAddrList   dns;
140} DHC_IF;
141
142static void
143dbus_mgr_watch_handler( int fd, dbus_svc_WatchFlags flags, void *mgrp );
144
145static
146dbus_svc_HandlerResult
147dbus_mgr_message_handler
148(
149    DBusMsgHandlerArgs
150);
151
152static
153void dbus_mgr_close_socket( const void *p, const VISIT which, const int level);
154
155static
156void dbus_mgr_destroy_socket( void *p );
157
158static
159void dbus_mgr_free_dhc( void *p );
160
161static void
162dbus_mgr_watches_selected(isc_task_t *t, isc_event_t *ev);
163
164static isc_result_t
165dbus_mgr_init_dbus(ns_dbus_mgr_t *);
166
167static isc_result_t
168dbus_mgr_record_initial_fwdtable(ns_dbus_mgr_t *);
169
170static
171dns_fwdtable_t *dbus_mgr_get_fwdtable(void);
172
173static void
174dbus_mgr_free_initial_fwdtable(ns_dbus_mgr_t *);
175
176static
177uint8_t dbus_mgr_subscribe_to_dhcdbd( ns_dbus_mgr_t * );
178
179static
180void dbus_mgr_dbus_shutdown_handler ( ns_dbus_mgr_t * );
181
182static
183int dbus_mgr_log_err( const char *fmt, ...)
184{
185    va_list  va;
186    va_start(va, fmt);
187    isc_log_vwrite(ns_g_lctx,
188		   NS_LOGCATEGORY_DBUS,
189		   NS_LOGMODULE_DBUS,
190		   ISC_LOG_NOTICE,
191		   fmt, va
192	          );
193    va_end(va);
194    return 0;
195}
196
197static
198int dbus_mgr_log_dbg( const char *fmt, ...)
199{
200    va_list  va;
201    va_start(va, fmt);
202    isc_log_vwrite(ns_g_lctx,
203		   NS_LOGCATEGORY_DBUS,
204		   NS_LOGMODULE_DBUS,
205		   ISC_LOG_DEBUG(80),
206		   fmt, va
207	          );
208    va_end(va);
209    return 0;
210}
211
212static
213int dbus_mgr_log_info( const char *fmt, ...)
214{
215    va_list  va;
216    va_start(va, fmt);
217    isc_log_vwrite(ns_g_lctx,
218		   NS_LOGCATEGORY_DBUS,
219		   NS_LOGMODULE_DBUS,
220		   ISC_LOG_DEBUG(1),
221		   fmt, va
222	          );
223    va_end(va);
224    return 0;
225}
226
227isc_result_t
228dbus_mgr_create
229(   isc_mem_t *mctx,
230    isc_taskmgr_t *taskmgr,
231    isc_socketmgr_t *socketmgr,
232    isc_timermgr_t *timermgr,
233    ns_dbus_mgr_t **dbus_mgr
234)
235{
236    isc_result_t result;
237    ns_dbus_mgr_t *mgr;
238
239    *dbus_mgr = 0L;
240
241    mgr = isc_mem_get(mctx, sizeof(*mgr));
242    if (mgr == NULL)
243	return (ISC_R_NOMEMORY);
244
245    mgr->magic = DBUSMGR_MAGIC;
246    mgr->mctx = mctx;
247    mgr->taskmgr = taskmgr;
248    mgr->socketmgr = socketmgr;
249    mgr->timermgr = timermgr;
250    mgr->task = 0L;
251    mgr->sockets = 0L;
252    mgr->timer = 0L;
253    mgr->dhc_if = 0L;
254    mgr->ifwdt = 0L;
255    mgr->dhcdbd_name = 0L;
256
257    if( (result = isc_task_create( taskmgr, 100, &(mgr->task)))
258        != ISC_R_SUCCESS
259      )	goto cleanup_mgr;
260
261    isc_task_setname( mgr->task, "dbusmgr", mgr );
262
263    mgr->dbus = 0L;
264
265    if( (result = dbus_mgr_record_initial_fwdtable( mgr ))
266	!= ISC_R_SUCCESS
267      )	goto cleanup_mgr;
268
269    if( (result = dbus_mgr_init_dbus( mgr ))
270	!= ISC_R_SUCCESS
271      )	goto cleanup_mgr;
272
273    *dbus_mgr = mgr;
274
275    return ISC_R_SUCCESS;
276
277 cleanup_mgr:
278    if ( dbus_mgr_get_fwdtable() != NULL)
279	dbus_mgr_free_initial_fwdtable (mgr);
280    if( mgr->task != 0L )
281	isc_task_detach(&(mgr->task));
282    isc_mem_put(mctx, mgr, sizeof(*mgr));
283    return (result);
284}
285
286static isc_result_t
287dbus_mgr_init_dbus(ns_dbus_mgr_t * mgr)
288{
289    char destination[]=DBUSMGR_DESTINATION;
290    isc_result_t result;
291
292    if( mgr->sockets != 0L )
293    {
294	isc_task_purgerange(mgr->task, 0L, ISC_SOCKEVENT_READ_READY, ISC_SOCKEVENT_SELECTED, 0L);
295	twalk(mgr->sockets, dbus_mgr_close_socket);
296	tdestroy(mgr->sockets, dbus_mgr_destroy_socket);
297	mgr->sockets = 0L;
298    }
299
300    if( mgr->dbus != 0L )
301    {
302	dbus_svc_shutdown(mgr->dbus);
303	mgr->dbus = 0L;
304    }
305
306    result = dbus_svc_init(DBUS_PRIVATE_SYSTEM, destination, &mgr->dbus,
307					dbus_mgr_watch_handler, 0L, 0L, mgr);
308
309    if(result != ISC_R_SUCCESS)
310	goto cleanup;
311
312    if( mgr->dbus == 0L )
313    {
314	if( mgr->timer == 0L)
315	{
316	    isc_task_purgerange(mgr->task, 0L, ISC_SOCKEVENT_READ_READY, ISC_SOCKEVENT_SELECTED, 0L);
317	    if( mgr->sockets != 0L )
318	    {
319		twalk(mgr->sockets, dbus_mgr_close_socket);
320		tdestroy(mgr->sockets, dbus_mgr_destroy_socket);
321		mgr->sockets = 0L;
322	    }
323	    dbus_mgr_dbus_shutdown_handler (  mgr );
324	    return ISC_R_SUCCESS;
325	}
326	goto cleanup;
327    }
328
329    if( !dbus_svc_add_filter
330	( mgr->dbus, dbus_mgr_message_handler, mgr, 4,
331	  "type=signal,path=/org/freedesktop/DBus,member=NameOwnerChanged",
332	  "type=signal,path=/org/freedesktop/DBus/Local,member=Disconnected",
333	  "type=signal,interface=com.redhat.dhcp.subscribe.binary",
334	  "type=method_call,destination=com.redhat.named,path=/com/redhat/named"
335	)
336      )
337    {
338	dbus_mgr_log_err( "dbus_svc_add_filter failed" );
339	goto cleanup;
340    }
341
342    if( mgr->timer != 0L )
343    {
344	isc_timer_reset(mgr->timer,
345			isc_timertype_inactive,
346			NULL, NULL, ISC_TRUE
347	               );
348    }
349
350    if( !dbus_mgr_subscribe_to_dhcdbd( mgr ) )
351	dbus_mgr_log_err("D-BUS dhcdbd subscription disabled.");
352
353    dbus_mgr_log_err("D-BUS service enabled.");
354    return ISC_R_SUCCESS;
355
356 cleanup:
357    isc_task_purgerange(mgr->task, 0L, ISC_SOCKEVENT_READ_READY, ISC_SOCKEVENT_SELECTED, 0L);
358    twalk(mgr->sockets, dbus_mgr_close_socket);
359    tdestroy(mgr->sockets, dbus_mgr_destroy_socket);
360    mgr->sockets = 0L;
361    if( mgr->dbus )
362    {
363	dbus_svc_shutdown(mgr->dbus);
364	mgr->dbus = 0L;
365    }
366    return ISC_R_FAILURE;
367}
368
369static
370uint8_t dbus_mgr_subscribe_to_dhcdbd( ns_dbus_mgr_t *mgr )
371{
372    DBUS_SVC dbus = mgr->dbus;
373    char subs[1024], path[1024],
374	dhcdbd_destination[]="com.redhat.dhcp", *ddp[1]={ &(dhcdbd_destination[0]) },
375	*dhcdbd_name=0L;
376    const char *options[] = { "reason", "ip-address", "subnet-mask",
377			      "domain-name", "domain-name-servers"
378                            };
379    dbus_svc_MessageHandle msg;
380    int i, n_opts = 5;
381
382    if( mgr->dhcdbd_name == 0L )
383    {
384	msg = dbus_svc_call
385	      ( dbus,
386		"org.freedesktop.DBus",
387		"/org/freedesktop/DBus",
388		"GetNameOwner",
389		"org.freedesktop.DBus",
390		TYPE_STRING, &ddp,
391		TYPE_INVALID
392	       );
393	if( msg == 0L )
394	    return 0;
395
396	if( !dbus_svc_get_args(dbus, msg,
397			       TYPE_STRING, &(dhcdbd_name),
398			       TYPE_INVALID
399		              )
400	  )	return 0;
401
402	mgr->dhcdbd_name = isc_mem_get(mgr->mctx, strlen(dhcdbd_name) + 1);
403	if( mgr->dhcdbd_name == 0L )
404	    return 0;
405
406	strcpy(mgr->dhcdbd_name, dhcdbd_name);
407
408    }
409
410    sprintf(path,"/com/redhat/dhcp/subscribe");
411    sprintf(subs,"com.redhat.dhcp.binary");
412
413    for(i = 0; i < n_opts; i++)
414    {
415	msg = dbus_svc_call
416	      ( dbus,
417		"com.redhat.dhcp",
418		path,
419		"binary",
420		subs,
421		TYPE_STRING, &(options[i]),
422		TYPE_INVALID
423	      );
424	if(msg == 0L)
425	    return 0;
426	if ( dbus_svc_message_type( msg ) == ERROR )
427	    return 0;
428    }
429    dbus_mgr_log_err("D-BUS dhcdbd subscription enabled.");
430    return 1;
431}
432
433void
434dbus_mgr_shutdown
435(   ns_dbus_mgr_t *mgr
436)
437{
438    if( mgr->timer != 0L )
439	isc_timer_detach(&(mgr->timer));
440    if( mgr->dbus != 0L )
441    {
442	isc_task_purgerange(mgr->task, 0L, ISC_SOCKEVENT_READ_READY, ISC_SOCKEVENT_SELECTED, 0L);
443	if( mgr->sockets != 0L )
444	{
445	    twalk(mgr->sockets, dbus_mgr_close_socket);
446	    tdestroy(mgr->sockets, dbus_mgr_destroy_socket);
447	    mgr->sockets = 0L;
448	}
449	dbus_svc_shutdown(mgr->dbus);
450    }
451    if( mgr->dhc_if != 0L )
452	tdestroy(mgr->dhc_if, dbus_mgr_free_dhc);
453    if( mgr->dhcdbd_name != 0L )
454	isc_mem_put(mgr->mctx, mgr->dhcdbd_name, strlen(mgr->dhcdbd_name) + 1);
455    isc_task_detach(&(mgr->task));
456    dbus_mgr_free_initial_fwdtable(mgr);
457    isc_mem_put(mgr->mctx, mgr, sizeof(ns_dbus_mgr_t));
458}
459
460static
461void dbus_mgr_restart_dbus(isc_task_t *t, isc_event_t *ev)
462{
463    ns_dbus_mgr_t *mgr = (ns_dbus_mgr_t*)(ev->ev_arg) ;
464    t=t;
465    isc_event_free(&ev);
466    dbus_mgr_log_dbg("attempting to connect to D-BUS");
467    dbus_mgr_init_dbus( mgr );
468}
469
470static
471void dbus_mgr_handle_dbus_shutdown_event(isc_task_t *t, isc_event_t *ev)
472{
473    ns_dbus_mgr_t *mgr = ev->ev_arg;
474    isc_time_t     tick={10,0};
475    isc_interval_t tock={10,0};
476    DBUS_SVC dbus = mgr->dbus;
477    t = t;
478
479    mgr->dbus = 0L;
480
481    isc_event_free(&ev);
482
483    if ( dbus != 0L )
484    {
485	isc_task_purgerange(mgr->task, 0L, ISC_SOCKEVENT_READ_READY, ISC_SOCKEVENT_SELECTED, 0L);
486	if( mgr->sockets != 0L )
487	{
488	    twalk(mgr->sockets, dbus_mgr_close_socket);
489	    tdestroy(mgr->sockets, dbus_mgr_destroy_socket);
490	    mgr->sockets = 0L;
491	}
492	dbus_svc_shutdown(dbus);
493    }
494
495    dbus_mgr_log_err( "D-BUS service disabled." );
496
497    if( mgr->timer != 0L )
498    {
499	isc_timer_reset(mgr->timer,
500			isc_timertype_ticker,
501			&tick, &tock, ISC_TRUE
502	               );
503    }else
504    if( isc_timer_create
505	(   mgr->timermgr,
506	    isc_timertype_ticker,
507	    &tick, &tock,
508	    mgr->task,
509	    dbus_mgr_restart_dbus,
510	    mgr,
511	    &(mgr->timer)
512	) != ISC_R_SUCCESS
513      )
514    {
515	dbus_mgr_log_err( "D-BUS service cannot be restored." );
516    }
517}
518
519static
520void dbus_mgr_dbus_shutdown_handler ( ns_dbus_mgr_t *mgr )
521{
522    isc_event_t *dbus_shutdown_event =
523	isc_event_allocate
524	(   mgr->mctx,
525	    mgr->task,
526	    1,
527	    dbus_mgr_handle_dbus_shutdown_event,
528	    mgr,
529	    sizeof(isc_event_t)
530	 );
531    if( dbus_shutdown_event != 0L )
532    {
533	isc_task_purgerange(mgr->task, 0L, ISC_SOCKEVENT_READ_READY, ISC_SOCKEVENT_SELECTED, 0L);
534	isc_task_send( mgr->task, &dbus_shutdown_event );
535    }else
536	dbus_mgr_log_err("unable to allocate dbus shutdown event");
537}
538
539static
540dns_view_t *dbus_mgr_get_localhost_view(void)
541{
542    dns_view_t       *view;
543    isc_netaddr_t    localhost = { AF_INET, { { htonl( ( 127 << 24 ) | 1 ) } }, 0 };
544    int              match;
545
546    for (view = ISC_LIST_HEAD(ns_g_server->viewlist);
547	 view != NULL;
548	 view = ISC_LIST_NEXT(view, link)
549        )
550    {
551	/* return first view matching "localhost" source and dest */
552
553	if(( (view->matchclients != 0L )   /* 0L: accept "any" */
554	   &&(( dns_acl_match( &localhost,
555			     NULL, /* unsigned queries */
556			     view->matchclients,
557		  	     &(ns_g_server->aclenv),
558			     &match,
559			     NULL  /* no match list */
560		            ) != ISC_R_SUCCESS
561	      ) || (match <= 0)
562	     )
563	    )
564	 ||( (view->matchdestinations != 0L )   /* 0L: accept "any" */
565	   &&(( dns_acl_match( &localhost,
566			     NULL, /* unsigned queries */
567			     view->matchdestinations,
568		  	     &(ns_g_server->aclenv),
569			     &match,
570			     NULL  /* no match list */
571		            ) != ISC_R_SUCCESS
572	      ) || (match <= 0)
573	     )
574	    )
575	  ) continue;
576
577	break;
578    }
579    return view;
580}
581
582static
583dns_fwdtable_t *dbus_mgr_get_fwdtable(void)
584{
585    dns_view_t *view = dbus_mgr_get_localhost_view();
586    if( view != 0L )
587	return view->fwdtable;
588    return 0L;
589}
590
591static
592dns_fwdtable_t *dbus_mgr_get_view_and_fwdtable( dns_view_t **viewp )
593{
594    *viewp = dbus_mgr_get_localhost_view();
595    if( *viewp != 0L )
596	return (*viewp)->fwdtable;
597    return 0L;
598}
599
600static int dbus_mgr_ifwdr_comparator( const void *p1, const void *p2 )
601{
602    char  n1buf[ DNS_NAME_FORMATSIZE ]="", *n1p=&(n1buf[0]),
603	  n2buf[ DNS_NAME_FORMATSIZE ]="", *n2p=&(n2buf[0]);
604    dns_name_t *dn1;
605    dns_name_t *dn2;
606    DE_CONST(&(((const DBusMgrInitialFwdr*)p1)->dn), dn1);
607    DE_CONST(&(((const DBusMgrInitialFwdr*)p2)->dn), dn2);
608    dns_name_format(dn1, n1p, DNS_NAME_FORMATSIZE );
609    dns_name_format(dn2, n2p, DNS_NAME_FORMATSIZE );
610    return strcmp(n1buf, n2buf);
611}
612
613static int dbus_mgr_dhc_if_comparator( const void *p1, const void *p2 );
614
615static void dbus_mgr_record_initial_forwarder( dns_name_t *name, dns_forwarders_t *fwdr, void *mp )
616{
617    ns_dbus_mgr_t *mgr = mp;
618    isc_sockaddr_t *sa, *nsa;
619    DBusMgrInitialFwdr *ifwdr;
620
621    if( ISC_LIST_HEAD(fwdr->addrs) == 0L)
622	return;
623
624    if( (ifwdr = isc_mem_get(mgr->mctx, sizeof(DBusMgrInitialFwdr))) == 0L)
625	return;
626
627    ifwdr->fwdpolicy = fwdr->fwdpolicy;
628
629    dns_name_init(&(ifwdr->dn), NULL);
630    if( dns_name_dupwithoffsets(name, mgr->mctx, &(ifwdr->dn)) != ISC_R_SUCCESS )
631	goto namedup_err;
632
633    ISC_LIST_INIT(ifwdr->sa);
634
635    for( sa = ISC_LIST_HEAD(fwdr->addrs);
636	 sa != 0L;
637	 sa = ISC_LIST_NEXT(sa,link)
638       )
639    {
640	nsa = isc_mem_get(mgr->mctx, sizeof(isc_sockaddr_t));
641	if( nsa == 0L )
642	    goto nsa_err;
643	*nsa = *sa;
644	ISC_LINK_INIT(nsa, link);
645	ISC_LIST_APPEND(ifwdr->sa, nsa, link);
646    }
647    ISC_LINK_INIT(ifwdr, link);
648    tsearch( ifwdr, &(mgr->ifwdt), dbus_mgr_ifwdr_comparator);
649
650    return;
651
652nsa_err:
653    while ( (sa = ISC_LIST_HEAD (ifwdr->sa)) != NULL) {
654	ISC_LIST_UNLINK (ifwdr->sa, sa, link);
655	isc_mem_put (mgr->mctx, sa, sizeof (*sa));
656    }
657
658namedup_err:
659    isc_mem_put (mgr->mctx, ifwdr, sizeof (*ifwdr));
660
661    return;
662}
663
664static isc_result_t
665dbus_mgr_record_initial_fwdtable( ns_dbus_mgr_t *mgr )
666{
667    dns_fwdtable_t *fwdtable = dbus_mgr_get_fwdtable();
668
669    if( fwdtable == 0L )
670	return ISC_R_SUCCESS; /* no initial fwdtable */
671    dns_fwdtable_foreach( fwdtable, dbus_mgr_record_initial_forwarder, mgr);
672    return ISC_R_SUCCESS;
673}
674
675static void
676dbus_mgr_free_initial_forwarder( void *p )
677{
678   DBusMgrInitialFwdr *ifwdr = p;
679   isc_sockaddr_t *sa;
680
681   dns_name_free(&(ifwdr->dn), ns_g_mctx);
682   for( sa = ISC_LIST_HEAD( ifwdr->sa );
683	sa != 0L;
684	sa = ISC_LIST_HEAD( ifwdr->sa )
685      )
686   {
687       if( ISC_LINK_LINKED(sa, link) )
688	   ISC_LIST_UNLINK(ifwdr->sa, sa, link);
689       isc_mem_put(ns_g_mctx, sa, sizeof(isc_sockaddr_t));
690   }
691   isc_mem_put(ns_g_mctx, ifwdr, sizeof(DBusMgrInitialFwdr));
692}
693
694static void
695dbus_mgr_free_initial_fwdtable( ns_dbus_mgr_t *mgr )
696{
697    tdestroy(mgr->ifwdt, dbus_mgr_free_initial_forwarder);
698    mgr->ifwdt = 0L;
699}
700
701static void
702dbus_mgr_log_forwarders( const char *pfx, dns_name_t *name, SockAddrList *saList)
703{
704    isc_sockaddr_t   *sa;
705    char nameP[DNS_NAME_FORMATSIZE], addrP[128];
706    int s=0;
707    dns_name_format(name, nameP, DNS_NAME_FORMATSIZE );
708    for( sa = ISC_LIST_HEAD(*saList);
709	 sa != 0L;
710	 sa = ISC_LIST_NEXT(sa,link)
711	)
712    {
713	isc_sockaddr_format(sa, addrP, 128);
714	dbus_mgr_log_info("%s zone %s server %d: %s", pfx, nameP, s++, addrP);
715    }
716}
717
718static
719isc_result_t dbus_mgr_set_forwarders
720(
721    ns_dbus_mgr_t *mgr,
722    DNSNameList *nameList,
723    SockAddrList *saList,
724    dns_fwdpolicy_t fwdpolicy
725)
726{
727    isc_result_t   result = ISC_R_SUCCESS;
728    dns_fwdtable_t *fwdtable;
729    dns_view_t     *view=0L;
730    dns_name_t     *dnsName;
731    isc_sockaddr_t   *sa, *nsa;
732    dns_forwarders_t *fwdr=0L;
733
734    fwdtable = dbus_mgr_get_view_and_fwdtable(&view);
735
736    if( fwdtable == 0L )
737    {
738	if( ISC_LIST_HEAD(*saList) == 0L )
739	    return ISC_R_SUCCESS;/* deletion not required */
740
741	view = dbus_mgr_get_localhost_view();
742	if( view == 0L )
743	    return ISC_R_NOPERM; /* if configuration does not allow localhost clients,
744				  * then we really shouldn't be creating a forwarding table.
745				  */
746	result = isc_task_beginexclusive(mgr->task);
747
748	if( result == ISC_R_SUCCESS )
749	{
750	    result = dns_fwdtable_create( mgr->mctx, &(view->fwdtable) );
751
752	    isc_task_endexclusive(mgr->task);
753
754	    if( result != ISC_R_SUCCESS )
755		return result;
756
757	    if( view->fwdtable == 0L )
758		return ISC_R_NOMEMORY;
759
760	    if( isc_log_getdebuglevel(ns_g_lctx) >= 1 )
761		dbus_mgr_log_info("Created forwarder table.");
762	}
763    }
764
765    for( dnsName = ISC_LIST_HEAD(*nameList);
766	 dnsName != NULL;
767	 dnsName = ISC_LIST_NEXT(dnsName,link)
768	)
769    {
770	fwdr = 0L;
771	if( ( dns_fwdtable_find_exact( fwdtable, dnsName, &fwdr ) != ISC_R_SUCCESS )
772	  ||( fwdr == 0L )
773	  )
774	{
775	    if( ISC_LIST_HEAD( *saList )  == 0L )
776		continue;
777	   /* no forwarders for name - add forwarders */
778
779	    result = isc_task_beginexclusive(mgr->task);
780
781	    if( result == ISC_R_SUCCESS )
782	    {
783		result = dns_fwdtable_add( fwdtable, dnsName,
784					   (isc_sockaddrlist_t*)saList,
785					   fwdpolicy
786					 ) ;
787
788		if( view != 0L )
789		    dns_view_flushcache( view );
790
791		isc_task_endexclusive(mgr->task);
792
793		if( result != ISC_R_SUCCESS )
794		    return result;
795
796		if( isc_log_getdebuglevel(ns_g_lctx) >= 1 )
797		    dbus_mgr_log_forwarders("Created forwarder",dnsName, saList);
798	    }
799	    continue;
800	}
801
802	if( ISC_LIST_HEAD( *saList ) == 0L )
803	{ /* empty forwarders list - delete forwarder entry */
804
805	    if( isc_log_getdebuglevel(ns_g_lctx) >= 1 )
806		dbus_mgr_log_forwarders("Deleting forwarder", dnsName, (SockAddrList*)&(fwdr->addrs));
807
808	    result = isc_task_beginexclusive(mgr->task);
809	    if( result == ISC_R_SUCCESS )
810	    {
811		result = dns_fwdtable_delete( fwdtable, dnsName );
812
813		if( view != 0L )
814		    dns_view_flushcache( view );
815
816		isc_task_endexclusive(mgr->task);
817
818		if( result != ISC_R_SUCCESS )
819		    return result;
820	    }
821	    continue;
822	}
823
824	result = isc_task_beginexclusive(mgr->task);
825
826	if( result == ISC_R_SUCCESS )
827	{
828	    fwdr->fwdpolicy = fwdpolicy;
829
830	    if( isc_log_getdebuglevel(ns_g_lctx) >= 1 )
831		dbus_mgr_log_forwarders("Removing forwarder", dnsName, (SockAddrList*)&(fwdr->addrs));
832
833	    for( sa = ISC_LIST_HEAD(fwdr->addrs);
834		 sa != 0L ;
835		 sa = ISC_LIST_HEAD(fwdr->addrs)
836	       )
837	    {
838		if( ISC_LINK_LINKED(sa, link) )
839		    ISC_LIST_UNLINK(fwdr->addrs, sa, link);
840		isc_mem_put(mgr->mctx, sa, sizeof(isc_sockaddr_t));
841	    }
842
843	    ISC_LIST_INIT( fwdr->addrs );
844
845	    for( sa = ISC_LIST_HEAD(*saList);
846		 sa != 0L;
847		 sa = ISC_LIST_NEXT(sa,link)
848	       )
849	    {
850		nsa = isc_mem_get(mgr->mctx, sizeof(isc_sockaddr_t));
851		if( nsa == 0L )
852		{
853		    result = ISC_R_NOMEMORY;
854		    break;
855		}
856		*nsa = *sa;
857		ISC_LINK_INIT( nsa, link );
858		ISC_LIST_APPEND( fwdr->addrs, nsa, link );
859	    }
860
861	    if( view != 0L )
862		dns_view_flushcache( view );
863
864	    isc_task_endexclusive(mgr->task);
865
866	    if( isc_log_getdebuglevel(ns_g_lctx) >= 1 )
867		dbus_mgr_log_forwarders("Added forwarder", dnsName, (SockAddrList*)&(fwdr->addrs));
868
869	}else
870	    return result;
871
872    }
873    return (result);
874}
875
876static void
877dbus_mgr_get_name_list
878(
879    ns_dbus_mgr_t *mgr,
880    char *domains,
881    DNSNameList *nameList,
882    char *error_name,
883    char *error_message
884)
885{
886    char *name, *endName, *endp;
887    dns_fixedname_t *fixedname;
888    dns_name_t      *dnsName;
889    isc_buffer_t     buffer;
890    isc_result_t     result;
891    uint32_t total_length;
892
893    total_length = strlen(domains);
894    endp = domains + total_length;
895
896    ISC_LIST_INIT( *nameList );
897
898    for( name =   domains + strspn(domains," \t\n"),
899	 endName = name + strcspn(name," \t\n");
900	 (name < endp) && (endName <= endp);
901	 name =  endName + 1 + strspn(endName+1," \t\n"),
902	 endName = name + strcspn(name," \t\n")
903       )
904    {  /* name loop */
905	*endName = '\0';
906
907	isc_buffer_init( &buffer, name, endName - name );
908	isc_buffer_add(&buffer, endName - name);
909
910	fixedname = isc_mem_get( mgr->mctx, sizeof( dns_fixedname_t ));
911
912	dns_fixedname_init(fixedname);
913
914	dnsName = dns_fixedname_name(fixedname);
915
916	result= dns_name_fromtext
917	        (  dnsName, &buffer, ( *(endp-1) != '.') ? dns_rootname : NULL, 0, NULL
918		);
919
920	if( result != ISC_R_SUCCESS )
921	{
922	    sprintf(error_name, "com.redhat.named.InvalidArgument");
923	    sprintf(error_message,"Invalid DNS name initial argument: %s", name);
924
925	    isc_mem_put( mgr->mctx, fixedname, sizeof( dns_fixedname_t ) );
926
927	    for( dnsName = ISC_LIST_HEAD( *nameList );
928		 (dnsName != 0L);
929		 dnsName = ISC_LIST_HEAD( *nameList )
930	       )
931	    {
932		if( ISC_LINK_LINKED(dnsName,link) )
933		    ISC_LIST_DEQUEUE( *nameList, dnsName, link );
934		isc_mem_put( mgr->mctx, dnsName, sizeof( dns_fixedname_t ) );
935	    }
936	    ISC_LIST_INIT(*nameList);
937	    return;
938	}
939	ISC_LINK_INIT(dnsName, link);
940	ISC_LIST_ENQUEUE( *nameList, dnsName, link );
941    }
942}
943
944static isc_result_t
945dbus_mgr_get_sa_list
946(
947    ns_dbus_mgr_t *mgr,
948    dbus_svc_MessageIterator iter,
949    SockAddrList *saList ,
950    uint8_t *fwdpolicy,
951    char *error_name,
952    char *error_message
953)
954{
955    DBUS_SVC dbus = mgr->dbus;
956    isc_sockaddr_t *nsSA=0L, *nsSA_Q=0L;
957    uint32_t argType = dbus_svc_message_next_arg_type( dbus, iter ),
958	     length;
959    isc_result_t result;
960    in_port_t port;
961    char *ip;
962    uint8_t *iparray=0L;
963
964    ISC_LIST_INIT(*saList);
965
966    if( argType == TYPE_INVALID )
967	return ISC_R_SUCCESS; /* address list "removal" */
968
969    do
970    {
971	switch( argType )
972	{
973	case TYPE_UINT32:
974
975	    nsSA = isc_mem_get(mgr->mctx, sizeof(isc_sockaddr_t));
976	    if( nsSA != 0L )
977	    {
978		memset(nsSA,'\0', sizeof(isc_sockaddr_t));
979		nsSA_Q = nsSA;
980		dbus_svc_message_next_arg(dbus, iter, &(nsSA->type.sin.sin_addr.s_addr));
981		nsSA->type.sa.sa_family = AF_INET;
982		nsSA->length = sizeof( nsSA->type.sin );
983	    }
984	    break;
985
986	case TYPE_ARRAY:
987
988	    argType = dbus_svc_message_element_type( dbus, iter );
989	    if( argType == TYPE_BYTE )
990	    {
991		iparray = 0L;
992		length = 0;
993
994		dbus_svc_message_get_elements(dbus, iter, &length, &iparray);
995
996		if( iparray != 0L )
997		{
998		    if (length == sizeof( struct in_addr ))
999		    {
1000			nsSA = isc_mem_get(mgr->mctx, sizeof(isc_sockaddr_t));
1001			if( nsSA != 0L )
1002			{
1003			    memset(nsSA,'\0', sizeof(isc_sockaddr_t));
1004			    nsSA_Q = nsSA;
1005
1006			    memcpy(&(nsSA->type.sin.sin_addr), iparray, sizeof( struct in_addr ));
1007			    nsSA->type.sa.sa_family = AF_INET;
1008			    nsSA->length = sizeof( nsSA->type.sin );
1009			}
1010		    }else
1011		    if (length == sizeof( struct in6_addr ))
1012		    {
1013			nsSA = isc_mem_get(mgr->mctx, sizeof(isc_sockaddr_t));
1014			if( nsSA != 0L )
1015			{
1016			    memset(nsSA,'\0', sizeof(isc_sockaddr_t));
1017			    nsSA_Q = nsSA;
1018
1019			    memcpy(&(nsSA->type.sin6.sin6_addr), iparray, sizeof( struct in6_addr ));
1020			    nsSA->type.sa.sa_family = AF_INET6;
1021			    nsSA->length = sizeof( nsSA->type.sin6 );
1022			}
1023		    }
1024		}
1025	    }
1026	    break;
1027
1028	case TYPE_STRING:
1029
1030	    ip = 0L;
1031	    dbus_svc_message_next_arg(dbus, iter, &(ip));
1032	    if( ip != 0L )
1033	    {
1034		length = strlen(ip);
1035		if( strspn(ip, "0123456789.") == length )
1036		{
1037		    nsSA = isc_mem_get(mgr->mctx, sizeof(isc_sockaddr_t));
1038		    if( nsSA != 0L)
1039		    {
1040			memset(nsSA,'\0', sizeof(isc_sockaddr_t));
1041			if( inet_pton( AF_INET, ip, &(nsSA->type.sin.sin_addr)) )
1042			{
1043			    nsSA->type.sa.sa_family = AF_INET;
1044			    nsSA->length = sizeof(nsSA->type.sin);
1045			    nsSA_Q = nsSA;
1046			}
1047		    }
1048		}else
1049		if( strspn(ip, "0123456789AaBbCcDdEeFf:.") == length)
1050		{
1051		    nsSA = isc_mem_get(mgr->mctx, sizeof(isc_sockaddr_t));
1052		    if( nsSA != 0L )
1053		    {
1054			memset(nsSA,'\0', sizeof(isc_sockaddr_t));
1055			if( inet_pton( AF_INET6, ip, &(nsSA->type.sin6.sin6_addr)) )
1056			{
1057			    nsSA->type.sa.sa_family = AF_INET6;
1058			    nsSA->length = sizeof(nsSA->type.sin6);
1059			    nsSA_Q = nsSA;
1060			}
1061		    }
1062		}
1063	    }
1064	    break;
1065
1066	case TYPE_UINT16:
1067
1068	    if( (nsSA == 0L) || (nsSA->type.sa.sa_family == AF_UNSPEC) )
1069		break;
1070	    else
1071	    if( nsSA->type.sa.sa_family == AF_INET )
1072		dbus_svc_message_next_arg(dbus, iter, &(nsSA->type.sin.sin_port));
1073	    else
1074            if( nsSA->type.sa.sa_family == AF_INET6 )
1075		dbus_svc_message_next_arg(dbus, iter, &(nsSA->type.sin6.sin6_port));
1076	    break;
1077
1078	case TYPE_BYTE:
1079
1080	    dbus_svc_message_next_arg(dbus, iter, fwdpolicy);
1081	    if(*fwdpolicy > dns_fwdpolicy_only)
1082		*fwdpolicy =  dns_fwdpolicy_only;
1083	    break;
1084
1085	default:
1086
1087	    if(nsSA != 0L)
1088		nsSA->type.sa.sa_family = AF_UNSPEC;
1089	    sprintf(error_message,"Unhandled argument type: %c", argType);
1090	    break;
1091	}
1092
1093	if( (nsSA != 0L)
1094	  &&(nsSA->type.sa.sa_family == AF_UNSPEC)
1095	  )
1096	{
1097	    sprintf(error_name, "com.redhat.named.InvalidArgument");
1098	    if( error_message[0]=='\0')
1099	    {
1100		if( nsSA == 0L )
1101		    sprintf(error_message,"Missing IP Address Name Server argument");
1102		else
1103		    sprintf(error_message,"Bad IP Address Name Server argument");
1104	    }
1105       	    if( nsSA != 0L )
1106		isc_mem_put(mgr->mctx, nsSA, sizeof(isc_sockaddr_t));
1107	    nsSA = 0L;
1108	    for( nsSA = ISC_LIST_HEAD( *saList );
1109		 (nsSA != 0L);
1110		 nsSA = ISC_LIST_HEAD( *saList )
1111	       )
1112	    {
1113		if(ISC_LINK_LINKED(nsSA, link))
1114		    ISC_LIST_DEQUEUE( *saList, nsSA, link );
1115		isc_mem_put( mgr->mctx, nsSA, sizeof( isc_sockaddr_t ) );
1116	    }
1117	    ISC_LIST_INIT(*saList);
1118	    return ISC_R_FAILURE;
1119	}
1120
1121	if( nsSA != 0L )
1122	{
1123	    if( nsSA->type.sin.sin_port == 0 )
1124	    {
1125		if( ns_g_port != 0L )
1126		    nsSA->type.sin.sin_port = htons(ns_g_port);
1127		else
1128		{
1129		    result = ns_config_getport(ns_g_config, &(port) );
1130		    if( result != ISC_R_SUCCESS )
1131			port = 53;
1132		    nsSA->type.sin.sin_port = htons( port );
1133		}
1134	    }
1135
1136	    if( nsSA_Q != 0L )
1137	    {
1138		ISC_LINK_INIT(nsSA,link);
1139		ISC_LIST_ENQUEUE(*saList, nsSA, link);
1140		nsSA_Q = 0L;
1141	    }
1142	}
1143
1144	argType = dbus_svc_message_next_arg_type( dbus, iter );
1145
1146    } while ( argType != TYPE_INVALID );
1147
1148    return ISC_R_SUCCESS;
1149}
1150
1151static void
1152dbus_mgr_handle_set_forwarders
1153(
1154    ns_dbus_mgr_t *mgr,
1155    DBUS_SVC dbus,
1156    uint8_t  reply_expected,
1157    uint32_t serial,
1158    const char *path,
1159    const char *member,
1160    const char *interface,
1161    const char *sender,
1162    dbus_svc_MessageHandle msg
1163)
1164{
1165    dbus_svc_MessageIterator iter;
1166    char error_name[1024]="", error_message[1024]="", *domains=0L;
1167    uint32_t       argType, new_serial;
1168    DNSNameList nameList;
1169    dns_name_t     *dnsName;
1170    SockAddrList  saList;
1171    isc_sockaddr_t *nsSA;
1172    isc_result_t   result;
1173    uint8_t fwdpolicy = dns_fwdpolicy_only;
1174
1175    iter = dbus_svc_message_iterator_new( dbus, msg );
1176
1177    if( iter == 0L )
1178    {
1179	if( reply_expected )
1180	{
1181	    sprintf(error_name, "com.redhat.named.InvalidArguments");
1182	    sprintf(error_message,"SetForwarders requires DNS name and nameservers arguments.");
1183	    dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
1184			   TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
1185		         );
1186	}
1187	return;
1188    }
1189
1190    argType = dbus_svc_message_next_arg_type( dbus, iter );
1191
1192    if( argType != TYPE_STRING )
1193    {
1194	if( reply_expected )
1195	{
1196	    sprintf(error_name, "com.redhat.named.InvalidArguments");
1197	    sprintf(error_message,"SetForwarders requires DNS name string initial argument.");
1198	    dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
1199			   TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
1200		         );
1201	}
1202	return;
1203    }
1204
1205    dbus_svc_message_next_arg( dbus, iter, &domains );
1206
1207    if( ( domains == 0L ) || (*domains == '\0') )
1208    {
1209	if( reply_expected )
1210	{
1211	    sprintf(error_name, "com.redhat.named.InvalidArguments");
1212	    sprintf(error_message,"SetForwarders requires DNS name string initial argument.");
1213	    dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
1214			   TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
1215		         );
1216	}
1217	return;
1218    }
1219
1220    dbus_mgr_get_name_list( mgr, domains, &nameList, error_name, error_message );
1221
1222    if( error_name[0] != '\0' )
1223    {
1224	if( reply_expected )
1225	{
1226	    dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
1227			   TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
1228		         );
1229	}
1230	return;
1231    }
1232
1233    if( ISC_LIST_HEAD( nameList ) == 0L )
1234	return;
1235
1236    result = dbus_mgr_get_sa_list( mgr, iter, &saList , &fwdpolicy, error_name, error_message );
1237
1238    if( result == ISC_R_SUCCESS )
1239    {
1240	result = dbus_mgr_set_forwarders( mgr, &nameList, &saList, fwdpolicy );
1241
1242	if( result != ISC_R_SUCCESS )
1243	{
1244	    if( reply_expected )
1245	    {
1246		sprintf(error_name, "com.redhat.named.Failure");
1247		sprintf(error_message, isc_result_totext(result));
1248		dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
1249			       TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
1250		             );
1251	    }
1252	}else
1253	    if( reply_expected )
1254		dbus_svc_send( dbus, RETURN, serial, &new_serial, sender, path, interface, member,
1255		       TYPE_UINT32, &result, TYPE_INVALID
1256	             );
1257    }else
1258    {
1259	if( reply_expected )
1260	{
1261	    dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
1262			   TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
1263		         );
1264	}
1265    }
1266
1267    for( dnsName = ISC_LIST_HEAD( nameList );
1268	 (dnsName != 0L) ;
1269	 dnsName = ISC_LIST_HEAD( nameList )
1270	)
1271    {
1272	if( ISC_LINK_LINKED(dnsName,link) )
1273	    ISC_LIST_DEQUEUE( nameList, dnsName, link );
1274	isc_mem_put( mgr->mctx, dnsName, sizeof( dns_fixedname_t ) );
1275    }
1276
1277    for( nsSA = ISC_LIST_HEAD(saList);
1278	 (nsSA != 0L) ;
1279	 nsSA = ISC_LIST_HEAD(saList)
1280       )
1281    {
1282	if( ISC_LINK_LINKED(nsSA,link) )
1283	    ISC_LIST_DEQUEUE( saList, nsSA, link );
1284	isc_mem_put(mgr->mctx, nsSA, sizeof(isc_sockaddr_t));
1285    }
1286}
1287
1288static
1289int dbus_mgr_msg_append_dns_name
1290(   DBUS_SVC dbus,
1291    dbus_svc_MessageHandle msg,
1292    dns_name_t *name
1293)
1294{
1295    char  nameBuf[ DNS_NAME_FORMATSIZE ]="", *nameP=&(nameBuf[0]);
1296
1297    dns_name_format(name, nameP, DNS_NAME_FORMATSIZE );
1298
1299    if( *nameP == '\0' )
1300	return 0;
1301
1302    return dbus_svc_message_append_args( dbus, msg, TYPE_STRING, &nameP, TYPE_INVALID ) > 0;
1303}
1304
1305typedef enum dbmoi_e
1306{
1307    OUTPUT_BINARY,
1308    OUTPUT_TEXT
1309}   DBusMgrOutputInterface;
1310
1311static
1312int dbus_mgr_msg_append_forwarders
1313(   DBUS_SVC               dbus,
1314    dbus_svc_MessageHandle msg,
1315    dns_forwarders_t      *fwdr,
1316    DBusMgrOutputInterface outputType
1317)
1318{
1319    isc_sockaddr_t *sa;
1320    char policyBuf[16]="", *pbp[1]={&(policyBuf[0])}, addressBuf[64]="", *abp[1]={&(addressBuf[0])};
1321    uint8_t *byteArray[1];
1322
1323    if( outputType == OUTPUT_BINARY )
1324    {
1325	if(!dbus_svc_message_append_args
1326	   (   dbus, msg,
1327	       TYPE_BYTE, &(fwdr->fwdpolicy),
1328	       TYPE_INVALID
1329	   )
1330	  ) return 0;
1331    }else
1332    if( outputType == OUTPUT_TEXT )
1333    {
1334	sprintf(policyBuf,"%s",
1335		(fwdr->fwdpolicy == dns_fwdpolicy_none)
1336		? "none"
1337		:  (fwdr->fwdpolicy == dns_fwdpolicy_first)
1338		   ? "first"
1339		   : "only"
1340	       );
1341	if(!dbus_svc_message_append_args
1342	   (   dbus, msg,
1343	       TYPE_STRING, pbp,
1344	       TYPE_INVALID
1345	   )
1346	  ) return 0;
1347    }else
1348	return 0;
1349
1350    for( sa = ISC_LIST_HEAD(fwdr->addrs);
1351	 sa != 0L;
1352	 sa = ISC_LIST_NEXT(sa, link)
1353	)
1354    {
1355	if( outputType == OUTPUT_BINARY )
1356	{
1357	    if( sa->type.sa.sa_family == AF_INET )
1358	    {
1359		if(!dbus_svc_message_append_args
1360		   (   dbus, msg,
1361		       TYPE_UINT32, &(sa->type.sin.sin_addr.s_addr),
1362		       TYPE_INVALID
1363		   )
1364		  ) return 0;
1365
1366		if(!dbus_svc_message_append_args
1367		   (   dbus, msg,
1368		       TYPE_UINT16, &(sa->type.sin.sin_port),
1369		       TYPE_INVALID
1370		   )
1371		  ) return 0;
1372	    }else
1373	    if( sa->type.sa.sa_family == AF_INET6 )
1374	    {
1375		byteArray[0] = (uint8_t*)&(sa->type.sin6.sin6_addr);
1376		if(!dbus_svc_message_append_args
1377		   (   dbus, msg,
1378		       TYPE_ARRAY, TYPE_BYTE, &byteArray, sizeof(struct in6_addr),
1379		       TYPE_INVALID
1380		   )
1381		  ) return 0;
1382
1383		if(!dbus_svc_message_append_args
1384		   (   dbus, msg,
1385		       TYPE_UINT16, &(sa->type.sin6.sin6_port),
1386		       TYPE_INVALID
1387		   )
1388		  ) return 0;
1389	    }else
1390		continue;
1391	}else
1392	if( outputType == OUTPUT_TEXT )
1393	{
1394	    if( sa->type.sa.sa_family == AF_INET )
1395	    {
1396		if( inet_ntop( AF_INET, &(sa->type.sin.sin_addr), addressBuf, sizeof(addressBuf)) == 0L )
1397		    continue;
1398		if(!dbus_svc_message_append_args
1399		   (   dbus, msg,
1400		       TYPE_STRING, abp,
1401		       TYPE_INVALID
1402		   )
1403		  ) return 0;
1404		sprintf(addressBuf, "%hu", ntohs( sa->type.sin.sin_port ));
1405		if(!dbus_svc_message_append_args
1406		   (   dbus, msg,
1407		       TYPE_STRING, abp,
1408		       TYPE_INVALID
1409		   )
1410		  ) return 0;
1411	    }else
1412	    if( sa->type.sa.sa_family == AF_INET6 )
1413	    {
1414		if( inet_ntop( AF_INET6, &(sa->type.sin6.sin6_addr), addressBuf, sizeof(addressBuf)) == 0L )
1415		    continue;
1416		if(!dbus_svc_message_append_args
1417		   (   dbus, msg,
1418		       TYPE_STRING, abp,
1419		       TYPE_INVALID
1420		   )
1421		  ) return 0;
1422		sprintf(addressBuf, "%hu", ntohs( sa->type.sin6.sin6_port ));
1423		if(!dbus_svc_message_append_args
1424		   (   dbus, msg,
1425		       TYPE_STRING, abp,
1426		       TYPE_INVALID
1427		   )
1428		  ) return 0;
1429	    }else
1430		continue;
1431	}else
1432	    return 0;
1433    }
1434    return 1;
1435}
1436
1437typedef struct dbm_m_s
1438{
1439    DBUS_SVC dbus;
1440    dbus_svc_MessageHandle msg;
1441    DBusMgrOutputInterface outputType;
1442}   DBusMgrMsg;
1443
1444static
1445void forwarders_to_msg( dns_name_t *name, dns_forwarders_t *fwdr, void *mp )
1446{
1447    DBusMgrMsg *m = mp;
1448
1449    if( (fwdr == 0L) || (name == 0L) || (mp == 0L))
1450	return;
1451    dbus_mgr_msg_append_dns_name  ( m->dbus, m->msg, name );
1452    dbus_mgr_msg_append_forwarders( m->dbus, m->msg, fwdr, m->outputType );
1453}
1454
1455static void
1456dbus_mgr_handle_list_forwarders
1457(
1458    DBUS_SVC dbus,
1459    uint8_t  reply_expected,
1460    uint32_t serial,
1461    const char *path,
1462    const char *member,
1463    const char *interface,
1464    const char *sender,
1465    dbus_svc_MessageHandle msg
1466)
1467{
1468    char error_name[1024], error_message[1024];
1469    DBusMgrMsg m;
1470    uint32_t new_serial;
1471    dns_fwdtable_t *fwdtable = dbus_mgr_get_fwdtable();
1472    DBusMgrOutputInterface outputType = OUTPUT_BINARY;
1473    uint32_t length = strlen(interface);
1474
1475    if( !reply_expected )
1476	return;
1477
1478    if( (length > 4) && (strcmp(interface + (length - 4), "text")==0))
1479	outputType = OUTPUT_TEXT;
1480
1481    if( fwdtable == 0L )
1482    {
1483	sprintf(error_name,"com.redhat.dbus.Failure");
1484	sprintf(error_message, "%s", isc_result_totext(ISC_R_NOPERM));
1485	dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
1486		       TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
1487	             );
1488	return;
1489    }
1490
1491    msg = dbus_svc_new_message( dbus, RETURN, serial, sender, path, interface, member);
1492
1493    m.dbus = dbus;
1494    m.msg = msg;
1495    m.outputType = outputType;
1496
1497    if( msg == 0L )
1498    {
1499	sprintf(error_name,"com.redhat.dbus.OutOfMemory");
1500	sprintf(error_message,"out of memory");
1501	dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
1502		       TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
1503	             );
1504    }
1505
1506    dns_fwdtable_foreach( fwdtable, forwarders_to_msg, &m );
1507
1508    dbus_svc_send_message( dbus, msg, &new_serial );
1509}
1510
1511static void
1512dbus_mgr_handle_get_forwarders
1513(
1514    DBUS_SVC dbus,
1515    uint8_t  reply_expected,
1516    uint32_t serial,
1517    const char *path,
1518    const char *member,
1519    const char *interface,
1520    const char *sender,
1521    dbus_svc_MessageHandle msg
1522)
1523{
1524    char error_name[1024], error_message[1024], *domain=0L;
1525    isc_result_t    result;
1526    dns_fixedname_t  fixedname;
1527    dns_name_t       *dnsName;
1528    isc_buffer_t     buffer;
1529    uint32_t         length,  new_serial;
1530    dns_fwdtable_t   *fwdtable;
1531    dns_forwarders_t *fwdr=0L;
1532    dns_name_t       *foundname;
1533    dns_fixedname_t  fixedFoundName;
1534    DBusMgrOutputInterface outputType = OUTPUT_BINARY;
1535
1536    if( !reply_expected )
1537	return;
1538
1539    length = strlen(interface);
1540
1541    if( (length > 4) && (strcmp(interface + (length - 4), "text")==0))
1542	outputType = OUTPUT_TEXT;
1543
1544    if( (!dbus_svc_get_args( dbus, msg, TYPE_STRING, &domain, TYPE_INVALID))
1545      ||(domain == 0L)
1546      ||(*domain == '\0')
1547      )
1548    {
1549
1550	sprintf(error_name,"com.redhat.dbus.InvalidArguments");
1551	sprintf(error_message,"domain name argument expected");
1552	dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
1553		       TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
1554	             );
1555	return;
1556    }
1557
1558    length = strlen( domain );
1559
1560    isc_buffer_init( &buffer, domain, length);
1561
1562    isc_buffer_add(&buffer, length);
1563
1564    dns_fixedname_init(&fixedname);
1565
1566    dnsName = dns_fixedname_name(&fixedname);
1567
1568    result = dns_name_fromtext
1569	     (  dnsName, &buffer, dns_rootname, 0, NULL
1570	     );
1571
1572    if( result != ISC_R_SUCCESS )
1573    {
1574	sprintf(error_name,"com.redhat.dbus.InvalidArguments");
1575	sprintf(error_message,"invalid domain name argument: %s", domain);
1576	dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
1577		       TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
1578	             );
1579	return;
1580    }
1581
1582    msg = dbus_svc_new_message( dbus, RETURN, serial, sender, path, interface, member);
1583
1584    if( msg == 0L )
1585    {
1586	sprintf(error_name,"com.redhat.dbus.OutOfMemory");
1587	sprintf(error_message,"out of memory");
1588	dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
1589		       TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
1590	             );
1591	return;
1592    }
1593
1594    fwdtable = dbus_mgr_get_fwdtable();
1595
1596    if( fwdtable == 0L )
1597    {
1598	sprintf(error_name,"com.redhat.dbus.Failure");
1599	sprintf(error_message, "%s", isc_result_totext(ISC_R_NOPERM));
1600	dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
1601		       TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
1602	             );
1603	return;
1604    }
1605
1606    dns_fixedname_init(&fixedFoundName);
1607    foundname = dns_fixedname_name(&fixedFoundName);
1608
1609    if( ( dns_fwdtable_find_closest( fwdtable, dnsName, foundname, &fwdr ) == ISC_R_SUCCESS )
1610      &&( fwdr != 0L )
1611      )
1612    {
1613	if( (!dbus_mgr_msg_append_dns_name( dbus, msg, foundname ))
1614	  ||(!dbus_mgr_msg_append_forwarders( dbus, msg, fwdr, outputType ))
1615	  )
1616	{
1617	    sprintf(error_name,"com.redhat.dbus.OutOfMemory");
1618	    sprintf(error_message,"out of memory");
1619	    dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
1620			   TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
1621		);
1622	    return;
1623	}
1624
1625    }else
1626    {
1627	result = ISC_R_NOTFOUND;
1628	if( outputType == OUTPUT_BINARY )
1629	{
1630	    dbus_svc_message_append_args( dbus, msg,
1631					  TYPE_UINT32, &(result),
1632					  TYPE_INVALID
1633		                        ) ;
1634	}else
1635	{
1636	    sprintf(error_name,"com.redhat.dbus.NotFound");
1637	    sprintf(error_message,"Not Found");
1638	    dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
1639			   TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
1640		         );
1641	    return;
1642	}
1643    }
1644    dbus_svc_send_message( dbus, msg, &new_serial );
1645}
1646
1647static void
1648dbus_mgr_check_dhcdbd_state( ns_dbus_mgr_t *mgr, dbus_svc_MessageHandle msg )
1649{
1650    DBUS_SVC dbus = mgr->dbus;
1651    char *name_owned = 0L,
1652	 *old_owner = 0L,
1653	 *new_owner = 0L;
1654
1655    if( !dbus_svc_get_args( dbus, msg,
1656			    TYPE_STRING, &name_owned,
1657			    TYPE_STRING, &old_owner,
1658			    TYPE_STRING, &new_owner,
1659			    TYPE_INVALID
1660	                  )
1661      ) return;
1662
1663    dbus_mgr_log_dbg("NameOwnerChanged: %s %s %s ( %s )", name_owned, old_owner, new_owner, mgr->dhcdbd_name);
1664
1665    if( (name_owned == 0L) || (new_owner == 0L) || (old_owner == 0L) )
1666	return;
1667
1668    if( strcmp( name_owned, "com.redhat.dhcp" ) == 0 )
1669    {
1670	if( *new_owner == '\0' )
1671	{
1672	    isc_mem_put(mgr->mctx, mgr->dhcdbd_name, strlen(mgr->dhcdbd_name) + 1);
1673	    mgr->dhcdbd_name = 0L;
1674	    dbus_mgr_log_err("D-BUS dhcdbd subscription disabled.");
1675	    return;
1676	}
1677	if( (mgr->dhcdbd_name == 0L)
1678	  ||( strcmp( mgr->dhcdbd_name, new_owner) != 0 )
1679	  )
1680	{
1681	    if( mgr->dhcdbd_name != 0L )
1682	    {
1683		isc_mem_put(mgr->mctx, mgr->dhcdbd_name, strlen(mgr->dhcdbd_name)+1);
1684		mgr->dhcdbd_name = 0L;
1685	    }
1686	    mgr->dhcdbd_name = isc_mem_get(mgr->mctx, strlen(new_owner) + 1);
1687	    if( mgr->dhcdbd_name == 0L )
1688		return;
1689	    strcpy( mgr->dhcdbd_name, new_owner );
1690	    dbus_mgr_subscribe_to_dhcdbd( mgr );
1691	}
1692    }else
1693    if(  ( mgr->dhcdbd_name != 0L )
1694      && ( strcmp(mgr->dhcdbd_name, name_owned) == 0L )
1695      && ( *new_owner == '\0' )
1696      )
1697    {
1698	isc_mem_put(mgr->mctx, mgr->dhcdbd_name, strlen(mgr->dhcdbd_name));
1699	mgr->dhcdbd_name = 0L;
1700	dbus_mgr_log_err("D-BUS dhcdbd subscription disabled.");
1701    }
1702}
1703
1704static int dbus_mgr_dhc_if_comparator( const void *p1, const void *p2 )
1705{
1706    return( strcmp( ((const DHC_IF*)p1)->if_name, ((const DHC_IF*)p2)->if_name) );
1707}
1708
1709static
1710dns_name_t *dbus_mgr_if_reverse_ip_name
1711(   ns_dbus_mgr_t *mgr,
1712    struct in_addr ip_address,
1713    struct in_addr subnet_mask
1714)
1715{
1716    dns_name_t *dns_name =0L;
1717    dns_fixedname_t *fixedname=0L;
1718    char name [ DNS_NAME_FORMATSIZE ], *p;
1719    uint32_t ip = (ntohl(ip_address.s_addr) & ntohl(subnet_mask.s_addr)), i;
1720    isc_buffer_t buffer;
1721    isc_result_t result;
1722
1723    if( (ip == 0) || (ip == 0xffffffff) )
1724	return 0L;
1725
1726    for(i = 8, p = name; (i < 32); i += 8)
1727	if( ip & ( 0xff << i ) )
1728	    p += sprintf(p, "%u.", (((ip & ( 0xff << i )) >> i ) & 0xff) );
1729
1730    if( p > name )
1731    {
1732	p += sprintf(p, "in-addr.arpa");
1733	isc_buffer_init( &buffer, name, p - name );
1734	isc_buffer_add(&buffer, p - name);
1735
1736	fixedname = isc_mem_get( mgr->mctx, sizeof( dns_fixedname_t ));
1737
1738	dns_fixedname_init(fixedname);
1739
1740	dns_name = dns_fixedname_name(fixedname);
1741
1742	result= dns_name_fromtext
1743	        (  dns_name, &buffer, dns_rootname, 0, NULL
1744		);
1745
1746	ISC_LINK_INIT(dns_name, link);
1747	if( result == ISC_R_SUCCESS )
1748	    return dns_name;
1749    }
1750    return 0L;
1751}
1752
1753static void
1754dbus_mgr_free_dhc( void *p )
1755{
1756    DHC_IF *d_if = p;
1757    dns_name_t *dn;
1758    isc_sockaddr_t *sa;
1759
1760    isc_mem_put( ns_g_mctx, d_if->if_name, strlen(d_if->if_name) + 1);
1761    for( sa = ISC_LIST_HEAD( d_if->dns );
1762	 sa != NULL;
1763	 sa = ISC_LIST_HEAD( d_if->dns )
1764       )
1765    {
1766	if( ISC_LINK_LINKED( sa, link ) )
1767	    ISC_LIST_UNLINK( d_if->dns, sa, link );
1768	isc_mem_put(ns_g_mctx, sa, sizeof(isc_sockaddr_t));
1769    }
1770    for( dn = ISC_LIST_HEAD( d_if->dn );
1771	 dn != NULL;
1772	 dn = ISC_LIST_HEAD( d_if->dn )
1773       )
1774    {
1775	if( ISC_LINK_LINKED( dn, link ) )
1776	    ISC_LIST_UNLINK( d_if->dn, dn, link );
1777	isc_mem_put( ns_g_mctx, dn, sizeof( dns_fixedname_t ) );
1778    }
1779    isc_mem_put( ns_g_mctx, d_if, sizeof(DHC_IF));
1780}
1781
1782static void
1783dbus_mgr_handle_dhcdbd_message
1784(
1785    ns_dbus_mgr_t *mgr,
1786    const char *path,
1787    const char *member,
1788    dbus_svc_MessageHandle msg
1789)
1790{
1791    DBUS_SVC dbus = mgr->dbus;
1792    DHC_IF *d_if, *const*d_ifpp, dif;
1793    DHC_State dhc_state;
1794    char *if_name, *opt_name, error_name[1024]="", error_message[1024]="";
1795    uint8_t *value=0L;
1796    uint32_t length;
1797    isc_result_t result;
1798    isc_sockaddr_t *sa = 0L;
1799    dns_name_t *dn = 0L;
1800    struct in_addr *ip;
1801    in_port_t port;
1802    char dnBuf[ DNS_NAME_FORMATSIZE ];
1803    isc_buffer_t buffer;
1804    DBusMgrInitialFwdr *ifwdr, *const*ifwdpp, ifwd;
1805    ISC_LIST(DBusMgrInitialFwdr) ifwdrList;
1806    DNSNameList nameList;
1807    dbus_mgr_log_dbg("Got dhcdbd message: %s %s %p", path, member, msg );
1808
1809    if( ( if_name = strrchr(path,'/') ) == 0L )
1810    {
1811	dbus_mgr_log_err("bad path in dhcdbd message:", path);
1812	return;
1813    }
1814
1815    ++if_name;
1816    dif.if_name = if_name;
1817
1818    if( ((d_ifpp=tfind( &dif, &(mgr->dhc_if), dbus_mgr_dhc_if_comparator)) == 0L)
1819      ||((d_if = *d_ifpp) == 0L)
1820      )
1821    {
1822	d_if = isc_mem_get( mgr->mctx, sizeof(DHC_IF));
1823	if( d_if == 0L )
1824	{
1825	    dbus_mgr_log_err("out of memory");
1826	    return;
1827	}
1828	memset(d_if, '\0', sizeof(DHC_IF));
1829	if((d_if->if_name =  isc_mem_get( mgr->mctx, strlen(if_name) + 1)) == 0L)
1830	{
1831	    dbus_mgr_log_err("out of memory");
1832	    return;
1833	}
1834	strcpy(d_if->if_name, if_name);
1835	d_if->dhc_state = DHC_INVALID;
1836	d_if->previous_state = DHC_INVALID;
1837	ISC_LIST_INIT( d_if->dn );
1838	ISC_LIST_INIT( d_if->dns );
1839	if( tsearch( d_if, &(mgr->dhc_if), dbus_mgr_dhc_if_comparator) == 0L )
1840	{
1841	    dbus_mgr_log_err("out of memory");
1842	    return;
1843	}
1844    }
1845
1846    if( strcmp(member, "reason") == 0 )
1847    {
1848	if( (!dbus_svc_get_args( dbus, msg,
1849				 TYPE_STRING, &opt_name,
1850				 TYPE_ARRAY, TYPE_BYTE, &value, &length,
1851				 TYPE_INVALID
1852		               )
1853	    )
1854	  ||( value == 0L)
1855	  ||( length != sizeof(uint32_t))
1856	  ||( *((uint32_t*)value) > DHC_END_OPTIONS)
1857	  )
1858	{
1859	    dbus_mgr_log_err("Invalid DHC reason value received from dhcdbd");
1860	    return;
1861	}
1862	dhc_state = (DHC_State) *((uint32_t*)value);
1863	dbus_mgr_log_dbg("reason: %d %d %d", dhc_state, d_if->dhc_state, d_if->previous_state);
1864	switch( dhc_state )
1865	{
1866
1867	case  DHC_END_OPTIONS:
1868	    switch( d_if->dhc_state )
1869	    {
1870	    case  DHC_END_OPTIONS:
1871		break;
1872
1873	    case  DHC_RENEW:
1874	    case  DHC_REBIND:
1875		if( ( d_if->previous_state != DHC_INVALID )
1876		  &&( d_if->previous_state != DHC_RELEASE )
1877		  ) break;
1878		    /* DHC_RENEW means the same lease parameters were obtained.
1879		     * Only do configuration if we started up with existing dhclient
1880		     * which has now renewed - else we are already configured correctly.
1881		     */
1882		dbus_mgr_log_err("D-BUS: existing dhclient for interface %s RENEWed lease", if_name);
1883
1884	    case  DHC_REBOOT:
1885	    case  DHC_BOUND:
1886		d_if->previous_state = d_if->dhc_state;
1887		d_if->dhc_state = DHC_BOUND;
1888		if( (dn = dbus_mgr_if_reverse_ip_name(mgr, d_if->ip, d_if->subnet_mask )) != 0L )
1889		{
1890		    ISC_LIST_APPEND(d_if->dn, dn, link );
1891		}
1892		if( ( ISC_LIST_HEAD( d_if->dn ) != NULL )
1893		  &&( ISC_LIST_HEAD( d_if->dns ) != NULL )
1894		  )
1895		{
1896		    dbus_mgr_log_err("D-BUS: dhclient for interface %s acquired new lease - creating forwarders.",
1897				     if_name
1898			            );
1899		    result = dbus_mgr_set_forwarders( mgr, &(d_if->dn), &(d_if->dns), dns_fwdpolicy_only );
1900		    if( result != ISC_R_SUCCESS )
1901		    {
1902			dbus_mgr_log_err("D-BUS: forwarder configuration failed: %s", isc_result_totext(result));
1903		    }
1904		}
1905		break;
1906
1907	    case  DHC_STOP:
1908	    case  DHC_TIMEOUT:
1909	    case  DHC_FAIL:
1910	    case  DHC_EXPIRE:
1911	    case  DHC_RELEASE:
1912		d_if->previous_state = d_if->dhc_state;
1913		d_if->dhc_state = DHC_RELEASE;
1914		if( ISC_LIST_HEAD( d_if->dn ) != NULL )
1915		{
1916		    dbus_mgr_log_err("D-BUS: dhclient for interface %s released lease - removing forwarders.",
1917				     if_name);
1918		    for( sa = ISC_LIST_HEAD( d_if->dns );
1919			 sa != 0L;
1920			 sa = ISC_LIST_HEAD( d_if->dns )
1921		       )
1922		    {
1923			if( ISC_LINK_LINKED( sa, link ) )
1924			    ISC_LIST_UNLINK( d_if->dns, sa, link );
1925			isc_mem_put( mgr->mctx, sa, sizeof(isc_sockaddr_t));
1926		    }
1927		    ISC_LIST_INIT( d_if->dns );
1928		    ISC_LIST_INIT( ifwdrList );
1929
1930		    for( dn = ISC_LIST_HEAD( d_if->dn );
1931			 dn != 0L;
1932			 dn = ISC_LIST_NEXT( dn, link )
1933		       )
1934		    {
1935		        dns_name_init( &(ifwd.dn), NULL );
1936			isc_buffer_init( &buffer, dnBuf, DNS_NAME_FORMATSIZE);
1937			dns_name_setbuffer( &(ifwd.dn), &buffer);
1938			dns_name_copy(dn, &(ifwd.dn), NULL);
1939			if( ((ifwdpp = tfind(&ifwd, &(mgr->ifwdt), dbus_mgr_ifwdr_comparator)) != 0L )
1940			  &&((ifwdr = *ifwdpp) != 0L)
1941			  )
1942			{
1943			    ISC_LIST_APPEND( ifwdrList, ifwdr, link );
1944			}
1945		    }
1946
1947		    result = dbus_mgr_set_forwarders( mgr, &(d_if->dn), &(d_if->dns), dns_fwdpolicy_none );
1948		    if( result != ISC_R_SUCCESS )
1949		    {
1950			dbus_mgr_log_err("D-BUS: removal of forwarders failed: %s", isc_result_totext(result));
1951		    }
1952
1953		    for( dn = ISC_LIST_HEAD( d_if->dn );
1954			 dn != 0L;
1955			 dn = ISC_LIST_HEAD( d_if->dn )
1956		       )
1957		    {
1958			if( ISC_LINK_LINKED( dn, link ) )
1959			    ISC_LIST_UNLINK( d_if->dn, dn, link );
1960			isc_mem_put( mgr->mctx, dn, sizeof( dns_fixedname_t ) );
1961		    }
1962		    ISC_LIST_INIT( d_if->dn );
1963
1964		    for( ifwdr = ISC_LIST_HEAD( ifwdrList );
1965			 ifwdr != 0L;
1966			 ifwdr = ISC_LIST_HEAD( ifwdrList )
1967		       )
1968		    {
1969			if( ISC_LINK_LINKED( ifwdr, link ) )
1970			    ISC_LIST_UNLINK( ifwdrList, ifwdr, link );
1971			ISC_LINK_INIT(ifwdr, link);
1972			ISC_LIST_INIT(nameList);
1973			ISC_LINK_INIT(&(ifwdr->dn), link);
1974			ISC_LIST_APPEND( nameList, &(ifwdr->dn), link );
1975			result = dbus_mgr_set_forwarders( mgr, &nameList,
1976							  &(ifwdr->sa),
1977							  ifwdr->fwdpolicy
1978			                                );
1979			if( result != ISC_R_SUCCESS )
1980			{
1981			    dbus_mgr_log_err("D-BUS: restore of forwarders failed: %s", isc_result_totext(result));
1982			}
1983		    }
1984		}
1985
1986	    case  DHC_ABEND:
1987	    case  DHC_END:
1988	    case  DHC_NBI:
1989	    case  DHC_PREINIT:
1990	    case  DHC_MEDIUM:
1991	    case  DHC_START:
1992	    case  DHC_INVALID:
1993	    default:
1994		break;
1995	    }
1996	    break;
1997
1998	case  DHC_BOUND:
1999	case  DHC_REBOOT:
2000	case  DHC_REBIND:
2001	case  DHC_RENEW:
2002        case  DHC_STOP:
2003        case  DHC_TIMEOUT:
2004	case  DHC_FAIL:
2005	case  DHC_EXPIRE:
2006	case  DHC_RELEASE:
2007		d_if->previous_state = d_if->dhc_state;
2008		d_if->dhc_state = dhc_state;
2009
2010	case  DHC_ABEND:
2011	case  DHC_END:
2012	case  DHC_NBI:
2013	case  DHC_PREINIT:
2014	case  DHC_MEDIUM:
2015	case  DHC_START:
2016	case  DHC_INVALID:
2017	default:
2018	    break;
2019	}
2020    }else
2021    if( strcmp( member, "domain_name" ) == 0 )
2022    {
2023	if( (!dbus_svc_get_args( dbus, msg,
2024				 TYPE_STRING, &opt_name,
2025				 TYPE_ARRAY, TYPE_BYTE, &value, &length,
2026				 TYPE_INVALID
2027		               )
2028	    )
2029	  ||( value == 0L)
2030	  ||( length == 0)
2031	  )
2032	{
2033	    dbus_mgr_log_err("Invalid domain_name value received from dhcdbd");
2034	    return;
2035	}
2036	dbus_mgr_log_dbg("domain-name %s", (char*)value);
2037	dbus_mgr_get_name_list( mgr, (char*)value, &(d_if->dn), error_name, error_message );
2038	if( ( error_message[0] != '\0' ) || (ISC_LIST_HEAD(d_if->dn) == 0L ))
2039	{
2040	    dbus_mgr_log_err("Bad domain_name value: %s", error_message );
2041	}
2042    }else
2043    if( strcmp( member, "domain_name_servers") == 0 )
2044    {
2045	if( (!dbus_svc_get_args( dbus, msg,
2046				 TYPE_STRING, &opt_name,
2047				 TYPE_ARRAY, TYPE_BYTE, &value, &length,
2048				 TYPE_INVALID
2049		               )
2050	    )
2051	  ||( value == 0L)
2052	  ||( length == 0)
2053	  )
2054	{
2055	    dbus_mgr_log_err("Invalid domain_name_servers value received from dhcdbd");
2056	    return;
2057	}
2058	for(ip = (struct in_addr*) value; ip < ((struct in_addr*)(value + length)); ip++)
2059	{
2060	    dbus_mgr_log_dbg("domain-name-servers: %s", inet_ntop(AF_INET, value, error_name, 16));
2061	    sa = isc_mem_get(mgr->mctx, sizeof(isc_sockaddr_t));
2062	    memset(sa, '\0', sizeof(isc_sockaddr_t));
2063	    sa->type.sin.sin_addr = *ip;
2064	    sa->type.sa.sa_family = AF_INET;
2065	    sa->length = sizeof(sa->type.sin);
2066	    result = ns_config_getport(ns_g_config, &(port) );
2067	    if( result != ISC_R_SUCCESS )
2068		port = 53;
2069	    sa->type.sin.sin_port = htons( port );
2070	    ISC_LIST_APPEND(d_if->dns, sa, link);
2071	}
2072    }else
2073    if( strcmp(member, "ip_address") == 0)
2074    {
2075	if( (!dbus_svc_get_args( dbus, msg,
2076				 TYPE_STRING, &opt_name,
2077				 TYPE_ARRAY, TYPE_BYTE, &value, &length,
2078				 TYPE_INVALID
2079		               )
2080	    )
2081	  ||( value == 0L)
2082	  ||( length != sizeof(struct in_addr) )
2083	  )
2084	{
2085	    dbus_mgr_log_err("Invalid ip_address value received from dhcdbd");
2086	    return;
2087	}
2088	dbus_mgr_log_dbg("ip-address: %s", inet_ntop(AF_INET, value, error_name, 16));
2089	d_if->ip = *((struct in_addr*)value);
2090
2091    }else
2092    if( strcmp(member, "subnet_mask") == 0 )
2093    {
2094	if( (!dbus_svc_get_args( dbus, msg,
2095				 TYPE_STRING, &opt_name,
2096				 TYPE_ARRAY, TYPE_BYTE, &value, &length,
2097				 TYPE_INVALID
2098		               )
2099	    )
2100	  ||( value == 0L)
2101	  ||( length != sizeof(struct in_addr) )
2102	  )
2103	{
2104	    dbus_mgr_log_err("Invalid subnet_mask value received from dhcdbd");
2105	    return;
2106	}
2107	dbus_mgr_log_dbg("subnet-mask: %s", inet_ntop(AF_INET, value, error_name, 16));
2108	d_if->subnet_mask = *((struct in_addr*)value);
2109    }
2110}
2111
2112static
2113dbus_svc_HandlerResult
2114dbus_mgr_message_handler
2115(
2116    DBusMsgHandlerArgs
2117)
2118{
2119    char error_name[1024], error_message[1024];
2120    ns_dbus_mgr_t *mgr = object;
2121    uint32_t new_serial;
2122
2123    if_suffix = prefix = suffix = prefixObject = 0L;
2124
2125    dbus_mgr_log_dbg("D-BUS message: %u %u %u %s %s %s %s %s %s",
2126		     type, reply_expected, serial, destination, path, member, interface, sender, signature
2127	            );
2128
2129    if (  ( type == SIGNAL )
2130	&&( strcmp(path,"/org/freedesktop/DBus/Local") == 0 )
2131       )
2132    {
2133	if( strcmp(member,"Disconnected") == 0 )
2134	    dbus_mgr_dbus_shutdown_handler( mgr );
2135    }else
2136    if( ( type == SIGNAL )
2137      &&( strcmp(path,"/org/freedesktop/DBus") == 0 )
2138      &&(strcmp(member,"NameOwnerChanged") == 0)
2139      &&(strcmp(signature, "sss") == 0)
2140      )
2141    {
2142	dbus_mgr_check_dhcdbd_state( mgr, msg );
2143    }else
2144    if( ( type == SIGNAL )
2145      &&( (sender != 0L) && (mgr->dhcdbd_name != 0L) && (strcmp(sender,mgr->dhcdbd_name)   == 0))
2146      &&( strcmp(interface,"com.redhat.dhcp.subscribe.binary") == 0 )
2147      )
2148    {
2149	dbus_mgr_handle_dhcdbd_message( mgr, path, member, msg );
2150    }else
2151    if( (type == CALL)
2152      &&( strcmp(destination, DBUSMGR_DESTINATION)==0)
2153      &&( strcmp(path, DBUSMGR_OBJECT_PATH)==0)
2154      )
2155    {
2156	if( strcmp(member, "SetForwarders") == 0 )
2157	    dbus_mgr_handle_set_forwarders
2158	    ( mgr, dbus, reply_expected, serial, path, member, interface, sender, msg );
2159	else
2160	if( strcmp(member, "GetForwarders") == 0 )
2161	{
2162	    if( *signature != '\0' )
2163		dbus_mgr_handle_get_forwarders
2164		( dbus, reply_expected, serial, path, member, interface, sender, msg );
2165	    else
2166		dbus_mgr_handle_list_forwarders
2167		( dbus, reply_expected, serial, path, member, interface, sender, msg );
2168	}else
2169	if( reply_expected )
2170	{
2171	    sprintf(error_name, "InvalidOperation");
2172	    sprintf(error_message, "Unrecognized path / interface / member");
2173	    dbus_svc_send( dbus, ERROR, serial, &new_serial, sender, path, interface, member,
2174			   TYPE_STRING, error_name, TYPE_STRING, error_message, TYPE_INVALID
2175		);
2176	}
2177    }
2178    return HANDLED;
2179}
2180
2181static void
2182dbus_mgr_read_watch_activated(isc_task_t *t, isc_event_t *ev)
2183{
2184    DBusMgrSocket *sfd = (DBusMgrSocket*)(ev->ev_arg);
2185    t = t;
2186    isc_mem_put(sfd->mgr->mctx, ev, ev->ev_size);
2187    dbus_mgr_log_dbg("watch %d READ",sfd->fd);
2188    isc_socket_fd_handle_reads( sfd->sock, sfd->ser );
2189    dbus_svc_handle_watch( sfd->mgr->dbus, sfd->fd, WATCH_ENABLE | WATCH_READ );
2190}
2191
2192static void
2193dbus_mgr_write_watch_activated(isc_task_t *t, isc_event_t *ev)
2194{
2195    DBusMgrSocket *sfd = (DBusMgrSocket*)(ev->ev_arg);
2196    t = t;
2197    isc_mem_put(sfd->mgr->mctx, ev, ev->ev_size);
2198    dbus_mgr_log_dbg("watch %d WRITE",sfd->fd);
2199    isc_socket_fd_handle_writes( sfd->sock, sfd->ser );
2200    dbus_svc_handle_watch( sfd->mgr->dbus, sfd->fd, WATCH_ENABLE | WATCH_WRITE );
2201}
2202
2203static void
2204dbus_mgr_watches_selected(isc_task_t *t, isc_event_t *ev)
2205{
2206    ns_dbus_mgr_t *mgr = (ns_dbus_mgr_t*)(ev->ev_arg);
2207    t = t;
2208    isc_mem_put(mgr->mctx, ev, ev->ev_size);
2209    if( ( mgr->dbus == 0L ) || (mgr->sockets == 0L))
2210    {
2211	return;
2212    }
2213    dbus_mgr_log_dbg("watches selected");
2214    dbus_svc_dispatch( mgr->dbus );
2215    dbus_mgr_log_dbg("dispatch complete");
2216}
2217
2218static int dbus_mgr_socket_comparator( const void *p1, const void *p2 )
2219{
2220    return( (   ((const DBusMgrSocket*)p1)->fd
2221	     == ((const DBusMgrSocket*)p2)->fd
2222	    ) ? 0
2223	      : (   ((const DBusMgrSocket*)p1)->fd
2224	          > ((const DBusMgrSocket*)p2)->fd
2225	        ) ? 1
2226	          : -1
2227	  );
2228}
2229
2230static void
2231dbus_mgr_watch_handler( int fd, dbus_svc_WatchFlags flags, void *mgrp )
2232{
2233    ns_dbus_mgr_t *mgr = mgrp;
2234    DBusMgrSocket sockFd, *sfd=0L, *const*spp=0L;
2235    isc_result_t  result=ISC_R_SUCCESS;
2236    isc_socketevent_t *sev;
2237    isc_event_t *pev[1];
2238
2239    if(mgr == 0L)
2240	return;
2241
2242    if( (flags & 7) == WATCH_ERROR )
2243	return;
2244
2245    sockFd.fd = fd;
2246
2247    dbus_mgr_log_dbg("watch handler: fd %d %d", fd, flags);
2248
2249    if( ((spp = tfind( &sockFd, &(mgr->sockets), dbus_mgr_socket_comparator) ) == 0L )
2250      ||((sfd = *spp) == 0L )
2251      )
2252    {
2253	if( ( flags & WATCH_ENABLE ) == 0 )
2254	    return;
2255
2256	sfd = isc_mem_get(mgr->mctx, sizeof(DBusMgrSocket));
2257	if( sfd == 0L )
2258	{
2259	    dbus_mgr_log_err("dbus_mgr: out of memory" );
2260	    return;
2261	}
2262	sfd->fd = fd;
2263	sfd->mgr = mgr;
2264	sfd->ser = sfd->sew = sfd->sel = 0L;
2265
2266	if( tsearch(sfd, &(mgr->sockets), dbus_mgr_socket_comparator) == 0L )
2267	{
2268	    dbus_mgr_log_err("dbus_mgr: out of memory" );
2269	    isc_mem_put(mgr->mctx, sfd, sizeof(DBusMgrSocket));
2270	    return;
2271	}
2272	sfd->sock = 0L;
2273	result = isc_socket_create( mgr->socketmgr, fd, isc_sockettype_fd, &(sfd->sock) );
2274	if( result != ISC_R_SUCCESS )
2275	{
2276	    dbus_mgr_log_err("dbus_mgr: isc_socket_create failed: %s",
2277			     isc_result_totext(result)
2278	                    );
2279	    tdelete(sfd,  &(mgr->sockets), dbus_mgr_socket_comparator);
2280	    isc_mem_put(mgr->mctx, sfd, sizeof(DBusMgrSocket));
2281	    return;
2282	}
2283    }
2284
2285    if( (flags & WATCH_ENABLE) == WATCH_ENABLE )
2286    {
2287	if( (flags & WATCH_READ) == WATCH_READ )
2288	{
2289	    if( sfd->ser == 0L )
2290	    {
2291		sfd->ser = (isc_socketevent_t *)
2292		    isc_event_allocate
2293		    (
2294			mgr->mctx, mgr->task,
2295			ISC_SOCKEVENT_READ_READY,
2296			dbus_mgr_read_watch_activated,
2297			sfd,
2298			sizeof(isc_socketevent_t)
2299		    );
2300
2301		if( sfd->ser == 0L )
2302		{
2303		    dbus_mgr_log_err("dbus_mgr: out of memory" );
2304		    tdelete(sfd,  &(mgr->sockets), dbus_mgr_socket_comparator);
2305		    isc_mem_put(mgr->mctx, sfd, sizeof(DBusMgrSocket));
2306		    return;
2307		}
2308
2309		sev = isc_socket_fd_handle_reads(sfd->sock, sfd->ser );
2310
2311	    }else
2312	    {
2313		sev = isc_socket_fd_handle_reads(sfd->sock, sfd->ser );
2314	    }
2315	}
2316	if( (flags & WATCH_WRITE) == WATCH_WRITE )
2317	{
2318	    if( sfd->sew == 0L )
2319	    {
2320		sfd->sew = (isc_socketevent_t *)
2321		    isc_event_allocate
2322		    (
2323			mgr->mctx, mgr->task,
2324			ISC_SOCKEVENT_WRITE_READY,
2325			dbus_mgr_write_watch_activated,
2326			sfd,
2327			sizeof(isc_socketevent_t)
2328		    );
2329		if( sfd->sew == 0L )
2330		{
2331		    dbus_mgr_log_err("dbus_mgr: out of memory" );
2332		    tdelete(sfd,  &(mgr->sockets), dbus_mgr_socket_comparator);
2333		    isc_mem_put(mgr->mctx, sfd, sizeof(DBusMgrSocket));
2334		    return;
2335		}
2336
2337		sev = isc_socket_fd_handle_writes(sfd->sock, sfd->sew );
2338
2339	    }else
2340	    {
2341		sev = isc_socket_fd_handle_writes(sfd->sock, sfd->sew );
2342	    }
2343	}
2344	if( (sfd->ser != 0L) || (sfd->sew != 0L) )
2345	{
2346	    if( sfd->sel == 0L )
2347	    {
2348		sfd->sel = (isc_socketevent_t *)
2349		    isc_event_allocate
2350		    (
2351			mgr->mctx, mgr->task,
2352			ISC_SOCKEVENT_SELECTED,
2353			dbus_mgr_watches_selected,
2354			mgr,
2355			sizeof(isc_socketevent_t)
2356		    );
2357		if( sfd->sel == 0L )
2358		{
2359		    dbus_mgr_log_err("dbus_mgr: out of memory" );
2360		    tdelete(sfd,  &(mgr->sockets), dbus_mgr_socket_comparator);
2361		    isc_mem_put(mgr->mctx, sfd, sizeof(DBusMgrSocket));
2362		    return;
2363		}
2364
2365		sev = isc_socket_fd_handle_selected(sfd->sock, sfd->sel );
2366
2367	    }else
2368	    {
2369		sev = isc_socket_fd_handle_selected(sfd->sock, sfd->sel);
2370	    }
2371	}
2372    }else
2373    {
2374	dbus_mgr_log_dbg("watch %d disabled",fd);
2375	if(flags & WATCH_READ)
2376	{
2377	    sev = isc_socket_fd_handle_reads( sfd->sock, 0L );
2378	    if( sev != 0L )
2379	    {
2380		pev[0]=(isc_event_t*)sev;
2381		isc_event_free(pev);
2382	    }
2383	    sfd->ser = 0L;
2384	}
2385
2386	if( flags & WATCH_WRITE )
2387	{
2388	    sev = isc_socket_fd_handle_writes( sfd->sock, 0L );
2389	    if( sev != 0L )
2390	    {
2391		pev[0]=(isc_event_t*)sev;
2392		isc_event_free(pev);
2393	    }
2394	    sfd->sew = 0L;
2395	}
2396
2397	if( (sfd->ser == 0L) && (sfd->sew == 0L) )
2398	{
2399	    sev = isc_socket_fd_handle_selected( sfd->sock, 0L );
2400	    if( sev != 0L )
2401	    {
2402		pev[0]=(isc_event_t*)sev;
2403		isc_event_free(pev);
2404	    }
2405	    sfd->sel = 0L;
2406
2407	    tdelete(sfd, &(mgr->sockets), dbus_mgr_socket_comparator);
2408
2409	    isc_mem_put(mgr->mctx, sfd,  sizeof(DBusMgrSocket));
2410	}
2411    }
2412}
2413
2414static
2415void dbus_mgr_close_socket( const void *p, const VISIT which, const int level)
2416{
2417    DBusMgrSocket *const*spp=p, *sfd;
2418    isc_event_t *ev ;
2419    int i =  level ? 0 :1;
2420    i &= i;
2421
2422    if( (spp==0L) || ((sfd = *spp)==0L)
2423      ||((which != leaf) && (which != postorder))
2424      ) return;
2425
2426    if( sfd->ser != 0L )
2427    {
2428	ev = (isc_event_t *)isc_socket_fd_handle_reads(sfd->sock, 0);
2429	if( ev != 0L )
2430	    isc_event_free((isc_event_t **)&ev);
2431	sfd->ser = 0L;
2432    }
2433
2434    if( sfd->sew != 0L )
2435    {
2436	ev = (isc_event_t *)isc_socket_fd_handle_writes(sfd->sock, 0);
2437	if( ev != 0L )
2438	    isc_event_free((isc_event_t **)&ev);
2439	sfd->sew = 0L;
2440    }
2441
2442    if( sfd->sel != 0L )
2443    {
2444	ev = (isc_event_t *)isc_socket_fd_handle_selected(sfd->sock, 0);
2445	if( ev != 0L )
2446	    isc_event_free((isc_event_t **)&ev);
2447	sfd->sel = 0L;
2448	dbus_mgr_log_dbg("CLOSED socket %d", sfd->fd);
2449    }
2450}
2451
2452static
2453void dbus_mgr_destroy_socket( void *p )
2454{
2455    DBusMgrSocket *sfd = p;
2456
2457    isc_mem_put( sfd->mgr->mctx, sfd, sizeof(DBusMgrSocket) );
2458}
2459