Home | History | Annotate | Download | only in avahi-daemon
      1 /***
      2   This file is part of avahi.
      3 
      4   avahi is free software; you can redistribute it and/or modify it
      5   under the terms of the GNU Lesser General Public License as
      6   published by the Free Software Foundation; either version 2.1 of the
      7   License, or (at your option) any later version.
      8 
      9   avahi is distributed in the hope that it will be useful, but WITHOUT
     10   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     11   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
     12   Public License for more details.
     13 
     14   You should have received a copy of the GNU Lesser General Public
     15   License along with avahi; if not, write to the Free Software
     16   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
     17   USA.
     18 ***/
     19 
     20 #ifdef HAVE_CONFIG_H
     21 #include <config.h>
     22 #endif
     23 
     24 #include <assert.h>
     25 #include <stdlib.h>
     26 #include <sys/stat.h>
     27 #include <unistd.h>
     28 #include <fcntl.h>
     29 #include <errno.h>
     30 #include <string.h>
     31 
     32 #include <avahi-common/error.h>
     33 #include <avahi-common/dbus.h>
     34 #include "avahi-common/avahi-malloc.h"
     35 #include <avahi-core/log.h>
     36 #include <avahi-core/core.h>
     37 
     38 #ifdef ENABLE_CHROOT
     39 #include "chroot.h"
     40 #endif
     41 
     42 #include "main.h"
     43 #include "dbus-util.h"
     44 
     45 DBusHandlerResult avahi_dbus_respond_error(DBusConnection *c, DBusMessage *m, int error, const char *text) {
     46     DBusMessage *reply;
     47 
     48     assert(-error > -AVAHI_OK);
     49     assert(-error < -AVAHI_ERR_MAX);
     50 
     51     if (!text)
     52         text = avahi_strerror(error);
     53 
     54     reply = dbus_message_new_error(m, avahi_error_number_to_dbus(error), text);
     55 
     56     if (!reply) {
     57         avahi_log_error("Failed allocate message");
     58         return DBUS_HANDLER_RESULT_NEED_MEMORY;
     59     }
     60 
     61     dbus_connection_send(c, reply, NULL);
     62     dbus_message_unref(reply);
     63 
     64     avahi_log_debug(__FILE__": Responding error '%s' (%i)", text, error);
     65 
     66     return DBUS_HANDLER_RESULT_HANDLED;
     67 }
     68 
     69 DBusHandlerResult avahi_dbus_respond_string(DBusConnection *c, DBusMessage *m, const char *text) {
     70     DBusMessage *reply;
     71 
     72     reply = dbus_message_new_method_return(m);
     73 
     74     if (!reply) {
     75         avahi_log_error("Failed allocate message");
     76         return DBUS_HANDLER_RESULT_NEED_MEMORY;
     77     }
     78 
     79     dbus_message_append_args(reply, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID);
     80     dbus_connection_send(c, reply, NULL);
     81     dbus_message_unref(reply);
     82 
     83     return DBUS_HANDLER_RESULT_HANDLED;
     84 }
     85 
     86 DBusHandlerResult avahi_dbus_respond_int32(DBusConnection *c, DBusMessage *m, int32_t i) {
     87     DBusMessage *reply;
     88 
     89     reply = dbus_message_new_method_return(m);
     90 
     91     if (!reply) {
     92         avahi_log_error("Failed allocate message");
     93         return DBUS_HANDLER_RESULT_NEED_MEMORY;
     94     }
     95 
     96     dbus_message_append_args(reply, DBUS_TYPE_INT32, &i, DBUS_TYPE_INVALID);
     97     dbus_connection_send(c, reply, NULL);
     98     dbus_message_unref(reply);
     99 
    100     return DBUS_HANDLER_RESULT_HANDLED;
    101 }
    102 
    103 DBusHandlerResult avahi_dbus_respond_uint32(DBusConnection *c, DBusMessage *m, uint32_t u) {
    104     DBusMessage *reply;
    105 
    106     reply = dbus_message_new_method_return(m);
    107 
    108     if (!reply) {
    109         avahi_log_error("Failed allocate message");
    110         return DBUS_HANDLER_RESULT_NEED_MEMORY;
    111     }
    112 
    113     dbus_message_append_args(reply, DBUS_TYPE_UINT32, &u, DBUS_TYPE_INVALID);
    114     dbus_connection_send(c, reply, NULL);
    115     dbus_message_unref(reply);
    116 
    117     return DBUS_HANDLER_RESULT_HANDLED;
    118 }
    119 
    120 DBusHandlerResult avahi_dbus_respond_boolean(DBusConnection *c, DBusMessage *m, int b) {
    121     DBusMessage *reply;
    122 
    123     reply = dbus_message_new_method_return(m);
    124 
    125     if (!reply) {
    126         avahi_log_error("Failed allocate message");
    127         return DBUS_HANDLER_RESULT_NEED_MEMORY;
    128     }
    129 
    130     dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &b, DBUS_TYPE_INVALID);
    131     dbus_connection_send(c, reply, NULL);
    132     dbus_message_unref(reply);
    133 
    134     return DBUS_HANDLER_RESULT_HANDLED;
    135 }
    136 
    137 DBusHandlerResult avahi_dbus_respond_ok(DBusConnection *c, DBusMessage *m) {
    138     DBusMessage *reply;
    139 
    140     reply = dbus_message_new_method_return(m);
    141 
    142     if (!reply) {
    143         avahi_log_error("Failed allocate message");
    144         return DBUS_HANDLER_RESULT_NEED_MEMORY;
    145     }
    146 
    147     dbus_connection_send(c, reply, NULL);
    148     dbus_message_unref(reply);
    149 
    150     return DBUS_HANDLER_RESULT_HANDLED;
    151 }
    152 
    153 DBusHandlerResult avahi_dbus_respond_path(DBusConnection *c, DBusMessage *m, const char *path) {
    154     DBusMessage *reply;
    155 
    156     reply = dbus_message_new_method_return(m);
    157 
    158     if (!reply) {
    159         avahi_log_error("Failed allocate message");
    160         return DBUS_HANDLER_RESULT_NEED_MEMORY;
    161     }
    162 
    163     dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
    164     dbus_connection_send(c, reply, NULL);
    165     dbus_message_unref(reply);
    166 
    167     return DBUS_HANDLER_RESULT_HANDLED;
    168 }
    169 
    170 void avahi_dbus_append_server_error(DBusMessage *reply) {
    171     const char *t;
    172 
    173     t = avahi_error_number_to_dbus(avahi_server_errno(avahi_server));
    174 
    175     dbus_message_append_args(
    176         reply,
    177         DBUS_TYPE_STRING, &t,
    178         DBUS_TYPE_INVALID);
    179 }
    180 
    181 const char *avahi_dbus_map_browse_signal_name(AvahiBrowserEvent e) {
    182     switch (e) {
    183         case AVAHI_BROWSER_NEW : return "ItemNew";
    184         case AVAHI_BROWSER_REMOVE : return "ItemRemove";
    185         case AVAHI_BROWSER_FAILURE : return "Failure";
    186         case AVAHI_BROWSER_CACHE_EXHAUSTED : return "CacheExhausted";
    187         case AVAHI_BROWSER_ALL_FOR_NOW : return "AllForNow";
    188     }
    189 
    190     abort();
    191 }
    192 
    193 const char *avahi_dbus_map_resolve_signal_name(AvahiResolverEvent e) {
    194     switch (e) {
    195         case AVAHI_RESOLVER_FOUND : return "Found";
    196         case AVAHI_RESOLVER_FAILURE : return "Failure";
    197     }
    198 
    199     abort();
    200 }
    201 
    202 static char *file_get_contents(const char *fname) {
    203     int fd = -1;
    204     struct stat st;
    205     ssize_t size;
    206     char *buf = NULL;
    207 
    208     assert(fname);
    209 
    210 #ifdef ENABLE_CHROOT
    211     fd = avahi_chroot_helper_get_fd(fname);
    212 #else
    213     fd = open(fname, O_RDONLY);
    214 #endif
    215 
    216     if (fd < 0) {
    217         avahi_log_error("Failed to open %s: %s", fname, strerror(errno));
    218         goto fail;
    219     }
    220 
    221     if (fstat(fd, &st) < 0) {
    222         avahi_log_error("stat(%s) failed: %s", fname, strerror(errno));
    223         goto fail;
    224     }
    225 
    226     if (!(S_ISREG(st.st_mode))) {
    227         avahi_log_error("Invalid file %s", fname);
    228         goto fail;
    229     }
    230 
    231     if (st.st_size > 1024*1024) { /** 1MB */
    232         avahi_log_error("File too large %s", fname);
    233         goto fail;
    234     }
    235 
    236     buf = avahi_new(char, st.st_size+1);
    237 
    238     if ((size = read(fd, buf, st.st_size)) < 0) {
    239         avahi_log_error("read() failed: %s\n", strerror(errno));
    240         goto fail;
    241     }
    242 
    243     buf[size] = 0;
    244 
    245     close(fd);
    246 
    247     return buf;
    248 
    249 fail:
    250     if (fd >= 0)
    251         close(fd);
    252 
    253     if (buf)
    254         avahi_free(buf);
    255 
    256     return NULL;
    257 
    258 }
    259 
    260 DBusHandlerResult avahi_dbus_handle_introspect(DBusConnection *c, DBusMessage *m, const char *fname) {
    261 #ifdef AVAHI_DBUS_INTROSPECTION_DIR
    262     char *contents, *path;
    263     DBusError error;
    264 
    265     assert(c);
    266     assert(m);
    267     assert(fname);
    268 
    269     dbus_error_init(&error);
    270 
    271     if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
    272         avahi_log_error("Error parsing Introspect message: %s", error.message);
    273         goto fail;
    274     }
    275 
    276     path = avahi_strdup_printf("%s/%s", AVAHI_DBUS_INTROSPECTION_DIR, fname);
    277     contents = file_get_contents(path);
    278     avahi_free(path);
    279 
    280     if (!contents) {
    281         avahi_log_error("Failed to load introspection data.");
    282         goto fail;
    283     }
    284 
    285     avahi_dbus_respond_string(c, m, contents);
    286     avahi_free(contents);
    287 
    288     return DBUS_HANDLER_RESULT_HANDLED;
    289 
    290 fail:
    291     if (dbus_error_is_set(&error))
    292         dbus_error_free(&error);
    293 #endif
    294 
    295     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    296 
    297 }
    298 
    299 void avahi_dbus_append_string_list(DBusMessage *reply, AvahiStringList *txt) {
    300     AvahiStringList *p;
    301     DBusMessageIter iter, sub;
    302 
    303     assert(reply);
    304 
    305     dbus_message_iter_init_append(reply, &iter);
    306     dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "ay", &sub);
    307 
    308     for (p = txt; p; p = p->next) {
    309         DBusMessageIter sub2;
    310         const uint8_t *data = p->text;
    311 
    312         dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "y", &sub2);
    313         dbus_message_iter_append_fixed_array(&sub2, DBUS_TYPE_BYTE, &data, p->size);
    314         dbus_message_iter_close_container(&sub, &sub2);
    315 
    316     }
    317     dbus_message_iter_close_container(&iter, &sub);
    318 }
    319 
    320 int avahi_dbus_read_rdata(DBusMessage *m, int idx, void **rdata, uint32_t *size) {
    321     DBusMessageIter iter, sub;
    322     int n, j;
    323     uint8_t *k;
    324 
    325     assert(m);
    326 
    327     dbus_message_iter_init(m, &iter);
    328 
    329     for (j = 0; j < idx; j++)
    330        dbus_message_iter_next(&iter);
    331 
    332     if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
    333         dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE)
    334         goto fail;
    335 
    336     dbus_message_iter_recurse(&iter, &sub);
    337     dbus_message_iter_get_fixed_array(&sub, &k, &n);
    338 
    339     *rdata = k;
    340     *size = n;
    341 
    342     return 0;
    343 
    344 fail:
    345     avahi_log_warn("Error parsing data");
    346 
    347     *rdata = NULL;
    348     size = 0;
    349     return -1;
    350 }
    351 
    352 int avahi_dbus_read_strlst(DBusMessage *m, int idx, AvahiStringList **l) {
    353     DBusMessageIter iter, sub;
    354     int j;
    355     AvahiStringList *strlst = NULL;
    356 
    357     assert(m);
    358     assert(l);
    359 
    360     dbus_message_iter_init(m, &iter);
    361 
    362     for (j = 0; j < idx; j++)
    363         dbus_message_iter_next(&iter);
    364 
    365     if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
    366         dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_ARRAY)
    367         goto fail;
    368 
    369     dbus_message_iter_recurse(&iter, &sub);
    370 
    371     for (;;) {
    372         int at, n;
    373         const uint8_t *k;
    374         DBusMessageIter sub2;
    375 
    376         if ((at = dbus_message_iter_get_arg_type(&sub)) == DBUS_TYPE_INVALID)
    377             break;
    378 
    379         assert(at == DBUS_TYPE_ARRAY);
    380 
    381         if (dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_BYTE)
    382             goto fail;
    383 
    384         dbus_message_iter_recurse(&sub, &sub2);
    385 
    386         k = (const uint8_t*) "";
    387         n = 0;
    388         dbus_message_iter_get_fixed_array(&sub2, &k, &n);
    389 
    390         if (!k)
    391             k = (const uint8_t*) "";
    392 
    393         strlst = avahi_string_list_add_arbitrary(strlst, k, n);
    394 
    395         dbus_message_iter_next(&sub);
    396     }
    397 
    398     *l = strlst;
    399 
    400     return 0;
    401 
    402 fail:
    403     avahi_log_warn("Error parsing TXT data");
    404 
    405     avahi_string_list_free(strlst);
    406     *l = NULL;
    407     return -1;
    408 }
    409 
    410 int avahi_dbus_is_our_own_service(Client *c, AvahiIfIndex interface, AvahiProtocol protocol, const char *name, const char *type, const char *domain) {
    411     AvahiSEntryGroup *g;
    412 
    413     if (avahi_server_get_group_of_service(avahi_server, interface, protocol, name, type, domain, &g) == AVAHI_OK) {
    414         EntryGroupInfo *egi;
    415 
    416         for (egi = c->entry_groups; egi; egi = egi->entry_groups_next)
    417             if (egi->entry_group == g)
    418                 return 1;
    419     }
    420 
    421     return 0;
    422 }
    423 
    424 int avahi_dbus_append_rdata(DBusMessage *message, const void *rdata, size_t size) {
    425     DBusMessageIter iter, sub;
    426 
    427     assert(message);
    428 
    429     dbus_message_iter_init_append(message, &iter);
    430 
    431     if (!(dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &sub)) ||
    432         !(dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &rdata, size)) ||
    433         !(dbus_message_iter_close_container(&iter, &sub)))
    434         return -1;
    435 
    436     return 0;
    437 }
    438