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 45DBusHandlerResult 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 69DBusHandlerResult 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 86DBusHandlerResult 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 103DBusHandlerResult 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 120DBusHandlerResult 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 137DBusHandlerResult 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 153DBusHandlerResult 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 170void 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 181const 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 193const 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 202static 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 249fail: 250 if (fd >= 0) 251 close(fd); 252 253 if (buf) 254 avahi_free(buf); 255 256 return NULL; 257 258} 259 260DBusHandlerResult 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 289fail: 290 if (dbus_error_is_set(&error)) 291 dbus_error_free(&error); 292 293 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 294 295} 296 297void 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 318int 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 342fail: 343 avahi_log_warn("Error parsing data"); 344 345 *rdata = NULL; 346 size = 0; 347 return -1; 348} 349 350int 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 400fail: 401 avahi_log_warn("Error parsing TXT data"); 402 403 avahi_string_list_free(strlst); 404 *l = NULL; 405 return -1; 406} 407 408int 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 422int 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} 436