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

1.1.1.4 ! misho       1: /* dnsmasq is Copyright (c) 2000-2021 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"
                     55: "    <method name=\"SetBogusPrivOption\">\n"
                     56: "      <arg name=\"boguspriv\" direction=\"in\" type=\"b\"/>\n"
                     57: "    </method>\n"
1.1       misho      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"
1.1.1.3   misho      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
1.1.1.4 ! misho      88: "    <method name=\"GetMetrics\">\n"
        !            89: "      <arg name=\"metrics\" direction=\"out\" type=\"a{su}\"/>\n"
        !            90: "    </method>\n"
1.1       misho      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: 
1.1.1.2   misho     148:   mark_servers(SERV_FROM_DBUS);
                    149:   
1.1       misho     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)
1.1.1.3   misho     182:                {
                    183:                  i++;
                    184:                  break;
                    185:                }
1.1       misho     186:            }
                    187: 
1.1.1.3   misho     188:          if (i == sizeof(struct in6_addr))
1.1       misho     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)
1.1.1.2   misho     218:          add_update_server(SERV_FROM_DBUS, &addr, &source_addr, NULL, domain);
1.1       misho     219:      
                    220:       } while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING); 
                    221:     }
                    222:    
                    223:   /* unlink and free anything still marked. */
1.1.1.2   misho     224:   cleanup_servers();
1.1       misho     225: }
                    226: 
1.1.1.3   misho     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:       {
1.1.1.4 ! misho     240:        (void)prettyprint_addr(&serv->addr, daemon->addrbuff);
1.1.1.3   misho     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: 
1.1       misho     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:  
1.1.1.2   misho     271:   mark_servers(SERV_FROM_DBUS);
1.1       misho     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;
1.1.1.2   misho     279:       int flags = 0;
1.1       misho     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 */
1.1.1.2   misho     369:       if ((addr_err = parse_server(str_addr, &addr, &source_addr, (char *) &interface, &flags)))
                    370:        {
1.1       misho     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:         }
1.1.1.2   misho     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:       
1.1       misho     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.2   misho     395:            add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str_domain);
1.1       misho     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:            
1.1.1.2   misho     410:            add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str);
1.1       misho     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: 
1.1.1.2   misho     418:   cleanup_servers();
1.1       misho     419: 
                    420:   if (dup)
                    421:     free(dup);
                    422: 
                    423:   return error;
                    424: }
                    425: 
1.1.1.3   misho     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;
1.1.1.4 ! misho     459:   union all_addr addr;
1.1.1.3   misho     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: 
1.1.1.4 ! misho     529:   if (inet_pton(AF_INET, ipaddr, &addr.addr4))
1.1.1.3   misho     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:       
1.1.1.4 ! misho     535:       if (!(lease = lease_find_by_addr(addr.addr4)))
        !           536:        lease = lease4_allocate(addr.addr4);
1.1.1.3   misho     537:     }
                    538: #ifdef HAVE_DHCP6
1.1.1.4 ! misho     539:   else if (inet_pton(AF_INET6, ipaddr, &addr.addr6))
1.1.1.3   misho     540:     {
1.1.1.4 ! misho     541:       if (!(lease = lease6_find_by_addr(&addr.addr6, 128, 0)))
        !           542:        lease = lease6_allocate(&addr.addr6,
1.1.1.3   misho     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:    
1.1.1.4 ! misho     551:   hw_len = parse_hex((char*)hwaddr, dhcp_chaddr, DHCP_CHADDR_MAX, NULL, &hw_type);
1.1.1.3   misho     552:   if (hw_type == 0 && hw_len != 0)
                    553:     hw_type = ARPHRD_ETHER;
1.1.1.4 ! misho     554:   
        !           555:   lease_set_hwaddr(lease, dhcp_chaddr, clid, hw_len, hw_type,
1.1.1.3   misho     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);
1.1.1.4 ! misho     560:   
1.1.1.3   misho     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;
1.1.1.4 ! misho     573:   union all_addr addr;
1.1.1.3   misho     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: 
1.1.1.4 ! misho     587:   if (inet_pton(AF_INET, ipaddr, &addr.addr4))
        !           588:     lease = lease_find_by_addr(addr.addr4);
1.1.1.3   misho     589: #ifdef HAVE_DHCP6
1.1.1.4 ! misho     590:   else if (inet_pton(AF_INET6, ipaddr, &addr.addr6))
        !           591:     lease = lease6_find_by_addr(&addr.addr6, 128, 0);
1.1.1.3   misho     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: 
1.1.1.4 ! misho     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: 
1.1       misho     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;
1.1.1.2   misho     645:   int clear_cache = 0, new_servers = 0;
1.1       misho     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:     }
1.1.1.3   misho     667: #ifdef HAVE_LOOP
                    668:   else if (strcmp(method, "GetLoopServers") == 0)
                    669:     {
                    670:       reply = dbus_reply_server_loop(message);
                    671:     }
                    672: #endif
1.1       misho     673:   else if (strcmp(method, "SetServers") == 0)
                    674:     {
                    675:       dbus_read_servers(message);
1.1.1.2   misho     676:       new_servers = 1;
1.1       misho     677:     }
                    678:   else if (strcmp(method, "SetServersEx") == 0)
                    679:     {
                    680:       reply = dbus_read_servers_ex(message, 0);
1.1.1.2   misho     681:       new_servers = 1;
1.1       misho     682:     }
                    683:   else if (strcmp(method, "SetDomainServers") == 0)
                    684:     {
                    685:       reply = dbus_read_servers_ex(message, 1);
1.1.1.2   misho     686:       new_servers = 1;
1.1       misho     687:     }
1.1.1.3   misho     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
1.1.1.4 ! misho     706:   else if (strcmp(method, "GetMetrics") == 0)
        !           707:     {
        !           708:       reply = dbus_get_metrics(message);
        !           709:     }
1.1       misho     710:   else if (strcmp(method, "ClearCache") == 0)
1.1.1.2   misho     711:     clear_cache = 1;
1.1       misho     712:   else
                    713:     return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
1.1.1.2   misho     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());
1.1       misho     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: 
1.1.1.3   misho     778: void set_dbus_listeners(void)
1.1       misho     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)
1.1.1.3   misho     789:          poll_listen(fd, POLLIN);
1.1       misho     790:        
                    791:        if (flags & DBUS_WATCH_WRITABLE)
1.1.1.3   misho     792:          poll_listen(fd, POLLOUT);
1.1       misho     793:        
1.1.1.3   misho     794:        poll_listen(fd, POLLERR);
1.1       misho     795:       }
                    796: }
                    797: 
1.1.1.3   misho     798: void check_dbus_listeners()
1.1       misho     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:        
1.1.1.3   misho     809:        if (poll_check(fd, POLLIN))
1.1       misho     810:          flags |= DBUS_WATCH_READABLE;
                    811:        
1.1.1.3   misho     812:        if (poll_check(fd, POLLOUT))
1.1       misho     813:          flags |= DBUS_WATCH_WRITABLE;
                    814:        
1.1.1.3   misho     815:        if (poll_check(fd, POLLERR))
1.1       misho     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);
1.1.1.3   misho     850:        inet_ntop(AF_INET6, &lease->addr6, daemon->addrbuff, ADDRSTRLEN);
1.1       misho     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>