File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / dbus.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:56:46 2021 UTC (3 years, 4 months ago) by misho
Branches: elwix, dnsmasq, MAIN
CVS tags: v2_84, HEAD
dnsmasq 2.84

    1: /* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
    2: 
    3:    This program is free software; you can redistribute it and/or modify
    4:    it under the terms of the GNU General Public License as published by
    5:    the Free Software Foundation; version 2 dated June, 1991, or
    6:    (at your option) version 3 dated 29 June, 2007.
    7:  
    8:    This program is distributed in the hope that it will be useful,
    9:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   10:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   11:    GNU General Public License for more details.
   12:      
   13:    You should have received a copy of the GNU General Public License
   14:    along with this program.  If not, see <http://www.gnu.org/licenses/>.
   15: */
   16: 
   17: #include "dnsmasq.h"
   18: 
   19: #ifdef HAVE_DBUS
   20: 
   21: #include <dbus/dbus.h>
   22: 
   23: const char* introspection_xml_template =
   24: "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
   25: "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
   26: "<node name=\"" DNSMASQ_PATH "\">\n"
   27: "  <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
   28: "    <method name=\"Introspect\">\n"
   29: "      <arg name=\"data\" direction=\"out\" type=\"s\"/>\n"
   30: "    </method>\n"
   31: "  </interface>\n"
   32: "  <interface name=\"%s\">\n"
   33: "    <method name=\"ClearCache\">\n"
   34: "    </method>\n"
   35: "    <method name=\"GetVersion\">\n"
   36: "      <arg name=\"version\" direction=\"out\" type=\"s\"/>\n"
   37: "    </method>\n"
   38: #ifdef HAVE_LOOP
   39: "    <method name=\"GetLoopServers\">\n"
   40: "      <arg name=\"server\" direction=\"out\" type=\"as\"/>\n"
   41: "    </method>\n"
   42: #endif
   43: "    <method name=\"SetServers\">\n"
   44: "      <arg name=\"servers\" direction=\"in\" type=\"av\"/>\n"
   45: "    </method>\n"
   46: "    <method name=\"SetDomainServers\">\n"
   47: "      <arg name=\"servers\" direction=\"in\" type=\"as\"/>\n"
   48: "    </method>\n"
   49: "    <method name=\"SetServersEx\">\n"
   50: "      <arg name=\"servers\" direction=\"in\" type=\"aas\"/>\n"
   51: "    </method>\n"
   52: "    <method name=\"SetFilterWin2KOption\">\n"
   53: "      <arg name=\"filterwin2k\" direction=\"in\" type=\"b\"/>\n"
   54: "    </method>\n"
   55: "    <method name=\"SetBogusPrivOption\">\n"
   56: "      <arg name=\"boguspriv\" direction=\"in\" type=\"b\"/>\n"
   57: "    </method>\n"
   58: "    <signal name=\"DhcpLeaseAdded\">\n"
   59: "      <arg name=\"ipaddr\" type=\"s\"/>\n"
   60: "      <arg name=\"hwaddr\" type=\"s\"/>\n"
   61: "      <arg name=\"hostname\" type=\"s\"/>\n"
   62: "    </signal>\n"
   63: "    <signal name=\"DhcpLeaseDeleted\">\n"
   64: "      <arg name=\"ipaddr\" type=\"s\"/>\n"
   65: "      <arg name=\"hwaddr\" type=\"s\"/>\n"
   66: "      <arg name=\"hostname\" type=\"s\"/>\n"
   67: "    </signal>\n"
   68: "    <signal name=\"DhcpLeaseUpdated\">\n"
   69: "      <arg name=\"ipaddr\" type=\"s\"/>\n"
   70: "      <arg name=\"hwaddr\" type=\"s\"/>\n"
   71: "      <arg name=\"hostname\" type=\"s\"/>\n"
   72: "    </signal>\n"
   73: #ifdef HAVE_DHCP
   74: "    <method name=\"AddDhcpLease\">\n"
   75: "       <arg name=\"ipaddr\" type=\"s\"/>\n"
   76: "       <arg name=\"hwaddr\" type=\"s\"/>\n"
   77: "       <arg name=\"hostname\" type=\"ay\"/>\n"
   78: "       <arg name=\"clid\" type=\"ay\"/>\n"
   79: "       <arg name=\"lease_duration\" type=\"u\"/>\n"
   80: "       <arg name=\"ia_id\" type=\"u\"/>\n"
   81: "       <arg name=\"is_temporary\" type=\"b\"/>\n"
   82: "    </method>\n"
   83: "    <method name=\"DeleteDhcpLease\">\n"
   84: "       <arg name=\"ipaddr\" type=\"s\"/>\n"
   85: "       <arg name=\"success\" type=\"b\" direction=\"out\"/>\n"
   86: "    </method>\n"
   87: #endif
   88: "    <method name=\"GetMetrics\">\n"
   89: "      <arg name=\"metrics\" direction=\"out\" type=\"a{su}\"/>\n"
   90: "    </method>\n"
   91: "  </interface>\n"
   92: "</node>\n";
   93: 
   94: static char *introspection_xml = NULL;
   95: 
   96: struct watch {
   97:   DBusWatch *watch;      
   98:   struct watch *next;
   99: };
  100: 
  101: 
  102: static dbus_bool_t add_watch(DBusWatch *watch, void *data)
  103: {
  104:   struct watch *w;
  105: 
  106:   for (w = daemon->watches; w; w = w->next)
  107:     if (w->watch == watch)
  108:       return TRUE;
  109: 
  110:   if (!(w = whine_malloc(sizeof(struct watch))))
  111:     return FALSE;
  112: 
  113:   w->watch = watch;
  114:   w->next = daemon->watches;
  115:   daemon->watches = w;
  116: 
  117:   w = data; /* no warning */
  118:   return TRUE;
  119: }
  120: 
  121: static void remove_watch(DBusWatch *watch, void *data)
  122: {
  123:   struct watch **up, *w, *tmp;  
  124:   
  125:   for (up = &(daemon->watches), w = daemon->watches; w; w = tmp)
  126:     {
  127:       tmp = w->next;
  128:       if (w->watch == watch)
  129: 	{
  130: 	  *up = tmp;
  131: 	  free(w);
  132: 	}
  133:       else
  134: 	up = &(w->next);
  135:     }
  136: 
  137:   w = data; /* no warning */
  138: }
  139: 
  140: static void dbus_read_servers(DBusMessage *message)
  141: {
  142:   DBusMessageIter iter;
  143:   union  mysockaddr addr, source_addr;
  144:   char *domain;
  145:   
  146:   dbus_message_iter_init(message, &iter);
  147: 
  148:   mark_servers(SERV_FROM_DBUS);
  149:   
  150:   while (1)
  151:     {
  152:       int skip = 0;
  153: 
  154:       if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_UINT32)
  155: 	{
  156: 	  u32 a;
  157: 	  
  158: 	  dbus_message_iter_get_basic(&iter, &a);
  159: 	  dbus_message_iter_next (&iter);
  160: 	  
  161: #ifdef HAVE_SOCKADDR_SA_LEN
  162: 	  source_addr.in.sin_len = addr.in.sin_len = sizeof(struct sockaddr_in);
  163: #endif
  164: 	  addr.in.sin_addr.s_addr = ntohl(a);
  165: 	  source_addr.in.sin_family = addr.in.sin_family = AF_INET;
  166: 	  addr.in.sin_port = htons(NAMESERVER_PORT);
  167: 	  source_addr.in.sin_addr.s_addr = INADDR_ANY;
  168: 	  source_addr.in.sin_port = htons(daemon->query_port);
  169: 	}
  170:       else if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_BYTE)
  171: 	{
  172: 	  unsigned char p[sizeof(struct in6_addr)];
  173: 	  unsigned int i;
  174: 
  175: 	  skip = 1;
  176: 
  177: 	  for(i = 0; i < sizeof(struct in6_addr); i++)
  178: 	    {
  179: 	      dbus_message_iter_get_basic(&iter, &p[i]);
  180: 	      dbus_message_iter_next (&iter);
  181: 	      if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BYTE)
  182: 		{
  183: 		  i++;
  184: 		  break;
  185: 		}
  186: 	    }
  187: 
  188: 	  if (i == sizeof(struct in6_addr))
  189: 	    {
  190: 	      memcpy(&addr.in6.sin6_addr, p, sizeof(struct in6_addr));
  191: #ifdef HAVE_SOCKADDR_SA_LEN
  192:               source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(struct sockaddr_in6);
  193: #endif
  194:               source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
  195:               addr.in6.sin6_port = htons(NAMESERVER_PORT);
  196:               source_addr.in6.sin6_flowinfo = addr.in6.sin6_flowinfo = 0;
  197: 	      source_addr.in6.sin6_scope_id = addr.in6.sin6_scope_id = 0;
  198:               source_addr.in6.sin6_addr = in6addr_any;
  199:               source_addr.in6.sin6_port = htons(daemon->query_port);
  200: 	      skip = 0;
  201: 	    }
  202: 	}
  203:       else
  204: 	/* At the end */
  205: 	break;
  206:       
  207:       /* process each domain */
  208:       do {
  209: 	if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING)
  210: 	  {
  211: 	    dbus_message_iter_get_basic(&iter, &domain);
  212: 	    dbus_message_iter_next (&iter);
  213: 	  }
  214: 	else
  215: 	  domain = NULL;
  216: 	
  217: 	if (!skip)
  218: 	  add_update_server(SERV_FROM_DBUS, &addr, &source_addr, NULL, domain);
  219:      
  220:       } while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING); 
  221:     }
  222:    
  223:   /* unlink and free anything still marked. */
  224:   cleanup_servers();
  225: }
  226: 
  227: #ifdef HAVE_LOOP
  228: static DBusMessage *dbus_reply_server_loop(DBusMessage *message)
  229: {
  230:   DBusMessageIter args, args_iter;
  231:   struct server *serv;
  232:   DBusMessage *reply = dbus_message_new_method_return(message);
  233:    
  234:   dbus_message_iter_init_append (reply, &args);
  235:   dbus_message_iter_open_container (&args, DBUS_TYPE_ARRAY,DBUS_TYPE_STRING_AS_STRING, &args_iter);
  236: 
  237:   for (serv = daemon->servers; serv; serv = serv->next)
  238:     if (serv->flags & SERV_LOOP)
  239:       {
  240: 	(void)prettyprint_addr(&serv->addr, daemon->addrbuff);
  241: 	dbus_message_iter_append_basic (&args_iter, DBUS_TYPE_STRING, &daemon->addrbuff);
  242:       }
  243:   
  244:   dbus_message_iter_close_container (&args, &args_iter);
  245: 
  246:   return reply;
  247: }
  248: #endif
  249: 
  250: static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
  251: {
  252:   DBusMessageIter iter, array_iter, string_iter;
  253:   DBusMessage *error = NULL;
  254:   const char *addr_err;
  255:   char *dup = NULL;
  256:   
  257:   if (!dbus_message_iter_init(message, &iter))
  258:     {
  259:       return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  260:                                     "Failed to initialize dbus message iter");
  261:     }
  262: 
  263:   /* check that the message contains an array of arrays */
  264:   if ((dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) ||
  265:       (dbus_message_iter_get_element_type(&iter) != (strings ? DBUS_TYPE_STRING : DBUS_TYPE_ARRAY)))
  266:     {
  267:       return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  268:                                     strings ? "Expected array of string" : "Expected array of string arrays");
  269:      }
  270:  
  271:   mark_servers(SERV_FROM_DBUS);
  272: 
  273:   /* array_iter points to each "as" element in the outer array */
  274:   dbus_message_iter_recurse(&iter, &array_iter);
  275:   while (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_INVALID)
  276:     {
  277:       const char *str = NULL;
  278:       union  mysockaddr addr, source_addr;
  279:       int flags = 0;
  280:       char interface[IF_NAMESIZE];
  281:       char *str_addr, *str_domain = NULL;
  282: 
  283:       if (strings)
  284: 	{
  285: 	  dbus_message_iter_get_basic(&array_iter, &str);
  286: 	  if (!str || !strlen (str))
  287: 	    {
  288: 	      error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  289: 					     "Empty string");
  290: 	      break;
  291: 	    }
  292: 	  
  293: 	  /* dup the string because it gets modified during parsing */
  294: 	  if (dup)
  295: 	    free(dup);
  296: 	  if (!(dup = str_domain = whine_malloc(strlen(str)+1)))
  297: 	    break;
  298: 	  
  299: 	  strcpy(str_domain, str);
  300: 
  301: 	  /* point to address part of old string for error message */
  302: 	  if ((str_addr = strrchr(str, '/')))
  303: 	    str = str_addr+1;
  304: 	  
  305: 	  if ((str_addr = strrchr(str_domain, '/')))
  306: 	    {
  307: 	      if (*str_domain != '/' || str_addr == str_domain)
  308: 		{
  309: 		  error = dbus_message_new_error_printf(message,
  310: 							DBUS_ERROR_INVALID_ARGS,
  311: 							"No domain terminator '%s'",
  312: 							str);
  313: 		  break;
  314: 		}
  315: 	      *str_addr++ = 0;
  316: 	      str_domain++;
  317: 	    }
  318: 	  else
  319: 	    {
  320: 	      str_addr = str_domain;
  321: 	      str_domain = NULL;
  322: 	    }
  323: 
  324: 	  
  325: 	}
  326:       else
  327: 	{
  328: 	  /* check the types of the struct and its elements */
  329: 	  if ((dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY) ||
  330: 	      (dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_STRING))
  331: 	    {
  332: 	      error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  333: 					     "Expected inner array of strings");
  334: 	      break;
  335: 	    }
  336: 	  
  337: 	  /* string_iter points to each "s" element in the inner array */
  338: 	  dbus_message_iter_recurse(&array_iter, &string_iter);
  339: 	  if (dbus_message_iter_get_arg_type(&string_iter) != DBUS_TYPE_STRING)
  340: 	    {
  341: 	      /* no IP address given */
  342: 	      error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  343: 					     "Expected IP address");
  344: 	      break;
  345: 	    }
  346: 	  
  347: 	  dbus_message_iter_get_basic(&string_iter, &str);
  348: 	  if (!str || !strlen (str))
  349: 	    {
  350: 	      error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  351: 					     "Empty IP address");
  352: 	      break;
  353: 	    }
  354: 	  
  355: 	  /* dup the string because it gets modified during parsing */
  356: 	  if (dup)
  357: 	    free(dup);
  358: 	  if (!(dup = str_addr = whine_malloc(strlen(str)+1)))
  359: 	    break;
  360: 	  
  361: 	  strcpy(str_addr, str);
  362: 	}
  363: 
  364:       memset(&addr, 0, sizeof(addr));
  365:       memset(&source_addr, 0, sizeof(source_addr));
  366:       memset(&interface, 0, sizeof(interface));
  367: 
  368:       /* parse the IP address */
  369:       if ((addr_err = parse_server(str_addr, &addr, &source_addr, (char *) &interface, &flags)))
  370: 	{
  371:           error = dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
  372:                                                 "Invalid IP address '%s': %s",
  373:                                                 str, addr_err);
  374:           break;
  375:         }
  376:       
  377:       /* 0.0.0.0 for server address == NULL, for Dbus */
  378:       if (addr.in.sin_family == AF_INET &&
  379:           addr.in.sin_addr.s_addr == 0)
  380:         flags |= SERV_NO_ADDR;
  381:       
  382:       if (strings)
  383: 	{
  384: 	  char *p;
  385: 	  
  386: 	  do {
  387: 	    if (str_domain)
  388: 	      {
  389: 		if ((p = strchr(str_domain, '/')))
  390: 		  *p++ = 0;
  391: 	      }
  392: 	    else 
  393: 	      p = NULL;
  394: 	    
  395: 	    add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str_domain);
  396: 	  } while ((str_domain = p));
  397: 	}
  398:       else
  399: 	{
  400: 	  /* jump past the address to the domain list (if any) */
  401: 	  dbus_message_iter_next (&string_iter);
  402: 	  
  403: 	  /* parse domains and add each server/domain pair to the list */
  404: 	  do {
  405: 	    str = NULL;
  406: 	    if (dbus_message_iter_get_arg_type(&string_iter) == DBUS_TYPE_STRING)
  407: 	      dbus_message_iter_get_basic(&string_iter, &str);
  408: 	    dbus_message_iter_next (&string_iter);
  409: 	    
  410: 	    add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str);
  411: 	  } while (dbus_message_iter_get_arg_type(&string_iter) == DBUS_TYPE_STRING);
  412: 	}
  413: 	 
  414:       /* jump to next element in outer array */
  415:       dbus_message_iter_next(&array_iter);
  416:     }
  417: 
  418:   cleanup_servers();
  419: 
  420:   if (dup)
  421:     free(dup);
  422: 
  423:   return error;
  424: }
  425: 
  426: static DBusMessage *dbus_set_bool(DBusMessage *message, int flag, char *name)
  427: {
  428:   DBusMessageIter iter;
  429:   dbus_bool_t enabled;
  430: 
  431:   if (!dbus_message_iter_init(message, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
  432:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, "Expected boolean argument");
  433:   
  434:   dbus_message_iter_get_basic(&iter, &enabled);
  435: 
  436:   if (enabled)
  437:     { 
  438:       my_syslog(LOG_INFO, _("Enabling --%s option from D-Bus"), name);
  439:       set_option_bool(flag);
  440:     }
  441:   else
  442:     {
  443:       my_syslog(LOG_INFO, _("Disabling --%s option from D-Bus"), name);
  444:       reset_option_bool(flag);
  445:     }
  446: 
  447:   return NULL;
  448: }
  449: 
  450: #ifdef HAVE_DHCP
  451: static DBusMessage *dbus_add_lease(DBusMessage* message)
  452: {
  453:   struct dhcp_lease *lease;
  454:   const char *ipaddr, *hwaddr, *hostname, *tmp;
  455:   const unsigned char* clid;
  456:   int clid_len, hostname_len, hw_len, hw_type;
  457:   dbus_uint32_t expires, ia_id;
  458:   dbus_bool_t is_temporary;
  459:   union all_addr addr;
  460:   time_t now = dnsmasq_time();
  461:   unsigned char dhcp_chaddr[DHCP_CHADDR_MAX];
  462: 
  463:   DBusMessageIter iter, array_iter;
  464:   if (!dbus_message_iter_init(message, &iter))
  465:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  466: 				  "Failed to initialize dbus message iter");
  467: 
  468:   if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
  469:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  470: 				  "Expected string as first argument");
  471: 
  472:   dbus_message_iter_get_basic(&iter, &ipaddr);
  473:   dbus_message_iter_next(&iter);
  474: 
  475:   if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
  476:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  477: 				  "Expected string as second argument");
  478:     
  479:   dbus_message_iter_get_basic(&iter, &hwaddr);
  480:   dbus_message_iter_next(&iter);
  481: 
  482:   if ((dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) ||
  483:       (dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE))
  484:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  485: 				  "Expected byte array as third argument");
  486:     
  487:   dbus_message_iter_recurse(&iter, &array_iter);
  488:   dbus_message_iter_get_fixed_array(&array_iter, &hostname, &hostname_len);
  489:   tmp = memchr(hostname, '\0', hostname_len);
  490:   if (tmp)
  491:     {
  492:       if (tmp == &hostname[hostname_len - 1])
  493: 	hostname_len--;
  494:       else
  495: 	return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  496: 				      "Hostname contains an embedded NUL character");
  497:     }
  498:   dbus_message_iter_next(&iter);
  499: 
  500:   if ((dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) ||
  501:       (dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE))
  502:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  503: 				  "Expected byte array as fourth argument");
  504: 
  505:   dbus_message_iter_recurse(&iter, &array_iter);
  506:   dbus_message_iter_get_fixed_array(&array_iter, &clid, &clid_len);
  507:   dbus_message_iter_next(&iter);
  508: 
  509:   if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
  510:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  511: 				  "Expected uint32 as fifth argument");
  512:     
  513:   dbus_message_iter_get_basic(&iter, &expires);
  514:   dbus_message_iter_next(&iter);
  515: 
  516:   if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
  517:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  518:                                     "Expected uint32 as sixth argument");
  519:   
  520:   dbus_message_iter_get_basic(&iter, &ia_id);
  521:   dbus_message_iter_next(&iter);
  522: 
  523:   if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
  524:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  525: 				  "Expected uint32 as sixth argument");
  526: 
  527:   dbus_message_iter_get_basic(&iter, &is_temporary);
  528: 
  529:   if (inet_pton(AF_INET, ipaddr, &addr.addr4))
  530:     {
  531:       if (ia_id != 0 || is_temporary)
  532: 	return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  533: 				      "ia_id and is_temporary must be zero for IPv4 lease");
  534:       
  535:       if (!(lease = lease_find_by_addr(addr.addr4)))
  536:     	lease = lease4_allocate(addr.addr4);
  537:     }
  538: #ifdef HAVE_DHCP6
  539:   else if (inet_pton(AF_INET6, ipaddr, &addr.addr6))
  540:     {
  541:       if (!(lease = lease6_find_by_addr(&addr.addr6, 128, 0)))
  542: 	lease = lease6_allocate(&addr.addr6,
  543: 				is_temporary ? LEASE_TA : LEASE_NA);
  544:       lease_set_iaid(lease, ia_id);
  545:     }
  546: #endif
  547:   else
  548:     return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
  549: 					 "Invalid IP address '%s'", ipaddr);
  550:    
  551:   hw_len = parse_hex((char*)hwaddr, dhcp_chaddr, DHCP_CHADDR_MAX, NULL, &hw_type);
  552:   if (hw_type == 0 && hw_len != 0)
  553:     hw_type = ARPHRD_ETHER;
  554:   
  555:   lease_set_hwaddr(lease, dhcp_chaddr, clid, hw_len, hw_type,
  556:                    clid_len, now, 0);
  557:   lease_set_expires(lease, expires, now);
  558:   if (hostname_len != 0)
  559:     lease_set_hostname(lease, hostname, 0, get_domain(lease->addr), NULL);
  560:   
  561:   lease_update_file(now);
  562:   lease_update_dns(0);
  563: 
  564:   return NULL;
  565: }
  566: 
  567: static DBusMessage *dbus_del_lease(DBusMessage* message)
  568: {
  569:   struct dhcp_lease *lease;
  570:   DBusMessageIter iter;
  571:   const char *ipaddr;
  572:   DBusMessage *reply;
  573:   union all_addr addr;
  574:   dbus_bool_t ret = 1;
  575:   time_t now = dnsmasq_time();
  576: 
  577:   if (!dbus_message_iter_init(message, &iter))
  578:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  579: 				  "Failed to initialize dbus message iter");
  580:    
  581:   if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
  582:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  583: 				  "Expected string as first argument");
  584:    
  585:   dbus_message_iter_get_basic(&iter, &ipaddr);
  586: 
  587:   if (inet_pton(AF_INET, ipaddr, &addr.addr4))
  588:     lease = lease_find_by_addr(addr.addr4);
  589: #ifdef HAVE_DHCP6
  590:   else if (inet_pton(AF_INET6, ipaddr, &addr.addr6))
  591:     lease = lease6_find_by_addr(&addr.addr6, 128, 0);
  592: #endif
  593:   else
  594:     return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
  595: 					 "Invalid IP address '%s'", ipaddr);
  596:     
  597:   if (lease)
  598:     {
  599:       lease_prune(lease, now);
  600:       lease_update_file(now);
  601:       lease_update_dns(0);
  602:     }
  603:   else
  604:     ret = 0;
  605:   
  606:   if ((reply = dbus_message_new_method_return(message)))
  607:     dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &ret,
  608: 			     DBUS_TYPE_INVALID);
  609:   
  610:     
  611:   return reply;
  612: }
  613: #endif
  614: 
  615: static DBusMessage *dbus_get_metrics(DBusMessage* message)
  616: {
  617:   DBusMessage *reply = dbus_message_new_method_return(message);
  618:   DBusMessageIter array, dict, iter;
  619:   int i;
  620: 
  621:   dbus_message_iter_init_append(reply, &iter);
  622:   dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{su}", &array);
  623: 
  624:   for (i = 0; i < __METRIC_MAX; i++) {
  625:     const char *key     = get_metric_name(i);
  626:     dbus_uint32_t value = daemon->metrics[i];
  627: 
  628:     dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, NULL, &dict);
  629:     dbus_message_iter_append_basic(&dict, DBUS_TYPE_STRING, &key);
  630:     dbus_message_iter_append_basic(&dict, DBUS_TYPE_UINT32, &value);
  631:     dbus_message_iter_close_container(&array, &dict);
  632:   }
  633: 
  634:   dbus_message_iter_close_container(&iter, &array);
  635: 
  636:   return reply;
  637: }
  638: 
  639: DBusHandlerResult message_handler(DBusConnection *connection, 
  640: 				  DBusMessage *message, 
  641: 				  void *user_data)
  642: {
  643:   char *method = (char *)dbus_message_get_member(message);
  644:   DBusMessage *reply = NULL;
  645:   int clear_cache = 0, new_servers = 0;
  646:     
  647:   if (dbus_message_is_method_call(message, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
  648:     {
  649:       /* string length: "%s" provides space for termination zero */
  650:       if (!introspection_xml && 
  651: 	  (introspection_xml = whine_malloc(strlen(introspection_xml_template) + strlen(daemon->dbus_name))))
  652: 	sprintf(introspection_xml, introspection_xml_template, daemon->dbus_name);
  653:     
  654:       if (introspection_xml)
  655: 	{
  656: 	  reply = dbus_message_new_method_return(message);
  657: 	  dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection_xml, DBUS_TYPE_INVALID);
  658: 	}
  659:     }
  660:   else if (strcmp(method, "GetVersion") == 0)
  661:     {
  662:       char *v = VERSION;
  663:       reply = dbus_message_new_method_return(message);
  664:       
  665:       dbus_message_append_args(reply, DBUS_TYPE_STRING, &v, DBUS_TYPE_INVALID);
  666:     }
  667: #ifdef HAVE_LOOP
  668:   else if (strcmp(method, "GetLoopServers") == 0)
  669:     {
  670:       reply = dbus_reply_server_loop(message);
  671:     }
  672: #endif
  673:   else if (strcmp(method, "SetServers") == 0)
  674:     {
  675:       dbus_read_servers(message);
  676:       new_servers = 1;
  677:     }
  678:   else if (strcmp(method, "SetServersEx") == 0)
  679:     {
  680:       reply = dbus_read_servers_ex(message, 0);
  681:       new_servers = 1;
  682:     }
  683:   else if (strcmp(method, "SetDomainServers") == 0)
  684:     {
  685:       reply = dbus_read_servers_ex(message, 1);
  686:       new_servers = 1;
  687:     }
  688:   else if (strcmp(method, "SetFilterWin2KOption") == 0)
  689:     {
  690:       reply = dbus_set_bool(message, OPT_FILTER, "filterwin2k");
  691:     }
  692:   else if (strcmp(method, "SetBogusPrivOption") == 0)
  693:     {
  694:       reply = dbus_set_bool(message, OPT_BOGUSPRIV, "bogus-priv");
  695:     }
  696: #ifdef HAVE_DHCP
  697:   else if (strcmp(method, "AddDhcpLease") == 0)
  698:     {
  699:       reply = dbus_add_lease(message);
  700:     }
  701:   else if (strcmp(method, "DeleteDhcpLease") == 0)
  702:     {
  703:       reply = dbus_del_lease(message);
  704:     }
  705: #endif
  706:   else if (strcmp(method, "GetMetrics") == 0)
  707:     {
  708:       reply = dbus_get_metrics(message);
  709:     }
  710:   else if (strcmp(method, "ClearCache") == 0)
  711:     clear_cache = 1;
  712:   else
  713:     return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
  714:    
  715:   if (new_servers)
  716:     {
  717:       my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
  718:       check_servers();
  719:       if (option_bool(OPT_RELOAD))
  720: 	clear_cache = 1;
  721:     }
  722: 
  723:   if (clear_cache)
  724:     clear_cache_and_reload(dnsmasq_time());
  725:   
  726:   method = user_data; /* no warning */
  727: 
  728:   /* If no reply or no error, return nothing */
  729:   if (!reply)
  730:     reply = dbus_message_new_method_return(message);
  731: 
  732:   if (reply)
  733:     {
  734:       dbus_connection_send (connection, reply, NULL);
  735:       dbus_message_unref (reply);
  736:     }
  737: 
  738:   return (DBUS_HANDLER_RESULT_HANDLED);
  739: }
  740:  
  741: 
  742: /* returns NULL or error message, may fail silently if dbus daemon not yet up. */
  743: char *dbus_init(void)
  744: {
  745:   DBusConnection *connection = NULL;
  746:   DBusObjectPathVTable dnsmasq_vtable = {NULL, &message_handler, NULL, NULL, NULL, NULL };
  747:   DBusError dbus_error;
  748:   DBusMessage *message;
  749: 
  750:   dbus_error_init (&dbus_error);
  751:   if (!(connection = dbus_bus_get (DBUS_BUS_SYSTEM, &dbus_error)))
  752:     return NULL;
  753:     
  754:   dbus_connection_set_exit_on_disconnect(connection, FALSE);
  755:   dbus_connection_set_watch_functions(connection, add_watch, remove_watch, 
  756: 				      NULL, NULL, NULL);
  757:   dbus_error_init (&dbus_error);
  758:   dbus_bus_request_name (connection, daemon->dbus_name, 0, &dbus_error);
  759:   if (dbus_error_is_set (&dbus_error))
  760:     return (char *)dbus_error.message;
  761:   
  762:   if (!dbus_connection_register_object_path(connection,  DNSMASQ_PATH, 
  763: 					    &dnsmasq_vtable, NULL))
  764:     return _("could not register a DBus message handler");
  765:   
  766:   daemon->dbus = connection; 
  767:   
  768:   if ((message = dbus_message_new_signal(DNSMASQ_PATH, daemon->dbus_name, "Up")))
  769:     {
  770:       dbus_connection_send(connection, message, NULL);
  771:       dbus_message_unref(message);
  772:     }
  773: 
  774:   return NULL;
  775: }
  776:  
  777: 
  778: void set_dbus_listeners(void)
  779: {
  780:   struct watch *w;
  781:   
  782:   for (w = daemon->watches; w; w = w->next)
  783:     if (dbus_watch_get_enabled(w->watch))
  784:       {
  785: 	unsigned int flags = dbus_watch_get_flags(w->watch);
  786: 	int fd = dbus_watch_get_unix_fd(w->watch);
  787: 	
  788: 	if (flags & DBUS_WATCH_READABLE)
  789: 	  poll_listen(fd, POLLIN);
  790: 	
  791: 	if (flags & DBUS_WATCH_WRITABLE)
  792: 	  poll_listen(fd, POLLOUT);
  793: 	
  794: 	poll_listen(fd, POLLERR);
  795:       }
  796: }
  797: 
  798: void check_dbus_listeners()
  799: {
  800:   DBusConnection *connection = (DBusConnection *)daemon->dbus;
  801:   struct watch *w;
  802: 
  803:   for (w = daemon->watches; w; w = w->next)
  804:     if (dbus_watch_get_enabled(w->watch))
  805:       {
  806: 	unsigned int flags = 0;
  807: 	int fd = dbus_watch_get_unix_fd(w->watch);
  808: 	
  809: 	if (poll_check(fd, POLLIN))
  810: 	  flags |= DBUS_WATCH_READABLE;
  811: 	
  812: 	if (poll_check(fd, POLLOUT))
  813: 	  flags |= DBUS_WATCH_WRITABLE;
  814: 	
  815: 	if (poll_check(fd, POLLERR))
  816: 	  flags |= DBUS_WATCH_ERROR;
  817: 
  818: 	if (flags != 0)
  819: 	  dbus_watch_handle(w->watch, flags);
  820:       }
  821: 
  822:   if (connection)
  823:     {
  824:       dbus_connection_ref (connection);
  825:       while (dbus_connection_dispatch (connection) == DBUS_DISPATCH_DATA_REMAINS);
  826:       dbus_connection_unref (connection);
  827:     }
  828: }
  829: 
  830: #ifdef HAVE_DHCP
  831: void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname)
  832: {
  833:   DBusConnection *connection = (DBusConnection *)daemon->dbus;
  834:   DBusMessage* message = NULL;
  835:   DBusMessageIter args;
  836:   char *action_str, *mac = daemon->namebuff;
  837:   unsigned char *p;
  838:   int i;
  839: 
  840:   if (!connection)
  841:     return;
  842:   
  843:   if (!hostname)
  844:     hostname = "";
  845:   
  846: #ifdef HAVE_DHCP6
  847:    if (lease->flags & (LEASE_TA | LEASE_NA))
  848:      {
  849:        print_mac(mac, lease->clid, lease->clid_len);
  850:        inet_ntop(AF_INET6, &lease->addr6, daemon->addrbuff, ADDRSTRLEN);
  851:      }
  852:    else
  853: #endif
  854:      {
  855:        p = extended_hwaddr(lease->hwaddr_type, lease->hwaddr_len,
  856: 			   lease->hwaddr, lease->clid_len, lease->clid, &i);
  857:        print_mac(mac, p, i);
  858:        inet_ntop(AF_INET, &lease->addr, daemon->addrbuff, ADDRSTRLEN);
  859:      }
  860: 
  861:   if (action == ACTION_DEL)
  862:     action_str = "DhcpLeaseDeleted";
  863:   else if (action == ACTION_ADD)
  864:     action_str = "DhcpLeaseAdded";
  865:   else if (action == ACTION_OLD)
  866:     action_str = "DhcpLeaseUpdated";
  867:   else
  868:     return;
  869: 
  870:   if (!(message = dbus_message_new_signal(DNSMASQ_PATH, daemon->dbus_name, action_str)))
  871:     return;
  872:   
  873:   dbus_message_iter_init_append(message, &args);
  874:   
  875:   if (dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &daemon->addrbuff) &&
  876:       dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &mac) &&
  877:       dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &hostname))
  878:     dbus_connection_send(connection, message, NULL);
  879:   
  880:   dbus_message_unref(message);
  881: }
  882: #endif
  883: 
  884: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>