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