Annotation of embedaddon/dnsmasq/src/dbus.c, revision 1.1.1.5

1.1.1.5 ! misho       1: /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
1.1       misho       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"
1.1.1.3   misho      38: #ifdef HAVE_LOOP
                     39: "    <method name=\"GetLoopServers\">\n"
                     40: "      <arg name=\"server\" direction=\"out\" type=\"as\"/>\n"
                     41: "    </method>\n"
                     42: #endif
1.1       misho      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"
1.1.1.3   misho      52: "    <method name=\"SetFilterWin2KOption\">\n"
                     53: "      <arg name=\"filterwin2k\" direction=\"in\" type=\"b\"/>\n"
                     54: "    </method>\n"
1.1.1.5 ! misho      55: "    <method name=\"SetLocaliseQueriesOption\">\n"
        !            56: "      <arg name=\"localise-queries\" direction=\"in\" type=\"b\"/>\n"
        !            57: "    </method>\n"
1.1.1.3   misho      58: "    <method name=\"SetBogusPrivOption\">\n"
                     59: "      <arg name=\"boguspriv\" direction=\"in\" type=\"b\"/>\n"
                     60: "    </method>\n"
1.1       misho      61: "    <signal name=\"DhcpLeaseAdded\">\n"
                     62: "      <arg name=\"ipaddr\" type=\"s\"/>\n"
                     63: "      <arg name=\"hwaddr\" type=\"s\"/>\n"
                     64: "      <arg name=\"hostname\" type=\"s\"/>\n"
                     65: "    </signal>\n"
                     66: "    <signal name=\"DhcpLeaseDeleted\">\n"
                     67: "      <arg name=\"ipaddr\" type=\"s\"/>\n"
                     68: "      <arg name=\"hwaddr\" type=\"s\"/>\n"
                     69: "      <arg name=\"hostname\" type=\"s\"/>\n"
                     70: "    </signal>\n"
                     71: "    <signal name=\"DhcpLeaseUpdated\">\n"
                     72: "      <arg name=\"ipaddr\" type=\"s\"/>\n"
                     73: "      <arg name=\"hwaddr\" type=\"s\"/>\n"
                     74: "      <arg name=\"hostname\" type=\"s\"/>\n"
                     75: "    </signal>\n"
1.1.1.3   misho      76: #ifdef HAVE_DHCP
                     77: "    <method name=\"AddDhcpLease\">\n"
                     78: "       <arg name=\"ipaddr\" type=\"s\"/>\n"
                     79: "       <arg name=\"hwaddr\" type=\"s\"/>\n"
                     80: "       <arg name=\"hostname\" type=\"ay\"/>\n"
                     81: "       <arg name=\"clid\" type=\"ay\"/>\n"
                     82: "       <arg name=\"lease_duration\" type=\"u\"/>\n"
                     83: "       <arg name=\"ia_id\" type=\"u\"/>\n"
                     84: "       <arg name=\"is_temporary\" type=\"b\"/>\n"
                     85: "    </method>\n"
                     86: "    <method name=\"DeleteDhcpLease\">\n"
                     87: "       <arg name=\"ipaddr\" type=\"s\"/>\n"
                     88: "       <arg name=\"success\" type=\"b\" direction=\"out\"/>\n"
                     89: "    </method>\n"
                     90: #endif
1.1.1.4   misho      91: "    <method name=\"GetMetrics\">\n"
                     92: "      <arg name=\"metrics\" direction=\"out\" type=\"a{su}\"/>\n"
                     93: "    </method>\n"
1.1.1.5 ! misho      94: "    <method name=\"GetServerMetrics\">\n"
        !            95: "      <arg name=\"metrics\" direction=\"out\" type=\"a{ss}\"/>\n"
        !            96: "    </method>\n"
        !            97: "    <method name=\"ClearMetrics\">\n"
        !            98: "    </method>\n"
1.1       misho      99: "  </interface>\n"
                    100: "</node>\n";
                    101: 
                    102: static char *introspection_xml = NULL;
                    103: 
                    104: struct watch {
                    105:   DBusWatch *watch;      
                    106:   struct watch *next;
                    107: };
                    108: 
                    109: 
                    110: static dbus_bool_t add_watch(DBusWatch *watch, void *data)
                    111: {
                    112:   struct watch *w;
                    113: 
                    114:   for (w = daemon->watches; w; w = w->next)
                    115:     if (w->watch == watch)
                    116:       return TRUE;
                    117: 
                    118:   if (!(w = whine_malloc(sizeof(struct watch))))
                    119:     return FALSE;
                    120: 
                    121:   w->watch = watch;
                    122:   w->next = daemon->watches;
                    123:   daemon->watches = w;
                    124: 
1.1.1.5 ! misho     125:   (void)data; /* no warning */
1.1       misho     126:   return TRUE;
                    127: }
                    128: 
                    129: static void remove_watch(DBusWatch *watch, void *data)
                    130: {
                    131:   struct watch **up, *w, *tmp;  
                    132:   
                    133:   for (up = &(daemon->watches), w = daemon->watches; w; w = tmp)
                    134:     {
                    135:       tmp = w->next;
                    136:       if (w->watch == watch)
                    137:        {
                    138:          *up = tmp;
                    139:          free(w);
                    140:        }
                    141:       else
                    142:        up = &(w->next);
                    143:     }
                    144: 
1.1.1.5 ! misho     145:   (void)data; /* no warning */
1.1       misho     146: }
                    147: 
1.1.1.5 ! misho     148: static DBusMessage* dbus_read_servers(DBusMessage *message)
1.1       misho     149: {
                    150:   DBusMessageIter iter;
                    151:   union  mysockaddr addr, source_addr;
                    152:   char *domain;
                    153:   
1.1.1.5 ! misho     154:   if (!dbus_message_iter_init(message, &iter))
        !           155:     {
        !           156:       return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
        !           157:                                     "Failed to initialize dbus message iter");
        !           158:     }
1.1       misho     159: 
1.1.1.2   misho     160:   mark_servers(SERV_FROM_DBUS);
                    161:   
1.1       misho     162:   while (1)
                    163:     {
                    164:       int skip = 0;
                    165: 
                    166:       if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_UINT32)
                    167:        {
                    168:          u32 a;
                    169:          
                    170:          dbus_message_iter_get_basic(&iter, &a);
                    171:          dbus_message_iter_next (&iter);
                    172:          
                    173: #ifdef HAVE_SOCKADDR_SA_LEN
                    174:          source_addr.in.sin_len = addr.in.sin_len = sizeof(struct sockaddr_in);
                    175: #endif
                    176:          addr.in.sin_addr.s_addr = ntohl(a);
                    177:          source_addr.in.sin_family = addr.in.sin_family = AF_INET;
                    178:          addr.in.sin_port = htons(NAMESERVER_PORT);
                    179:          source_addr.in.sin_addr.s_addr = INADDR_ANY;
                    180:          source_addr.in.sin_port = htons(daemon->query_port);
                    181:        }
                    182:       else if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_BYTE)
                    183:        {
                    184:          unsigned char p[sizeof(struct in6_addr)];
                    185:          unsigned int i;
                    186: 
                    187:          skip = 1;
                    188: 
                    189:          for(i = 0; i < sizeof(struct in6_addr); i++)
                    190:            {
                    191:              dbus_message_iter_get_basic(&iter, &p[i]);
                    192:              dbus_message_iter_next (&iter);
                    193:              if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BYTE)
1.1.1.3   misho     194:                {
                    195:                  i++;
                    196:                  break;
                    197:                }
1.1       misho     198:            }
                    199: 
1.1.1.3   misho     200:          if (i == sizeof(struct in6_addr))
1.1       misho     201:            {
                    202:              memcpy(&addr.in6.sin6_addr, p, sizeof(struct in6_addr));
                    203: #ifdef HAVE_SOCKADDR_SA_LEN
                    204:               source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(struct sockaddr_in6);
                    205: #endif
                    206:               source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
                    207:               addr.in6.sin6_port = htons(NAMESERVER_PORT);
                    208:               source_addr.in6.sin6_flowinfo = addr.in6.sin6_flowinfo = 0;
                    209:              source_addr.in6.sin6_scope_id = addr.in6.sin6_scope_id = 0;
                    210:               source_addr.in6.sin6_addr = in6addr_any;
                    211:               source_addr.in6.sin6_port = htons(daemon->query_port);
                    212:              skip = 0;
                    213:            }
                    214:        }
                    215:       else
                    216:        /* At the end */
                    217:        break;
                    218:       
                    219:       /* process each domain */
                    220:       do {
                    221:        if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING)
                    222:          {
                    223:            dbus_message_iter_get_basic(&iter, &domain);
                    224:            dbus_message_iter_next (&iter);
                    225:          }
                    226:        else
                    227:          domain = NULL;
                    228:        
                    229:        if (!skip)
1.1.1.5 ! misho     230:          add_update_server(SERV_FROM_DBUS, &addr, &source_addr, NULL, domain, NULL);
1.1       misho     231:      
                    232:       } while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING); 
                    233:     }
                    234:    
                    235:   /* unlink and free anything still marked. */
1.1.1.2   misho     236:   cleanup_servers();
1.1.1.5 ! misho     237:   return NULL;
1.1       misho     238: }
                    239: 
1.1.1.3   misho     240: #ifdef HAVE_LOOP
                    241: static DBusMessage *dbus_reply_server_loop(DBusMessage *message)
                    242: {
                    243:   DBusMessageIter args, args_iter;
                    244:   struct server *serv;
                    245:   DBusMessage *reply = dbus_message_new_method_return(message);
                    246:    
                    247:   dbus_message_iter_init_append (reply, &args);
                    248:   dbus_message_iter_open_container (&args, DBUS_TYPE_ARRAY,DBUS_TYPE_STRING_AS_STRING, &args_iter);
                    249: 
                    250:   for (serv = daemon->servers; serv; serv = serv->next)
                    251:     if (serv->flags & SERV_LOOP)
                    252:       {
1.1.1.4   misho     253:        (void)prettyprint_addr(&serv->addr, daemon->addrbuff);
1.1.1.3   misho     254:        dbus_message_iter_append_basic (&args_iter, DBUS_TYPE_STRING, &daemon->addrbuff);
                    255:       }
                    256:   
                    257:   dbus_message_iter_close_container (&args, &args_iter);
                    258: 
                    259:   return reply;
                    260: }
                    261: #endif
                    262: 
1.1       misho     263: static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
                    264: {
                    265:   DBusMessageIter iter, array_iter, string_iter;
                    266:   DBusMessage *error = NULL;
                    267:   const char *addr_err;
                    268:   char *dup = NULL;
                    269:   
                    270:   if (!dbus_message_iter_init(message, &iter))
                    271:     {
                    272:       return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
                    273:                                     "Failed to initialize dbus message iter");
                    274:     }
                    275: 
                    276:   /* check that the message contains an array of arrays */
                    277:   if ((dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) ||
                    278:       (dbus_message_iter_get_element_type(&iter) != (strings ? DBUS_TYPE_STRING : DBUS_TYPE_ARRAY)))
                    279:     {
                    280:       return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
                    281:                                     strings ? "Expected array of string" : "Expected array of string arrays");
                    282:      }
                    283:  
1.1.1.2   misho     284:   mark_servers(SERV_FROM_DBUS);
1.1       misho     285: 
                    286:   /* array_iter points to each "as" element in the outer array */
                    287:   dbus_message_iter_recurse(&iter, &array_iter);
                    288:   while (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_INVALID)
                    289:     {
                    290:       const char *str = NULL;
                    291:       union  mysockaddr addr, source_addr;
1.1.1.5 ! misho     292:       u16 flags = 0;
1.1       misho     293:       char interface[IF_NAMESIZE];
                    294:       char *str_addr, *str_domain = NULL;
1.1.1.5 ! misho     295:       struct server_details sdetails = { 0 };
        !           296:       sdetails.addr = &addr;
        !           297:       sdetails.source_addr = &source_addr;
        !           298:       sdetails.interface = interface;
        !           299:       sdetails.flags = &flags;
1.1       misho     300: 
                    301:       if (strings)
                    302:        {
                    303:          dbus_message_iter_get_basic(&array_iter, &str);
                    304:          if (!str || !strlen (str))
                    305:            {
                    306:              error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
                    307:                                             "Empty string");
                    308:              break;
                    309:            }
                    310:          
                    311:          /* dup the string because it gets modified during parsing */
                    312:          if (dup)
                    313:            free(dup);
                    314:          if (!(dup = str_domain = whine_malloc(strlen(str)+1)))
                    315:            break;
                    316:          
                    317:          strcpy(str_domain, str);
                    318: 
                    319:          /* point to address part of old string for error message */
                    320:          if ((str_addr = strrchr(str, '/')))
                    321:            str = str_addr+1;
                    322:          
                    323:          if ((str_addr = strrchr(str_domain, '/')))
                    324:            {
                    325:              if (*str_domain != '/' || str_addr == str_domain)
                    326:                {
                    327:                  error = dbus_message_new_error_printf(message,
                    328:                                                        DBUS_ERROR_INVALID_ARGS,
                    329:                                                        "No domain terminator '%s'",
                    330:                                                        str);
                    331:                  break;
                    332:                }
                    333:              *str_addr++ = 0;
                    334:              str_domain++;
                    335:            }
                    336:          else
                    337:            {
                    338:              str_addr = str_domain;
                    339:              str_domain = NULL;
                    340:            }
                    341: 
                    342:          
                    343:        }
                    344:       else
                    345:        {
                    346:          /* check the types of the struct and its elements */
                    347:          if ((dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY) ||
                    348:              (dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_STRING))
                    349:            {
                    350:              error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
                    351:                                             "Expected inner array of strings");
                    352:              break;
                    353:            }
                    354:          
                    355:          /* string_iter points to each "s" element in the inner array */
                    356:          dbus_message_iter_recurse(&array_iter, &string_iter);
                    357:          if (dbus_message_iter_get_arg_type(&string_iter) != DBUS_TYPE_STRING)
                    358:            {
                    359:              /* no IP address given */
                    360:              error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
                    361:                                             "Expected IP address");
                    362:              break;
                    363:            }
                    364:          
                    365:          dbus_message_iter_get_basic(&string_iter, &str);
                    366:          if (!str || !strlen (str))
                    367:            {
                    368:              error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
                    369:                                             "Empty IP address");
                    370:              break;
                    371:            }
                    372:          
                    373:          /* dup the string because it gets modified during parsing */
                    374:          if (dup)
                    375:            free(dup);
                    376:          if (!(dup = str_addr = whine_malloc(strlen(str)+1)))
                    377:            break;
                    378:          
                    379:          strcpy(str_addr, str);
                    380:        }
                    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:            
1.1.1.5 ! misho     395:             if (strings && strlen(str_addr) == 0)
        !           396:               add_update_server(SERV_LITERAL_ADDRESS | SERV_FROM_DBUS, &addr, &source_addr, interface, str_domain, NULL);
        !           397:             else
        !           398:               {
        !           399:                 if ((addr_err = parse_server(str_addr, &sdetails)))
        !           400:                   {
        !           401:                     error = dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
        !           402:                                                           "Invalid IP address '%s': %s",
        !           403:                                                           str, addr_err);
        !           404:                     break;
        !           405:                   }
        !           406:                 
        !           407:                 while (parse_server_next(&sdetails))
        !           408:                   {
        !           409:                     if ((addr_err = parse_server_addr(&sdetails)))
        !           410:                       {
        !           411:                         error = dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
        !           412:                                                               "Invalid IP address '%s': %s",
        !           413:                                                               str, addr_err);
        !           414:                         break;
        !           415:                       }
        !           416:                     
        !           417:                     add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str_domain, NULL);
        !           418:                   }
        !           419:               }
1.1       misho     420:          } while ((str_domain = p));
                    421:        }
                    422:       else
                    423:        {
                    424:          /* jump past the address to the domain list (if any) */
                    425:          dbus_message_iter_next (&string_iter);
                    426:          
                    427:          /* parse domains and add each server/domain pair to the list */
                    428:          do {
                    429:            str = NULL;
                    430:            if (dbus_message_iter_get_arg_type(&string_iter) == DBUS_TYPE_STRING)
                    431:              dbus_message_iter_get_basic(&string_iter, &str);
                    432:            dbus_message_iter_next (&string_iter);
1.1.1.5 ! misho     433: 
        !           434:            if ((addr_err = parse_server(str_addr, &sdetails)))
        !           435:              {
        !           436:                error = dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
        !           437:                                                      "Invalid IP address '%s': %s",
        !           438:                                                      str, addr_err);
        !           439:                break;
        !           440:              }
1.1       misho     441:            
1.1.1.5 ! misho     442:            while (parse_server_next(&sdetails))
        !           443:              {
        !           444:                if ((addr_err = parse_server_addr(&sdetails)))
        !           445:                  {
        !           446:                    error = dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
        !           447:                                                          "Invalid IP address '%s': %s",
        !           448:                                                          str, addr_err);
        !           449:                    break;
        !           450:                  }
        !           451:                
        !           452:                /* 0.0.0.0 for server address == NULL, for Dbus */
        !           453:                if (addr.in.sin_family == AF_INET &&
        !           454:                    addr.in.sin_addr.s_addr == 0)
        !           455:                  flags |= SERV_LITERAL_ADDRESS;
        !           456:                else
        !           457:                  flags &= ~SERV_LITERAL_ADDRESS;
        !           458:                
        !           459:                add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str, NULL);
        !           460:              }
1.1       misho     461:          } while (dbus_message_iter_get_arg_type(&string_iter) == DBUS_TYPE_STRING);
                    462:        }
1.1.1.5 ! misho     463:       
        !           464:       if (sdetails.orig_hostinfo)
        !           465:        freeaddrinfo(sdetails.orig_hostinfo);
        !           466:       
1.1       misho     467:       /* jump to next element in outer array */
                    468:       dbus_message_iter_next(&array_iter);
                    469:     }
                    470: 
1.1.1.2   misho     471:   cleanup_servers();
1.1.1.5 ! misho     472:     
1.1       misho     473:   if (dup)
                    474:     free(dup);
                    475: 
                    476:   return error;
                    477: }
                    478: 
1.1.1.3   misho     479: static DBusMessage *dbus_set_bool(DBusMessage *message, int flag, char *name)
                    480: {
                    481:   DBusMessageIter iter;
                    482:   dbus_bool_t enabled;
                    483: 
                    484:   if (!dbus_message_iter_init(message, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
                    485:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, "Expected boolean argument");
                    486:   
                    487:   dbus_message_iter_get_basic(&iter, &enabled);
                    488: 
                    489:   if (enabled)
                    490:     { 
                    491:       my_syslog(LOG_INFO, _("Enabling --%s option from D-Bus"), name);
                    492:       set_option_bool(flag);
                    493:     }
                    494:   else
                    495:     {
                    496:       my_syslog(LOG_INFO, _("Disabling --%s option from D-Bus"), name);
                    497:       reset_option_bool(flag);
                    498:     }
                    499: 
                    500:   return NULL;
                    501: }
                    502: 
                    503: #ifdef HAVE_DHCP
                    504: static DBusMessage *dbus_add_lease(DBusMessage* message)
                    505: {
                    506:   struct dhcp_lease *lease;
                    507:   const char *ipaddr, *hwaddr, *hostname, *tmp;
                    508:   const unsigned char* clid;
                    509:   int clid_len, hostname_len, hw_len, hw_type;
                    510:   dbus_uint32_t expires, ia_id;
                    511:   dbus_bool_t is_temporary;
1.1.1.4   misho     512:   union all_addr addr;
1.1.1.3   misho     513:   time_t now = dnsmasq_time();
                    514:   unsigned char dhcp_chaddr[DHCP_CHADDR_MAX];
                    515: 
                    516:   DBusMessageIter iter, array_iter;
                    517:   if (!dbus_message_iter_init(message, &iter))
                    518:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
                    519:                                  "Failed to initialize dbus message iter");
                    520: 
                    521:   if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
                    522:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
                    523:                                  "Expected string as first argument");
                    524: 
                    525:   dbus_message_iter_get_basic(&iter, &ipaddr);
                    526:   dbus_message_iter_next(&iter);
                    527: 
                    528:   if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
                    529:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
                    530:                                  "Expected string as second argument");
                    531:     
                    532:   dbus_message_iter_get_basic(&iter, &hwaddr);
                    533:   dbus_message_iter_next(&iter);
                    534: 
                    535:   if ((dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) ||
                    536:       (dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE))
                    537:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
                    538:                                  "Expected byte array as third argument");
                    539:     
                    540:   dbus_message_iter_recurse(&iter, &array_iter);
                    541:   dbus_message_iter_get_fixed_array(&array_iter, &hostname, &hostname_len);
                    542:   tmp = memchr(hostname, '\0', hostname_len);
                    543:   if (tmp)
                    544:     {
                    545:       if (tmp == &hostname[hostname_len - 1])
                    546:        hostname_len--;
                    547:       else
                    548:        return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
                    549:                                      "Hostname contains an embedded NUL character");
                    550:     }
                    551:   dbus_message_iter_next(&iter);
                    552: 
                    553:   if ((dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) ||
                    554:       (dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE))
                    555:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
                    556:                                  "Expected byte array as fourth argument");
                    557: 
                    558:   dbus_message_iter_recurse(&iter, &array_iter);
                    559:   dbus_message_iter_get_fixed_array(&array_iter, &clid, &clid_len);
                    560:   dbus_message_iter_next(&iter);
                    561: 
                    562:   if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
                    563:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
                    564:                                  "Expected uint32 as fifth argument");
                    565:     
                    566:   dbus_message_iter_get_basic(&iter, &expires);
                    567:   dbus_message_iter_next(&iter);
                    568: 
                    569:   if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
                    570:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
                    571:                                     "Expected uint32 as sixth argument");
                    572:   
                    573:   dbus_message_iter_get_basic(&iter, &ia_id);
                    574:   dbus_message_iter_next(&iter);
                    575: 
                    576:   if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
                    577:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
                    578:                                  "Expected uint32 as sixth argument");
                    579: 
                    580:   dbus_message_iter_get_basic(&iter, &is_temporary);
                    581: 
1.1.1.4   misho     582:   if (inet_pton(AF_INET, ipaddr, &addr.addr4))
1.1.1.3   misho     583:     {
                    584:       if (ia_id != 0 || is_temporary)
                    585:        return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
                    586:                                      "ia_id and is_temporary must be zero for IPv4 lease");
                    587:       
1.1.1.4   misho     588:       if (!(lease = lease_find_by_addr(addr.addr4)))
                    589:        lease = lease4_allocate(addr.addr4);
1.1.1.3   misho     590:     }
                    591: #ifdef HAVE_DHCP6
1.1.1.4   misho     592:   else if (inet_pton(AF_INET6, ipaddr, &addr.addr6))
1.1.1.3   misho     593:     {
1.1.1.4   misho     594:       if (!(lease = lease6_find_by_addr(&addr.addr6, 128, 0)))
                    595:        lease = lease6_allocate(&addr.addr6,
1.1.1.3   misho     596:                                is_temporary ? LEASE_TA : LEASE_NA);
                    597:       lease_set_iaid(lease, ia_id);
                    598:     }
                    599: #endif
                    600:   else
                    601:     return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
                    602:                                         "Invalid IP address '%s'", ipaddr);
                    603:    
1.1.1.4   misho     604:   hw_len = parse_hex((char*)hwaddr, dhcp_chaddr, DHCP_CHADDR_MAX, NULL, &hw_type);
1.1.1.5 ! misho     605:   if (hw_len < 0)
        !           606:     return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
        !           607:                                         "Invalid HW address '%s'", hwaddr);
        !           608: 
1.1.1.3   misho     609:   if (hw_type == 0 && hw_len != 0)
                    610:     hw_type = ARPHRD_ETHER;
1.1.1.4   misho     611:   
                    612:   lease_set_hwaddr(lease, dhcp_chaddr, clid, hw_len, hw_type,
1.1.1.3   misho     613:                    clid_len, now, 0);
                    614:   lease_set_expires(lease, expires, now);
                    615:   if (hostname_len != 0)
                    616:     lease_set_hostname(lease, hostname, 0, get_domain(lease->addr), NULL);
1.1.1.4   misho     617:   
1.1.1.3   misho     618:   lease_update_file(now);
                    619:   lease_update_dns(0);
                    620: 
                    621:   return NULL;
                    622: }
                    623: 
                    624: static DBusMessage *dbus_del_lease(DBusMessage* message)
                    625: {
                    626:   struct dhcp_lease *lease;
                    627:   DBusMessageIter iter;
                    628:   const char *ipaddr;
                    629:   DBusMessage *reply;
1.1.1.4   misho     630:   union all_addr addr;
1.1.1.3   misho     631:   dbus_bool_t ret = 1;
                    632:   time_t now = dnsmasq_time();
                    633: 
                    634:   if (!dbus_message_iter_init(message, &iter))
                    635:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
                    636:                                  "Failed to initialize dbus message iter");
                    637:    
                    638:   if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
                    639:     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
                    640:                                  "Expected string as first argument");
                    641:    
                    642:   dbus_message_iter_get_basic(&iter, &ipaddr);
                    643: 
1.1.1.4   misho     644:   if (inet_pton(AF_INET, ipaddr, &addr.addr4))
                    645:     lease = lease_find_by_addr(addr.addr4);
1.1.1.3   misho     646: #ifdef HAVE_DHCP6
1.1.1.4   misho     647:   else if (inet_pton(AF_INET6, ipaddr, &addr.addr6))
                    648:     lease = lease6_find_by_addr(&addr.addr6, 128, 0);
1.1.1.3   misho     649: #endif
                    650:   else
                    651:     return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
                    652:                                         "Invalid IP address '%s'", ipaddr);
                    653:     
                    654:   if (lease)
                    655:     {
                    656:       lease_prune(lease, now);
                    657:       lease_update_file(now);
                    658:       lease_update_dns(0);
                    659:     }
                    660:   else
                    661:     ret = 0;
                    662:   
                    663:   if ((reply = dbus_message_new_method_return(message)))
                    664:     dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &ret,
                    665:                             DBUS_TYPE_INVALID);
                    666:   
                    667:     
                    668:   return reply;
                    669: }
                    670: #endif
                    671: 
1.1.1.4   misho     672: static DBusMessage *dbus_get_metrics(DBusMessage* message)
                    673: {
                    674:   DBusMessage *reply = dbus_message_new_method_return(message);
                    675:   DBusMessageIter array, dict, iter;
                    676:   int i;
                    677: 
                    678:   dbus_message_iter_init_append(reply, &iter);
                    679:   dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{su}", &array);
                    680: 
                    681:   for (i = 0; i < __METRIC_MAX; i++) {
                    682:     const char *key     = get_metric_name(i);
                    683:     dbus_uint32_t value = daemon->metrics[i];
                    684: 
                    685:     dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, NULL, &dict);
                    686:     dbus_message_iter_append_basic(&dict, DBUS_TYPE_STRING, &key);
                    687:     dbus_message_iter_append_basic(&dict, DBUS_TYPE_UINT32, &value);
                    688:     dbus_message_iter_close_container(&array, &dict);
                    689:   }
                    690: 
                    691:   dbus_message_iter_close_container(&iter, &array);
                    692: 
                    693:   return reply;
                    694: }
                    695: 
1.1.1.5 ! misho     696: static void add_dict_entry(DBusMessageIter *container, const char *key, const char *val)
        !           697: {
        !           698:   DBusMessageIter dict;
        !           699: 
        !           700:   dbus_message_iter_open_container(container, DBUS_TYPE_DICT_ENTRY, NULL, &dict);
        !           701:   dbus_message_iter_append_basic(&dict, DBUS_TYPE_STRING, &key);
        !           702:   dbus_message_iter_append_basic(&dict, DBUS_TYPE_STRING, &val);
        !           703:   dbus_message_iter_close_container(container, &dict);
        !           704: }
        !           705: 
        !           706: static void add_dict_int(DBusMessageIter *container, const char *key, const unsigned int val)
        !           707: {
        !           708:   snprintf(daemon->namebuff, MAXDNAME, "%u", val);
        !           709:   
        !           710:   add_dict_entry(container, key, daemon->namebuff);
        !           711: }
        !           712: 
        !           713: static DBusMessage *dbus_get_server_metrics(DBusMessage* message)
        !           714: {
        !           715:   DBusMessage *reply = dbus_message_new_method_return(message);
        !           716:   DBusMessageIter server_array, dict_array, server_iter;
        !           717:   struct server *serv;
        !           718:   
        !           719:   dbus_message_iter_init_append(reply, &server_iter);
        !           720:   dbus_message_iter_open_container(&server_iter, DBUS_TYPE_ARRAY, "a{ss}", &server_array);
        !           721: 
        !           722:   /* sum counts from different records for same server */
        !           723:   for (serv = daemon->servers; serv; serv = serv->next)
        !           724:     serv->flags &= ~SERV_MARK;
        !           725:   
        !           726:   for (serv = daemon->servers; serv; serv = serv->next)
        !           727:     if (!(serv->flags & SERV_MARK))
        !           728:       {
        !           729:        unsigned int port;
        !           730:        unsigned int queries = 0, failed_queries = 0, nxdomain_replies = 0, retrys = 0;
        !           731:        unsigned int sigma_latency = 0, count_latency = 0;
        !           732:        
        !           733:        struct server *serv1;
        !           734: 
        !           735:        for (serv1 = serv; serv1; serv1 = serv1->next)
        !           736:          if (!(serv1->flags & SERV_MARK) && sockaddr_isequal(&serv->addr, &serv1->addr))
        !           737:            {
        !           738:              serv1->flags |= SERV_MARK;
        !           739:              queries += serv1->queries;
        !           740:              failed_queries += serv1->failed_queries;
        !           741:              nxdomain_replies += serv1->nxdomain_replies;
        !           742:              retrys += serv1->retrys;
        !           743:              sigma_latency += serv1->query_latency;
        !           744:              count_latency++;
        !           745:            }
        !           746:        
        !           747:        dbus_message_iter_open_container(&server_array, DBUS_TYPE_ARRAY, "{ss}", &dict_array);
        !           748:        
        !           749:        port = prettyprint_addr(&serv->addr, daemon->namebuff);
        !           750:        add_dict_entry(&dict_array, "address", daemon->namebuff);
        !           751:        
        !           752:        add_dict_int(&dict_array, "port", port);
        !           753:        add_dict_int(&dict_array, "queries", serv->queries);
        !           754:        add_dict_int(&dict_array, "failed_queries", serv->failed_queries);
        !           755:        add_dict_int(&dict_array, "nxdomain", serv->nxdomain_replies);
        !           756:        add_dict_int(&dict_array, "retries", serv->retrys);
        !           757:        add_dict_int(&dict_array, "latency", sigma_latency/count_latency);
        !           758:        
        !           759:        dbus_message_iter_close_container(&server_array, &dict_array);
        !           760:       }
        !           761:   
        !           762:   dbus_message_iter_close_container(&server_iter, &server_array);
        !           763:   
        !           764:   return reply;
        !           765: }
        !           766: 
1.1       misho     767: DBusHandlerResult message_handler(DBusConnection *connection, 
                    768:                                  DBusMessage *message, 
                    769:                                  void *user_data)
                    770: {
                    771:   char *method = (char *)dbus_message_get_member(message);
                    772:   DBusMessage *reply = NULL;
1.1.1.2   misho     773:   int clear_cache = 0, new_servers = 0;
1.1       misho     774:     
                    775:   if (dbus_message_is_method_call(message, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
                    776:     {
                    777:       /* string length: "%s" provides space for termination zero */
                    778:       if (!introspection_xml && 
                    779:          (introspection_xml = whine_malloc(strlen(introspection_xml_template) + strlen(daemon->dbus_name))))
                    780:        sprintf(introspection_xml, introspection_xml_template, daemon->dbus_name);
                    781:     
                    782:       if (introspection_xml)
                    783:        {
                    784:          reply = dbus_message_new_method_return(message);
                    785:          dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection_xml, DBUS_TYPE_INVALID);
                    786:        }
                    787:     }
                    788:   else if (strcmp(method, "GetVersion") == 0)
                    789:     {
                    790:       char *v = VERSION;
                    791:       reply = dbus_message_new_method_return(message);
                    792:       
                    793:       dbus_message_append_args(reply, DBUS_TYPE_STRING, &v, DBUS_TYPE_INVALID);
                    794:     }
1.1.1.3   misho     795: #ifdef HAVE_LOOP
                    796:   else if (strcmp(method, "GetLoopServers") == 0)
                    797:     {
                    798:       reply = dbus_reply_server_loop(message);
                    799:     }
                    800: #endif
1.1       misho     801:   else if (strcmp(method, "SetServers") == 0)
                    802:     {
1.1.1.5 ! misho     803:       reply = dbus_read_servers(message);
1.1.1.2   misho     804:       new_servers = 1;
1.1       misho     805:     }
                    806:   else if (strcmp(method, "SetServersEx") == 0)
                    807:     {
                    808:       reply = dbus_read_servers_ex(message, 0);
1.1.1.2   misho     809:       new_servers = 1;
1.1       misho     810:     }
                    811:   else if (strcmp(method, "SetDomainServers") == 0)
                    812:     {
                    813:       reply = dbus_read_servers_ex(message, 1);
1.1.1.2   misho     814:       new_servers = 1;
1.1       misho     815:     }
1.1.1.3   misho     816:   else if (strcmp(method, "SetFilterWin2KOption") == 0)
                    817:     {
                    818:       reply = dbus_set_bool(message, OPT_FILTER, "filterwin2k");
                    819:     }
1.1.1.5 ! misho     820:   else if (strcmp(method, "SetLocaliseQueriesOption") == 0)
        !           821:     {
        !           822:       reply = dbus_set_bool(message, OPT_LOCALISE, "localise-queries");
        !           823:     }
1.1.1.3   misho     824:   else if (strcmp(method, "SetBogusPrivOption") == 0)
                    825:     {
                    826:       reply = dbus_set_bool(message, OPT_BOGUSPRIV, "bogus-priv");
                    827:     }
                    828: #ifdef HAVE_DHCP
                    829:   else if (strcmp(method, "AddDhcpLease") == 0)
                    830:     {
                    831:       reply = dbus_add_lease(message);
                    832:     }
                    833:   else if (strcmp(method, "DeleteDhcpLease") == 0)
                    834:     {
                    835:       reply = dbus_del_lease(message);
                    836:     }
                    837: #endif
1.1.1.4   misho     838:   else if (strcmp(method, "GetMetrics") == 0)
                    839:     {
                    840:       reply = dbus_get_metrics(message);
                    841:     }
1.1.1.5 ! misho     842:   else if (strcmp(method, "GetServerMetrics") == 0)
        !           843:     {
        !           844:       reply = dbus_get_server_metrics(message);
        !           845:     }
        !           846:   else if (strcmp(method, "ClearMetrics") == 0)
        !           847:     {
        !           848:       clear_metrics();
        !           849:     }
1.1       misho     850:   else if (strcmp(method, "ClearCache") == 0)
1.1.1.2   misho     851:     clear_cache = 1;
1.1       misho     852:   else
                    853:     return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
1.1.1.2   misho     854:    
                    855:   if (new_servers)
                    856:     {
                    857:       my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
1.1.1.5 ! misho     858:       check_servers(0);
1.1.1.2   misho     859:       if (option_bool(OPT_RELOAD))
                    860:        clear_cache = 1;
                    861:     }
                    862: 
                    863:   if (clear_cache)
                    864:     clear_cache_and_reload(dnsmasq_time());
1.1       misho     865:   
1.1.1.5 ! misho     866:   (void)user_data; /* no warning */
1.1       misho     867: 
                    868:   /* If no reply or no error, return nothing */
                    869:   if (!reply)
                    870:     reply = dbus_message_new_method_return(message);
                    871: 
                    872:   if (reply)
                    873:     {
                    874:       dbus_connection_send (connection, reply, NULL);
                    875:       dbus_message_unref (reply);
                    876:     }
                    877: 
                    878:   return (DBUS_HANDLER_RESULT_HANDLED);
                    879: }
                    880:  
                    881: 
                    882: /* returns NULL or error message, may fail silently if dbus daemon not yet up. */
                    883: char *dbus_init(void)
                    884: {
                    885:   DBusConnection *connection = NULL;
                    886:   DBusObjectPathVTable dnsmasq_vtable = {NULL, &message_handler, NULL, NULL, NULL, NULL };
                    887:   DBusError dbus_error;
                    888:   DBusMessage *message;
                    889: 
                    890:   dbus_error_init (&dbus_error);
                    891:   if (!(connection = dbus_bus_get (DBUS_BUS_SYSTEM, &dbus_error)))
1.1.1.5 ! misho     892:     {
        !           893:       dbus_error_free(&dbus_error);
        !           894:       return NULL;
        !           895:     }
        !           896:   
1.1       misho     897:   dbus_connection_set_exit_on_disconnect(connection, FALSE);
                    898:   dbus_connection_set_watch_functions(connection, add_watch, remove_watch, 
                    899:                                      NULL, NULL, NULL);
                    900:   dbus_error_init (&dbus_error);
                    901:   dbus_bus_request_name (connection, daemon->dbus_name, 0, &dbus_error);
                    902:   if (dbus_error_is_set (&dbus_error))
                    903:     return (char *)dbus_error.message;
                    904:   
                    905:   if (!dbus_connection_register_object_path(connection,  DNSMASQ_PATH, 
                    906:                                            &dnsmasq_vtable, NULL))
                    907:     return _("could not register a DBus message handler");
                    908:   
                    909:   daemon->dbus = connection; 
                    910:   
                    911:   if ((message = dbus_message_new_signal(DNSMASQ_PATH, daemon->dbus_name, "Up")))
                    912:     {
                    913:       dbus_connection_send(connection, message, NULL);
                    914:       dbus_message_unref(message);
                    915:     }
                    916: 
                    917:   return NULL;
                    918: }
                    919:  
                    920: 
1.1.1.3   misho     921: void set_dbus_listeners(void)
1.1       misho     922: {
                    923:   struct watch *w;
                    924:   
                    925:   for (w = daemon->watches; w; w = w->next)
                    926:     if (dbus_watch_get_enabled(w->watch))
                    927:       {
                    928:        unsigned int flags = dbus_watch_get_flags(w->watch);
                    929:        int fd = dbus_watch_get_unix_fd(w->watch);
                    930:        
                    931:        if (flags & DBUS_WATCH_READABLE)
1.1.1.3   misho     932:          poll_listen(fd, POLLIN);
1.1       misho     933:        
                    934:        if (flags & DBUS_WATCH_WRITABLE)
1.1.1.3   misho     935:          poll_listen(fd, POLLOUT);
1.1       misho     936:        
1.1.1.3   misho     937:        poll_listen(fd, POLLERR);
1.1       misho     938:       }
                    939: }
                    940: 
1.1.1.3   misho     941: void check_dbus_listeners()
1.1       misho     942: {
                    943:   DBusConnection *connection = (DBusConnection *)daemon->dbus;
                    944:   struct watch *w;
                    945: 
                    946:   for (w = daemon->watches; w; w = w->next)
                    947:     if (dbus_watch_get_enabled(w->watch))
                    948:       {
                    949:        unsigned int flags = 0;
                    950:        int fd = dbus_watch_get_unix_fd(w->watch);
                    951:        
1.1.1.3   misho     952:        if (poll_check(fd, POLLIN))
1.1       misho     953:          flags |= DBUS_WATCH_READABLE;
                    954:        
1.1.1.3   misho     955:        if (poll_check(fd, POLLOUT))
1.1       misho     956:          flags |= DBUS_WATCH_WRITABLE;
                    957:        
1.1.1.3   misho     958:        if (poll_check(fd, POLLERR))
1.1       misho     959:          flags |= DBUS_WATCH_ERROR;
                    960: 
                    961:        if (flags != 0)
                    962:          dbus_watch_handle(w->watch, flags);
                    963:       }
                    964: 
                    965:   if (connection)
                    966:     {
                    967:       dbus_connection_ref (connection);
                    968:       while (dbus_connection_dispatch (connection) == DBUS_DISPATCH_DATA_REMAINS);
                    969:       dbus_connection_unref (connection);
                    970:     }
                    971: }
                    972: 
                    973: #ifdef HAVE_DHCP
                    974: void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname)
                    975: {
                    976:   DBusConnection *connection = (DBusConnection *)daemon->dbus;
                    977:   DBusMessage* message = NULL;
                    978:   DBusMessageIter args;
                    979:   char *action_str, *mac = daemon->namebuff;
                    980:   unsigned char *p;
                    981:   int i;
                    982: 
                    983:   if (!connection)
                    984:     return;
                    985:   
                    986:   if (!hostname)
                    987:     hostname = "";
                    988:   
                    989: #ifdef HAVE_DHCP6
                    990:    if (lease->flags & (LEASE_TA | LEASE_NA))
                    991:      {
                    992:        print_mac(mac, lease->clid, lease->clid_len);
1.1.1.3   misho     993:        inet_ntop(AF_INET6, &lease->addr6, daemon->addrbuff, ADDRSTRLEN);
1.1       misho     994:      }
                    995:    else
                    996: #endif
                    997:      {
                    998:        p = extended_hwaddr(lease->hwaddr_type, lease->hwaddr_len,
                    999:                           lease->hwaddr, lease->clid_len, lease->clid, &i);
                   1000:        print_mac(mac, p, i);
                   1001:        inet_ntop(AF_INET, &lease->addr, daemon->addrbuff, ADDRSTRLEN);
                   1002:      }
                   1003: 
                   1004:   if (action == ACTION_DEL)
                   1005:     action_str = "DhcpLeaseDeleted";
                   1006:   else if (action == ACTION_ADD)
                   1007:     action_str = "DhcpLeaseAdded";
                   1008:   else if (action == ACTION_OLD)
                   1009:     action_str = "DhcpLeaseUpdated";
                   1010:   else
                   1011:     return;
                   1012: 
                   1013:   if (!(message = dbus_message_new_signal(DNSMASQ_PATH, daemon->dbus_name, action_str)))
                   1014:     return;
                   1015:   
                   1016:   dbus_message_iter_init_append(message, &args);
                   1017:   
                   1018:   if (dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &daemon->addrbuff) &&
                   1019:       dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &mac) &&
                   1020:       dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &hostname))
                   1021:     dbus_connection_send(connection, message, NULL);
                   1022:   
                   1023:   dbus_message_unref(message);
                   1024: }
                   1025: #endif
                   1026: 
                   1027: #endif

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