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