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

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

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