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
avahi_dbus_respond_error(DBusConnection * c,DBusMessage * m,int error,const char * text)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
avahi_dbus_respond_string(DBusConnection * c,DBusMessage * m,const char * text)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
avahi_dbus_respond_int32(DBusConnection * c,DBusMessage * m,int32_t i)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
avahi_dbus_respond_uint32(DBusConnection * c,DBusMessage * m,uint32_t u)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
avahi_dbus_respond_boolean(DBusConnection * c,DBusMessage * m,int b)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
avahi_dbus_respond_ok(DBusConnection * c,DBusMessage * m)137 DBusHandlerResult avahi_dbus_respond_ok(DBusConnection *c, DBusMessage *m) {
138 DBusMessage *reply;
139
140 if (dbus_message_get_no_reply(m))
141 return DBUS_HANDLER_RESULT_HANDLED;
142
143 reply = dbus_message_new_method_return(m);
144
145 if (!reply) {
146 avahi_log_error("Failed allocate message");
147 return DBUS_HANDLER_RESULT_NEED_MEMORY;
148 }
149
150 dbus_connection_send(c, reply, NULL);
151 dbus_message_unref(reply);
152
153 return DBUS_HANDLER_RESULT_HANDLED;
154 }
155
avahi_dbus_respond_path(DBusConnection * c,DBusMessage * m,const char * path)156 DBusHandlerResult avahi_dbus_respond_path(DBusConnection *c, DBusMessage *m, const char *path) {
157 DBusMessage *reply;
158
159 reply = dbus_message_new_method_return(m);
160
161 if (!reply) {
162 avahi_log_error("Failed allocate message");
163 return DBUS_HANDLER_RESULT_NEED_MEMORY;
164 }
165
166 dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
167 dbus_connection_send(c, reply, NULL);
168 dbus_message_unref(reply);
169
170 return DBUS_HANDLER_RESULT_HANDLED;
171 }
172
avahi_dbus_append_server_error(DBusMessage * reply)173 void avahi_dbus_append_server_error(DBusMessage *reply) {
174 const char *t;
175
176 t = avahi_error_number_to_dbus(avahi_server_errno(avahi_server));
177
178 dbus_message_append_args(
179 reply,
180 DBUS_TYPE_STRING, &t,
181 DBUS_TYPE_INVALID);
182 }
183
avahi_dbus_map_browse_signal_name(AvahiBrowserEvent e)184 const char *avahi_dbus_map_browse_signal_name(AvahiBrowserEvent e) {
185 switch (e) {
186 case AVAHI_BROWSER_NEW : return "ItemNew";
187 case AVAHI_BROWSER_REMOVE : return "ItemRemove";
188 case AVAHI_BROWSER_FAILURE : return "Failure";
189 case AVAHI_BROWSER_CACHE_EXHAUSTED : return "CacheExhausted";
190 case AVAHI_BROWSER_ALL_FOR_NOW : return "AllForNow";
191 }
192
193 abort();
194 }
195
avahi_dbus_map_resolve_signal_name(AvahiResolverEvent e)196 const char *avahi_dbus_map_resolve_signal_name(AvahiResolverEvent e) {
197 switch (e) {
198 case AVAHI_RESOLVER_FOUND : return "Found";
199 case AVAHI_RESOLVER_FAILURE : return "Failure";
200 }
201
202 abort();
203 }
204
file_get_contents(const char * fname)205 static char *file_get_contents(const char *fname) {
206 int fd = -1;
207 struct stat st;
208 ssize_t size;
209 char *buf = NULL;
210
211 assert(fname);
212
213 #ifdef ENABLE_CHROOT
214 fd = avahi_chroot_helper_get_fd(fname);
215 #else
216 fd = open(fname, O_RDONLY);
217 #endif
218
219 if (fd < 0) {
220 avahi_log_error("Failed to open %s: %s", fname, strerror(errno));
221 goto fail;
222 }
223
224 if (fstat(fd, &st) < 0) {
225 avahi_log_error("stat(%s) failed: %s", fname, strerror(errno));
226 goto fail;
227 }
228
229 if (!(S_ISREG(st.st_mode))) {
230 avahi_log_error("Invalid file %s", fname);
231 goto fail;
232 }
233
234 if (st.st_size > 1024*1024) { /** 1MB */
235 avahi_log_error("File too large %s", fname);
236 goto fail;
237 }
238
239 buf = avahi_new(char, st.st_size+1);
240
241 if ((size = read(fd, buf, st.st_size)) < 0) {
242 avahi_log_error("read() failed: %s\n", strerror(errno));
243 goto fail;
244 }
245
246 buf[size] = 0;
247
248 close(fd);
249
250 return buf;
251
252 fail:
253 if (fd >= 0)
254 close(fd);
255
256 if (buf)
257 avahi_free(buf);
258
259 return NULL;
260
261 }
262
avahi_dbus_handle_introspect(DBusConnection * c,DBusMessage * m,const char * fname)263 DBusHandlerResult avahi_dbus_handle_introspect(DBusConnection *c, DBusMessage *m, const char *fname) {
264 char *contents, *path;
265 DBusError error;
266
267 assert(c);
268 assert(m);
269 assert(fname);
270
271 dbus_error_init(&error);
272
273 if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
274 avahi_log_error("Error parsing Introspect message: %s", error.message);
275 goto fail;
276 }
277
278 path = avahi_strdup_printf("%s/%s", AVAHI_DBUS_INTROSPECTION_DIR, fname);
279 contents = file_get_contents(path);
280 avahi_free(path);
281
282 if (!contents) {
283 avahi_log_error("Failed to load introspection data.");
284 goto fail;
285 }
286
287 avahi_dbus_respond_string(c, m, contents);
288 avahi_free(contents);
289
290 return DBUS_HANDLER_RESULT_HANDLED;
291
292 fail:
293 if (dbus_error_is_set(&error))
294 dbus_error_free(&error);
295
296 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
297
298 }
299
avahi_dbus_append_string_list(DBusMessage * reply,AvahiStringList * txt)300 void avahi_dbus_append_string_list(DBusMessage *reply, AvahiStringList *txt) {
301 AvahiStringList *p;
302 DBusMessageIter iter, sub;
303
304 assert(reply);
305
306 dbus_message_iter_init_append(reply, &iter);
307 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "ay", &sub);
308
309 for (p = txt; p; p = p->next) {
310 DBusMessageIter sub2;
311 const uint8_t *data = p->text;
312
313 dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "y", &sub2);
314 dbus_message_iter_append_fixed_array(&sub2, DBUS_TYPE_BYTE, &data, p->size);
315 dbus_message_iter_close_container(&sub, &sub2);
316
317 }
318 dbus_message_iter_close_container(&iter, &sub);
319 }
320
avahi_dbus_read_rdata(DBusMessage * m,int idx,void ** rdata,uint32_t * size)321 int avahi_dbus_read_rdata(DBusMessage *m, int idx, void **rdata, uint32_t *size) {
322 DBusMessageIter iter, sub;
323 int n, j;
324 uint8_t *k;
325
326 assert(m);
327
328 dbus_message_iter_init(m, &iter);
329
330 for (j = 0; j < idx; j++)
331 dbus_message_iter_next(&iter);
332
333 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
334 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE)
335 goto fail;
336
337 dbus_message_iter_recurse(&iter, &sub);
338 dbus_message_iter_get_fixed_array(&sub, &k, &n);
339
340 *rdata = k;
341 *size = n;
342
343 return 0;
344
345 fail:
346 avahi_log_warn("Error parsing data");
347
348 *rdata = NULL;
349 size = 0;
350 return -1;
351 }
352
avahi_dbus_read_strlst(DBusMessage * m,int idx,AvahiStringList ** l)353 int avahi_dbus_read_strlst(DBusMessage *m, int idx, AvahiStringList **l) {
354 DBusMessageIter iter, sub;
355 int j;
356 AvahiStringList *strlst = NULL;
357
358 assert(m);
359 assert(l);
360
361 dbus_message_iter_init(m, &iter);
362
363 for (j = 0; j < idx; j++)
364 dbus_message_iter_next(&iter);
365
366 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
367 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_ARRAY)
368 goto fail;
369
370 dbus_message_iter_recurse(&iter, &sub);
371
372 for (;;) {
373 int at, n;
374 const uint8_t *k;
375 DBusMessageIter sub2;
376
377 if ((at = dbus_message_iter_get_arg_type(&sub)) == DBUS_TYPE_INVALID)
378 break;
379
380 assert(at == DBUS_TYPE_ARRAY);
381
382 if (dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_BYTE)
383 goto fail;
384
385 dbus_message_iter_recurse(&sub, &sub2);
386
387 k = (const uint8_t*) "";
388 n = 0;
389 dbus_message_iter_get_fixed_array(&sub2, &k, &n);
390
391 if (!k)
392 k = (const uint8_t*) "";
393
394 strlst = avahi_string_list_add_arbitrary(strlst, k, n);
395
396 dbus_message_iter_next(&sub);
397 }
398
399 *l = strlst;
400
401 return 0;
402
403 fail:
404 avahi_log_warn("Error parsing TXT data");
405
406 avahi_string_list_free(strlst);
407 *l = NULL;
408 return -1;
409 }
410
avahi_dbus_is_our_own_service(Client * c,AvahiIfIndex interface,AvahiProtocol protocol,const char * name,const char * type,const char * domain)411 int avahi_dbus_is_our_own_service(Client *c, AvahiIfIndex interface, AvahiProtocol protocol, const char *name, const char *type, const char *domain) {
412 AvahiSEntryGroup *g;
413
414 if (avahi_server_get_group_of_service(avahi_server, interface, protocol, name, type, domain, &g) == AVAHI_OK) {
415 EntryGroupInfo *egi;
416
417 for (egi = c->entry_groups; egi; egi = egi->entry_groups_next)
418 if (egi->entry_group == g)
419 return 1;
420 }
421
422 return 0;
423 }
424
avahi_dbus_append_rdata(DBusMessage * message,const void * rdata,size_t size)425 int avahi_dbus_append_rdata(DBusMessage *message, const void *rdata, size_t size) {
426 DBusMessageIter iter, sub;
427
428 assert(message);
429
430 dbus_message_iter_init_append(message, &iter);
431
432 if (!(dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &sub)) ||
433 !(dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &rdata, size)) ||
434 !(dbus_message_iter_close_container(&iter, &sub)))
435 return -1;
436
437 return 0;
438 }
439