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 47DBusHandlerResult 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 65DBusHandlerResult 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 76DBusHandlerResult 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 87DBusHandlerResult 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 98DBusHandlerResult 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 109DBusHandlerResult 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 119DBusHandlerResult 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 130void 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 141const 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 153const 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 162static 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 209fail: 210 if (fd >= 0) 211 close(fd); 212 213 if (buf) 214 avahi_free(buf); 215 216 return NULL; 217 218} 219 220DBusHandlerResult 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 249fail: 250 if (dbus_error_is_set(&error)) 251 dbus_error_free(&error); 252 253 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 254 255} 256 257void 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 278int 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 302fail: 303 avahi_log_warn("Error parsing data"); 304 305 *rdata = NULL; 306 size = 0; 307 return -1; 308} 309 310int 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 360fail: 361 avahi_log_warn("Error parsing TXT data"); 362 363 avahi_string_list_free(strlst); 364 *l = NULL; 365 return -1; 366} 367 368int 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 382int 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} 396