]> git.meshlink.io Git - catta/blob - avahi-daemon/dbus-util.c
fix avahi_netlink_new to allow multiple netlinks per process
[catta] / avahi-daemon / dbus-util.c
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/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     char *contents, *path;
262     DBusError error;
263
264     assert(c);
265     assert(m);
266     assert(fname);
267
268     dbus_error_init(&error);
269
270     if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
271         avahi_log_error("Error parsing Introspect message: %s", error.message);
272         goto fail;
273     }
274
275     path = avahi_strdup_printf("%s/%s", AVAHI_DBUS_INTROSPECTION_DIR, fname);
276     contents = file_get_contents(path);
277     avahi_free(path);
278
279     if (!contents) {
280         avahi_log_error("Failed to load introspection data.");
281         goto fail;
282     }
283
284     avahi_dbus_respond_string(c, m, contents);
285     avahi_free(contents);
286
287     return DBUS_HANDLER_RESULT_HANDLED;
288
289 fail:
290     if (dbus_error_is_set(&error))
291         dbus_error_free(&error);
292
293     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
294
295 }
296
297 void avahi_dbus_append_string_list(DBusMessage *reply, AvahiStringList *txt) {
298     AvahiStringList *p;
299     DBusMessageIter iter, sub;
300
301     assert(reply);
302
303     dbus_message_iter_init_append(reply, &iter);
304     dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "ay", &sub);
305
306     for (p = txt; p; p = p->next) {
307         DBusMessageIter sub2;
308         const uint8_t *data = p->text;
309
310         dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "y", &sub2);
311         dbus_message_iter_append_fixed_array(&sub2, DBUS_TYPE_BYTE, &data, p->size);
312         dbus_message_iter_close_container(&sub, &sub2);
313
314     }
315     dbus_message_iter_close_container(&iter, &sub);
316 }
317
318 int avahi_dbus_read_rdata(DBusMessage *m, int idx, void **rdata, uint32_t *size) {
319     DBusMessageIter iter, sub;
320     int n, j;
321     uint8_t *k;
322
323     assert(m);
324
325     dbus_message_iter_init(m, &iter);
326
327     for (j = 0; j < idx; j++)
328        dbus_message_iter_next(&iter);
329
330     if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
331         dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE)
332         goto fail;
333
334     dbus_message_iter_recurse(&iter, &sub);
335     dbus_message_iter_get_fixed_array(&sub, &k, &n);
336
337     *rdata = k;
338     *size = n;
339
340     return 0;
341
342 fail:
343     avahi_log_warn("Error parsing data");
344
345     *rdata = NULL;
346     size = 0;
347     return -1;
348 }
349
350 int avahi_dbus_read_strlst(DBusMessage *m, int idx, AvahiStringList **l) {
351     DBusMessageIter iter, sub;
352     int j;
353     AvahiStringList *strlst = NULL;
354
355     assert(m);
356     assert(l);
357
358     dbus_message_iter_init(m, &iter);
359
360     for (j = 0; j < idx; j++)
361         dbus_message_iter_next(&iter);
362
363     if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
364         dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_ARRAY)
365         goto fail;
366
367     dbus_message_iter_recurse(&iter, &sub);
368
369     for (;;) {
370         int at, n;
371         const uint8_t *k;
372         DBusMessageIter sub2;
373
374         if ((at = dbus_message_iter_get_arg_type(&sub)) == DBUS_TYPE_INVALID)
375             break;
376
377         assert(at == DBUS_TYPE_ARRAY);
378
379         if (dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_BYTE)
380             goto fail;
381
382         dbus_message_iter_recurse(&sub, &sub2);
383
384         k = (const uint8_t*) "";
385         n = 0;
386         dbus_message_iter_get_fixed_array(&sub2, &k, &n);
387
388         if (!k)
389             k = (const uint8_t*) "";
390
391         strlst = avahi_string_list_add_arbitrary(strlst, k, n);
392
393         dbus_message_iter_next(&sub);
394     }
395
396     *l = strlst;
397
398     return 0;
399
400 fail:
401     avahi_log_warn("Error parsing TXT data");
402
403     avahi_string_list_free(strlst);
404     *l = NULL;
405     return -1;
406 }
407
408 int avahi_dbus_is_our_own_service(Client *c, AvahiIfIndex interface, AvahiProtocol protocol, const char *name, const char *type, const char *domain) {
409     AvahiSEntryGroup *g;
410
411     if (avahi_server_get_group_of_service(avahi_server, interface, protocol, name, type, domain, &g) == AVAHI_OK) {
412         EntryGroupInfo *egi;
413
414         for (egi = c->entry_groups; egi; egi = egi->entry_groups_next)
415             if (egi->entry_group == g)
416                 return 1;
417     }
418
419     return 0;
420 }
421
422 int avahi_dbus_append_rdata(DBusMessage *message, const void *rdata, size_t size) {
423     DBusMessageIter iter, sub;
424
425     assert(message);
426
427     dbus_message_iter_init_append(message, &iter);
428
429     if (!(dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &sub)) ||
430         !(dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &rdata, size)) ||
431         !(dbus_message_iter_close_container(&iter, &sub)))
432         return -1;
433
434     return 0;
435 }