1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 2 /* signals.c Bus signal connection implementation 3 * 4 * Copyright (C) 2003, 2005 Red Hat, Inc. 5 * 6 * Licensed under the Academic Free License version 2.1 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 * 22 */ 23 24 #include <config.h> 25 #include "signals.h" 26 #include "services.h" 27 #include "utils.h" 28 #include <dbus/dbus-marshal-validate.h> 29 30 struct BusMatchRule 31 { 32 int refcount; /**< reference count */ 33 34 DBusConnection *matches_go_to; /**< Owner of the rule */ 35 36 unsigned int flags; /**< BusMatchFlags */ 37 38 int message_type; 39 char *interface; 40 char *member; 41 char *sender; 42 char *destination; 43 char *path; 44 45 unsigned int *arg_lens; 46 char **args; 47 int args_len; 48 }; 49 50 #define BUS_MATCH_ARG_NAMESPACE 0x4000000u 51 #define BUS_MATCH_ARG_IS_PATH 0x8000000u 52 53 #define BUS_MATCH_ARG_FLAGS (BUS_MATCH_ARG_NAMESPACE | BUS_MATCH_ARG_IS_PATH) 54 55 BusMatchRule* 56 bus_match_rule_new (DBusConnection *matches_go_to) 57 { 58 BusMatchRule *rule; 59 60 rule = dbus_new0 (BusMatchRule, 1); 61 if (rule == NULL) 62 return NULL; 63 64 rule->refcount = 1; 65 rule->matches_go_to = matches_go_to; 66 67 #ifndef DBUS_BUILD_TESTS 68 _dbus_assert (rule->matches_go_to != NULL); 69 #endif 70 71 return rule; 72 } 73 74 BusMatchRule * 75 bus_match_rule_ref (BusMatchRule *rule) 76 { 77 _dbus_assert (rule->refcount > 0); 78 79 rule->refcount += 1; 80 81 return rule; 82 } 83 84 void 85 bus_match_rule_unref (BusMatchRule *rule) 86 { 87 _dbus_assert (rule->refcount > 0); 88 89 rule->refcount -= 1; 90 if (rule->refcount == 0) 91 { 92 dbus_free (rule->interface); 93 dbus_free (rule->member); 94 dbus_free (rule->sender); 95 dbus_free (rule->destination); 96 dbus_free (rule->path); 97 dbus_free (rule->arg_lens); 98 99 /* can't use dbus_free_string_array() since there 100 * are embedded NULL 101 */ 102 if (rule->args) 103 { 104 int i; 105 106 i = 0; 107 while (i < rule->args_len) 108 { 109 if (rule->args[i]) 110 dbus_free (rule->args[i]); 111 ++i; 112 } 113 114 dbus_free (rule->args); 115 } 116 117 dbus_free (rule); 118 } 119 } 120 121 #ifdef DBUS_ENABLE_VERBOSE_MODE 122 /* Note this function does not do escaping, so it's only 123 * good for debug spew at the moment 124 */ 125 static char* 126 match_rule_to_string (BusMatchRule *rule) 127 { 128 DBusString str; 129 char *ret; 130 131 if (!_dbus_string_init (&str)) 132 { 133 char *s; 134 while ((s = _dbus_strdup ("nomem")) == NULL) 135 ; /* only OK for debug spew... */ 136 return s; 137 } 138 139 if (rule->flags & BUS_MATCH_MESSAGE_TYPE) 140 { 141 if (!_dbus_string_append_printf (&str, "type='%s'", 142 dbus_message_type_to_string (rule->message_type))) 143 goto nomem; 144 } 145 146 if (rule->flags & BUS_MATCH_INTERFACE) 147 { 148 if (_dbus_string_get_length (&str) > 0) 149 { 150 if (!_dbus_string_append (&str, ",")) 151 goto nomem; 152 } 153 154 if (!_dbus_string_append_printf (&str, "interface='%s'", rule->interface)) 155 goto nomem; 156 } 157 158 if (rule->flags & BUS_MATCH_MEMBER) 159 { 160 if (_dbus_string_get_length (&str) > 0) 161 { 162 if (!_dbus_string_append (&str, ",")) 163 goto nomem; 164 } 165 166 if (!_dbus_string_append_printf (&str, "member='%s'", rule->member)) 167 goto nomem; 168 } 169 170 if (rule->flags & BUS_MATCH_PATH) 171 { 172 if (_dbus_string_get_length (&str) > 0) 173 { 174 if (!_dbus_string_append (&str, ",")) 175 goto nomem; 176 } 177 178 if (!_dbus_string_append_printf (&str, "path='%s'", rule->path)) 179 goto nomem; 180 } 181 182 if (rule->flags & BUS_MATCH_PATH_NAMESPACE) 183 { 184 if (_dbus_string_get_length (&str) > 0) 185 { 186 if (!_dbus_string_append (&str, ",")) 187 goto nomem; 188 } 189 190 if (!_dbus_string_append_printf (&str, "path_namespace='%s'", rule->path)) 191 goto nomem; 192 } 193 194 if (rule->flags & BUS_MATCH_SENDER) 195 { 196 if (_dbus_string_get_length (&str) > 0) 197 { 198 if (!_dbus_string_append (&str, ",")) 199 goto nomem; 200 } 201 202 if (!_dbus_string_append_printf (&str, "sender='%s'", rule->sender)) 203 goto nomem; 204 } 205 206 if (rule->flags & BUS_MATCH_DESTINATION) 207 { 208 if (_dbus_string_get_length (&str) > 0) 209 { 210 if (!_dbus_string_append (&str, ",")) 211 goto nomem; 212 } 213 214 if (!_dbus_string_append_printf (&str, "destination='%s'", rule->destination)) 215 goto nomem; 216 } 217 218 if (rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING) 219 { 220 if (_dbus_string_get_length (&str) > 0) 221 { 222 if (!_dbus_string_append (&str, ",")) 223 goto nomem; 224 } 225 226 if (!_dbus_string_append_printf (&str, "eavesdrop='%s'", 227 (rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING) ? 228 "true" : "false")) 229 goto nomem; 230 } 231 232 if (rule->flags & BUS_MATCH_ARGS) 233 { 234 int i; 235 236 _dbus_assert (rule->args != NULL); 237 238 i = 0; 239 while (i < rule->args_len) 240 { 241 if (rule->args[i] != NULL) 242 { 243 dbus_bool_t is_path, is_namespace; 244 245 if (_dbus_string_get_length (&str) > 0) 246 { 247 if (!_dbus_string_append (&str, ",")) 248 goto nomem; 249 } 250 251 is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0; 252 is_namespace = (rule->arg_lens[i] & BUS_MATCH_ARG_NAMESPACE) != 0; 253 254 if (!_dbus_string_append_printf (&str, 255 "arg%d%s='%s'", 256 i, 257 is_path ? "path" : 258 is_namespace ? "namespace" : "", 259 rule->args[i])) 260 goto nomem; 261 } 262 263 ++i; 264 } 265 } 266 267 if (!_dbus_string_steal_data (&str, &ret)) 268 goto nomem; 269 270 _dbus_string_free (&str); 271 return ret; 272 273 nomem: 274 _dbus_string_free (&str); 275 { 276 char *s; 277 while ((s = _dbus_strdup ("nomem")) == NULL) 278 ; /* only OK for debug spew... */ 279 return s; 280 } 281 } 282 #endif /* DBUS_ENABLE_VERBOSE_MODE */ 283 284 dbus_bool_t 285 bus_match_rule_set_message_type (BusMatchRule *rule, 286 int type) 287 { 288 rule->flags |= BUS_MATCH_MESSAGE_TYPE; 289 290 rule->message_type = type; 291 292 return TRUE; 293 } 294 295 dbus_bool_t 296 bus_match_rule_set_interface (BusMatchRule *rule, 297 const char *interface) 298 { 299 char *new; 300 301 _dbus_assert (interface != NULL); 302 303 new = _dbus_strdup (interface); 304 if (new == NULL) 305 return FALSE; 306 307 rule->flags |= BUS_MATCH_INTERFACE; 308 dbus_free (rule->interface); 309 rule->interface = new; 310 311 return TRUE; 312 } 313 314 dbus_bool_t 315 bus_match_rule_set_member (BusMatchRule *rule, 316 const char *member) 317 { 318 char *new; 319 320 _dbus_assert (member != NULL); 321 322 new = _dbus_strdup (member); 323 if (new == NULL) 324 return FALSE; 325 326 rule->flags |= BUS_MATCH_MEMBER; 327 dbus_free (rule->member); 328 rule->member = new; 329 330 return TRUE; 331 } 332 333 dbus_bool_t 334 bus_match_rule_set_sender (BusMatchRule *rule, 335 const char *sender) 336 { 337 char *new; 338 339 _dbus_assert (sender != NULL); 340 341 new = _dbus_strdup (sender); 342 if (new == NULL) 343 return FALSE; 344 345 rule->flags |= BUS_MATCH_SENDER; 346 dbus_free (rule->sender); 347 rule->sender = new; 348 349 return TRUE; 350 } 351 352 dbus_bool_t 353 bus_match_rule_set_destination (BusMatchRule *rule, 354 const char *destination) 355 { 356 char *new; 357 358 _dbus_assert (destination != NULL); 359 360 new = _dbus_strdup (destination); 361 if (new == NULL) 362 return FALSE; 363 364 rule->flags |= BUS_MATCH_DESTINATION; 365 dbus_free (rule->destination); 366 rule->destination = new; 367 368 return TRUE; 369 } 370 371 void 372 bus_match_rule_set_client_is_eavesdropping (BusMatchRule *rule, 373 dbus_bool_t is_eavesdropping) 374 { 375 if (is_eavesdropping) 376 rule->flags |= BUS_MATCH_CLIENT_IS_EAVESDROPPING; 377 else 378 rule->flags &= ~(BUS_MATCH_CLIENT_IS_EAVESDROPPING); 379 } 380 381 dbus_bool_t 382 bus_match_rule_set_path (BusMatchRule *rule, 383 const char *path, 384 dbus_bool_t is_namespace) 385 { 386 char *new; 387 388 _dbus_assert (path != NULL); 389 390 new = _dbus_strdup (path); 391 if (new == NULL) 392 return FALSE; 393 394 rule->flags &= ~(BUS_MATCH_PATH|BUS_MATCH_PATH_NAMESPACE); 395 396 if (is_namespace) 397 rule->flags |= BUS_MATCH_PATH_NAMESPACE; 398 else 399 rule->flags |= BUS_MATCH_PATH; 400 401 dbus_free (rule->path); 402 rule->path = new; 403 404 return TRUE; 405 } 406 407 dbus_bool_t 408 bus_match_rule_set_arg (BusMatchRule *rule, 409 int arg, 410 const DBusString *value, 411 dbus_bool_t is_path, 412 dbus_bool_t is_namespace) 413 { 414 int length; 415 char *new; 416 417 _dbus_assert (value != NULL); 418 419 /* args_len is the number of args not including null termination 420 * in the char** 421 */ 422 if (arg >= rule->args_len) 423 { 424 unsigned int *new_arg_lens; 425 char **new_args; 426 int new_args_len; 427 int i; 428 429 new_args_len = arg + 1; 430 431 /* add another + 1 here for null termination */ 432 new_args = dbus_realloc (rule->args, 433 sizeof (char *) * (new_args_len + 1)); 434 if (new_args == NULL) 435 return FALSE; 436 437 /* NULL the new slots */ 438 i = rule->args_len; 439 while (i <= new_args_len) /* <= for null termination */ 440 { 441 new_args[i] = NULL; 442 ++i; 443 } 444 445 rule->args = new_args; 446 447 /* and now add to the lengths */ 448 new_arg_lens = dbus_realloc (rule->arg_lens, 449 sizeof (int) * (new_args_len + 1)); 450 451 if (new_arg_lens == NULL) 452 return FALSE; 453 454 /* zero the new slots */ 455 i = rule->args_len; 456 while (i <= new_args_len) /* <= for null termination */ 457 { 458 new_arg_lens[i] = 0; 459 ++i; 460 } 461 462 rule->arg_lens = new_arg_lens; 463 rule->args_len = new_args_len; 464 } 465 466 length = _dbus_string_get_length (value); 467 if (!_dbus_string_copy_data (value, &new)) 468 return FALSE; 469 470 rule->flags |= BUS_MATCH_ARGS; 471 472 dbus_free (rule->args[arg]); 473 rule->arg_lens[arg] = length; 474 rule->args[arg] = new; 475 476 if (is_path) 477 rule->arg_lens[arg] |= BUS_MATCH_ARG_IS_PATH; 478 479 if (is_namespace) 480 rule->arg_lens[arg] |= BUS_MATCH_ARG_NAMESPACE; 481 482 /* NULL termination didn't get busted */ 483 _dbus_assert (rule->args[rule->args_len] == NULL); 484 _dbus_assert (rule->arg_lens[rule->args_len] == 0); 485 486 return TRUE; 487 } 488 489 #define ISWHITE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r')) 490 491 static dbus_bool_t 492 find_key (const DBusString *str, 493 int start, 494 DBusString *key, 495 int *value_pos, 496 DBusError *error) 497 { 498 const char *p; 499 const char *s; 500 const char *key_start; 501 const char *key_end; 502 503 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 504 505 s = _dbus_string_get_const_data (str); 506 507 p = s + start; 508 509 while (*p && ISWHITE (*p)) 510 ++p; 511 512 key_start = p; 513 514 while (*p && *p != '=' && !ISWHITE (*p)) 515 ++p; 516 517 key_end = p; 518 519 while (*p && ISWHITE (*p)) 520 ++p; 521 522 if (key_start == key_end) 523 { 524 /* Empty match rules or trailing whitespace are OK */ 525 *value_pos = p - s; 526 return TRUE; 527 } 528 529 if (*p != '=') 530 { 531 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 532 "Match rule has a key with no subsequent '=' character"); 533 return FALSE; 534 } 535 ++p; 536 537 if (!_dbus_string_append_len (key, key_start, key_end - key_start)) 538 { 539 BUS_SET_OOM (error); 540 return FALSE; 541 } 542 543 *value_pos = p - s; 544 545 return TRUE; 546 } 547 548 static dbus_bool_t 549 find_value (const DBusString *str, 550 int start, 551 const char *key, 552 DBusString *value, 553 int *value_end, 554 DBusError *error) 555 { 556 const char *p; 557 const char *s; 558 char quote_char; 559 int orig_len; 560 561 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 562 563 orig_len = _dbus_string_get_length (value); 564 565 s = _dbus_string_get_const_data (str); 566 567 p = s + start; 568 569 quote_char = '\0'; 570 571 while (*p) 572 { 573 if (quote_char == '\0') 574 { 575 switch (*p) 576 { 577 case '\0': 578 goto done; 579 580 case '\'': 581 quote_char = '\''; 582 goto next; 583 584 case ',': 585 ++p; 586 goto done; 587 588 case '\\': 589 quote_char = '\\'; 590 goto next; 591 592 default: 593 if (!_dbus_string_append_byte (value, *p)) 594 { 595 BUS_SET_OOM (error); 596 goto failed; 597 } 598 } 599 } 600 else if (quote_char == '\\') 601 { 602 /* \ only counts as an escape if escaping a quote mark */ 603 if (*p != '\'') 604 { 605 if (!_dbus_string_append_byte (value, '\\')) 606 { 607 BUS_SET_OOM (error); 608 goto failed; 609 } 610 } 611 612 if (!_dbus_string_append_byte (value, *p)) 613 { 614 BUS_SET_OOM (error); 615 goto failed; 616 } 617 618 quote_char = '\0'; 619 } 620 else 621 { 622 _dbus_assert (quote_char == '\''); 623 624 if (*p == '\'') 625 { 626 quote_char = '\0'; 627 } 628 else 629 { 630 if (!_dbus_string_append_byte (value, *p)) 631 { 632 BUS_SET_OOM (error); 633 goto failed; 634 } 635 } 636 } 637 638 next: 639 ++p; 640 } 641 642 done: 643 644 if (quote_char == '\\') 645 { 646 if (!_dbus_string_append_byte (value, '\\')) 647 { 648 BUS_SET_OOM (error); 649 goto failed; 650 } 651 } 652 else if (quote_char == '\'') 653 { 654 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 655 "Unbalanced quotation marks in match rule"); 656 goto failed; 657 } 658 else 659 _dbus_assert (quote_char == '\0'); 660 661 /* Zero-length values are allowed */ 662 663 *value_end = p - s; 664 665 return TRUE; 666 667 failed: 668 _DBUS_ASSERT_ERROR_IS_SET (error); 669 _dbus_string_set_length (value, orig_len); 670 return FALSE; 671 } 672 673 /* duplicates aren't allowed so the real legitimate max is only 6 or 674 * so. Leaving extra so we don't have to bother to update it. 675 * FIXME this is sort of busted now with arg matching, but we let 676 * you match on up to 10 args for now 677 */ 678 #define MAX_RULE_TOKENS 16 679 680 /* this is slightly too high level to be termed a "token" 681 * but let's not be pedantic. 682 */ 683 typedef struct 684 { 685 char *key; 686 char *value; 687 } RuleToken; 688 689 static dbus_bool_t 690 tokenize_rule (const DBusString *rule_text, 691 RuleToken tokens[MAX_RULE_TOKENS], 692 DBusError *error) 693 { 694 int i; 695 int pos; 696 DBusString key; 697 DBusString value; 698 dbus_bool_t retval; 699 700 retval = FALSE; 701 702 if (!_dbus_string_init (&key)) 703 { 704 BUS_SET_OOM (error); 705 return FALSE; 706 } 707 708 if (!_dbus_string_init (&value)) 709 { 710 _dbus_string_free (&key); 711 BUS_SET_OOM (error); 712 return FALSE; 713 } 714 715 i = 0; 716 pos = 0; 717 while (i < MAX_RULE_TOKENS && 718 pos < _dbus_string_get_length (rule_text)) 719 { 720 _dbus_assert (tokens[i].key == NULL); 721 _dbus_assert (tokens[i].value == NULL); 722 723 if (!find_key (rule_text, pos, &key, &pos, error)) 724 goto out; 725 726 if (_dbus_string_get_length (&key) == 0) 727 goto next; 728 729 if (!_dbus_string_steal_data (&key, &tokens[i].key)) 730 { 731 BUS_SET_OOM (error); 732 goto out; 733 } 734 735 if (!find_value (rule_text, pos, tokens[i].key, &value, &pos, error)) 736 goto out; 737 738 if (!_dbus_string_steal_data (&value, &tokens[i].value)) 739 { 740 BUS_SET_OOM (error); 741 goto out; 742 } 743 744 next: 745 ++i; 746 } 747 748 retval = TRUE; 749 750 out: 751 if (!retval) 752 { 753 i = 0; 754 while (tokens[i].key || tokens[i].value) 755 { 756 dbus_free (tokens[i].key); 757 dbus_free (tokens[i].value); 758 tokens[i].key = NULL; 759 tokens[i].value = NULL; 760 ++i; 761 } 762 } 763 764 _dbus_string_free (&key); 765 _dbus_string_free (&value); 766 767 return retval; 768 } 769 770 static dbus_bool_t 771 bus_match_rule_parse_arg_match (BusMatchRule *rule, 772 const char *key, 773 const DBusString *value, 774 DBusError *error) 775 { 776 dbus_bool_t is_path = FALSE; 777 dbus_bool_t is_namespace = FALSE; 778 DBusString key_str; 779 unsigned long arg; 780 int length; 781 int end; 782 783 /* For now, arg0='foo' always implies that 'foo' is a 784 * DBUS_TYPE_STRING. Someday we could add an arg0type='int32' thing 785 * if we wanted, which would specify another type, in which case 786 * arg0='5' would have the 5 parsed as an int rather than string. 787 */ 788 789 /* First we need to parse arg0 = 0, arg27 = 27 */ 790 791 _dbus_string_init_const (&key_str, key); 792 length = _dbus_string_get_length (&key_str); 793 794 if (_dbus_string_get_length (&key_str) < 4) 795 { 796 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 797 "Key '%s' in match rule starts with 'arg' but lacks an arg number. Should be 'arg0' or 'arg7' for example.\n", key); 798 goto failed; 799 } 800 801 if (!_dbus_string_parse_uint (&key_str, 3, &arg, &end)) 802 { 803 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 804 "Key '%s' in match rule starts with 'arg' but could not parse arg number. Should be 'arg0' or 'arg7' for example.\n", key); 805 goto failed; 806 } 807 808 if (end != length) 809 { 810 if ((end + strlen ("path")) == length && 811 _dbus_string_ends_with_c_str (&key_str, "path")) 812 { 813 is_path = TRUE; 814 } 815 else if (_dbus_string_equal_c_str (&key_str, "arg0namespace")) 816 { 817 int value_len = _dbus_string_get_length (value); 818 819 is_namespace = TRUE; 820 821 if (!_dbus_validate_bus_namespace (value, 0, value_len)) 822 { 823 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 824 "arg0namespace='%s' is not a valid prefix of a bus name", 825 _dbus_string_get_const_data (value)); 826 goto failed; 827 } 828 } 829 else 830 { 831 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 832 "Key '%s' in match rule contains junk after argument number (%u). Only 'arg%upath' (for example) or 'arg0namespace' are valid", key, arg, arg); 833 goto failed; 834 } 835 } 836 837 /* If we didn't check this we could allocate a huge amount of RAM */ 838 if (arg > DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER) 839 { 840 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 841 "Key '%s' in match rule has arg number %lu but the maximum is %d.\n", key, (unsigned long) arg, DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER); 842 goto failed; 843 } 844 845 if ((rule->flags & BUS_MATCH_ARGS) && 846 rule->args_len > (int) arg && 847 rule->args[arg] != NULL) 848 { 849 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 850 "Argument %d matched more than once in match rule\n", key); 851 goto failed; 852 } 853 854 if (!bus_match_rule_set_arg (rule, arg, value, is_path, is_namespace)) 855 { 856 BUS_SET_OOM (error); 857 goto failed; 858 } 859 860 return TRUE; 861 862 failed: 863 _DBUS_ASSERT_ERROR_IS_SET (error); 864 return FALSE; 865 } 866 867 /* 868 * The format is comma-separated with strings quoted with single quotes 869 * as for the shell (to escape a literal single quote, use '\''). 870 * 871 * type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo', 872 * path='/bar/foo',destination=':452345.34' 873 * 874 */ 875 BusMatchRule* 876 bus_match_rule_parse (DBusConnection *matches_go_to, 877 const DBusString *rule_text, 878 DBusError *error) 879 { 880 BusMatchRule *rule; 881 RuleToken tokens[MAX_RULE_TOKENS+1]; /* NULL termination + 1 */ 882 int i; 883 884 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 885 886 if (_dbus_string_get_length (rule_text) > DBUS_MAXIMUM_MATCH_RULE_LENGTH) 887 { 888 dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, 889 "Match rule text is %d bytes, maximum is %d", 890 _dbus_string_get_length (rule_text), 891 DBUS_MAXIMUM_MATCH_RULE_LENGTH); 892 return NULL; 893 } 894 895 memset (tokens, '\0', sizeof (tokens)); 896 897 rule = bus_match_rule_new (matches_go_to); 898 if (rule == NULL) 899 { 900 BUS_SET_OOM (error); 901 goto failed; 902 } 903 904 if (!tokenize_rule (rule_text, tokens, error)) 905 goto failed; 906 907 i = 0; 908 while (tokens[i].key != NULL) 909 { 910 DBusString tmp_str; 911 int len; 912 const char *key = tokens[i].key; 913 const char *value = tokens[i].value; 914 915 _dbus_string_init_const (&tmp_str, value); 916 len = _dbus_string_get_length (&tmp_str); 917 918 if (strcmp (key, "type") == 0) 919 { 920 int t; 921 922 if (rule->flags & BUS_MATCH_MESSAGE_TYPE) 923 { 924 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 925 "Key %s specified twice in match rule\n", key); 926 goto failed; 927 } 928 929 t = dbus_message_type_from_string (value); 930 931 if (t == DBUS_MESSAGE_TYPE_INVALID) 932 { 933 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 934 "Invalid message type (%s) in match rule\n", value); 935 goto failed; 936 } 937 938 if (!bus_match_rule_set_message_type (rule, t)) 939 { 940 BUS_SET_OOM (error); 941 goto failed; 942 } 943 } 944 else if (strcmp (key, "sender") == 0) 945 { 946 if (rule->flags & BUS_MATCH_SENDER) 947 { 948 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 949 "Key %s specified twice in match rule\n", key); 950 goto failed; 951 } 952 953 if (!_dbus_validate_bus_name (&tmp_str, 0, len)) 954 { 955 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 956 "Sender name '%s' is invalid\n", value); 957 goto failed; 958 } 959 960 if (!bus_match_rule_set_sender (rule, value)) 961 { 962 BUS_SET_OOM (error); 963 goto failed; 964 } 965 } 966 else if (strcmp (key, "interface") == 0) 967 { 968 if (rule->flags & BUS_MATCH_INTERFACE) 969 { 970 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 971 "Key %s specified twice in match rule\n", key); 972 goto failed; 973 } 974 975 if (!_dbus_validate_interface (&tmp_str, 0, len)) 976 { 977 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 978 "Interface name '%s' is invalid\n", value); 979 goto failed; 980 } 981 982 if (!bus_match_rule_set_interface (rule, value)) 983 { 984 BUS_SET_OOM (error); 985 goto failed; 986 } 987 } 988 else if (strcmp (key, "member") == 0) 989 { 990 if (rule->flags & BUS_MATCH_MEMBER) 991 { 992 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 993 "Key %s specified twice in match rule\n", key); 994 goto failed; 995 } 996 997 if (!_dbus_validate_member (&tmp_str, 0, len)) 998 { 999 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 1000 "Member name '%s' is invalid\n", value); 1001 goto failed; 1002 } 1003 1004 if (!bus_match_rule_set_member (rule, value)) 1005 { 1006 BUS_SET_OOM (error); 1007 goto failed; 1008 } 1009 } 1010 else if (strcmp (key, "path") == 0 || 1011 strcmp (key, "path_namespace") == 0) 1012 { 1013 dbus_bool_t is_namespace = (strcmp (key, "path_namespace") == 0); 1014 1015 if (rule->flags & (BUS_MATCH_PATH | BUS_MATCH_PATH_NAMESPACE)) 1016 { 1017 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 1018 "path or path_namespace specified twice in match rule\n"); 1019 goto failed; 1020 } 1021 1022 if (!_dbus_validate_path (&tmp_str, 0, len)) 1023 { 1024 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 1025 "Path '%s' is invalid\n", value); 1026 goto failed; 1027 } 1028 1029 if (!bus_match_rule_set_path (rule, value, is_namespace)) 1030 { 1031 BUS_SET_OOM (error); 1032 goto failed; 1033 } 1034 } 1035 else if (strcmp (key, "destination") == 0) 1036 { 1037 if (rule->flags & BUS_MATCH_DESTINATION) 1038 { 1039 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 1040 "Key %s specified twice in match rule\n", key); 1041 goto failed; 1042 } 1043 1044 if (!_dbus_validate_bus_name (&tmp_str, 0, len)) 1045 { 1046 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 1047 "Destination name '%s' is invalid\n", value); 1048 goto failed; 1049 } 1050 1051 if (!bus_match_rule_set_destination (rule, value)) 1052 { 1053 BUS_SET_OOM (error); 1054 goto failed; 1055 } 1056 } 1057 else if (strcmp (key, "eavesdrop") == 0) 1058 { 1059 /* do not detect "eavesdrop" being used more than once in rule: 1060 * 1) it's not possible, it's only in the flags 1061 * 2) it might be used twice to disable eavesdropping when it's 1062 * automatically added (eg dbus-monitor/bustle) */ 1063 1064 /* we accept only "true|false" as possible values */ 1065 if ((strcmp (value, "true") == 0)) 1066 { 1067 bus_match_rule_set_client_is_eavesdropping (rule, TRUE); 1068 } 1069 else if (strcmp (value, "false") == 0) 1070 { 1071 bus_match_rule_set_client_is_eavesdropping (rule, FALSE); 1072 } 1073 else 1074 { 1075 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 1076 "eavesdrop='%s' is invalid, " 1077 "it should be 'true' or 'false'\n", 1078 value); 1079 goto failed; 1080 } 1081 } 1082 else if (strncmp (key, "arg", 3) == 0) 1083 { 1084 if (!bus_match_rule_parse_arg_match (rule, key, &tmp_str, error)) 1085 goto failed; 1086 } 1087 else 1088 { 1089 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 1090 "Unknown key \"%s\" in match rule", 1091 key); 1092 goto failed; 1093 } 1094 1095 ++i; 1096 } 1097 1098 1099 goto out; 1100 1101 failed: 1102 _DBUS_ASSERT_ERROR_IS_SET (error); 1103 if (rule) 1104 { 1105 bus_match_rule_unref (rule); 1106 rule = NULL; 1107 } 1108 1109 out: 1110 1111 i = 0; 1112 while (tokens[i].key || tokens[i].value) 1113 { 1114 _dbus_assert (i < MAX_RULE_TOKENS); 1115 dbus_free (tokens[i].key); 1116 dbus_free (tokens[i].value); 1117 ++i; 1118 } 1119 1120 return rule; 1121 } 1122 1123 typedef struct RulePool RulePool; 1124 struct RulePool 1125 { 1126 /* Maps non-NULL interface names to non-NULL (DBusList **)s */ 1127 DBusHashTable *rules_by_iface; 1128 1129 /* List of BusMatchRules which don't specify an interface */ 1130 DBusList *rules_without_iface; 1131 }; 1132 1133 struct BusMatchmaker 1134 { 1135 int refcount; 1136 1137 /* Pools of rules, grouped by the type of message they match. 0 1138 * (DBUS_MESSAGE_TYPE_INVALID) represents rules that do not specify a message 1139 * type. 1140 */ 1141 RulePool rules_by_type[DBUS_NUM_MESSAGE_TYPES]; 1142 }; 1143 1144 static void 1145 rule_list_free (DBusList **rules) 1146 { 1147 while (*rules != NULL) 1148 { 1149 BusMatchRule *rule; 1150 1151 rule = (*rules)->data; 1152 bus_match_rule_unref (rule); 1153 _dbus_list_remove_link (rules, *rules); 1154 } 1155 } 1156 1157 static void 1158 rule_list_ptr_free (DBusList **list) 1159 { 1160 /* We have to cope with NULL because the hash table frees the "existing" 1161 * value (which is NULL) when creating a new table entry... 1162 */ 1163 if (list != NULL) 1164 { 1165 rule_list_free (list); 1166 dbus_free (list); 1167 } 1168 } 1169 1170 BusMatchmaker* 1171 bus_matchmaker_new (void) 1172 { 1173 BusMatchmaker *matchmaker; 1174 int i; 1175 1176 matchmaker = dbus_new0 (BusMatchmaker, 1); 1177 if (matchmaker == NULL) 1178 return NULL; 1179 1180 matchmaker->refcount = 1; 1181 1182 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++) 1183 { 1184 RulePool *p = matchmaker->rules_by_type + i; 1185 1186 p->rules_by_iface = _dbus_hash_table_new (DBUS_HASH_STRING, 1187 dbus_free, (DBusFreeFunction) rule_list_ptr_free); 1188 1189 if (p->rules_by_iface == NULL) 1190 goto nomem; 1191 } 1192 1193 return matchmaker; 1194 1195 nomem: 1196 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++) 1197 { 1198 RulePool *p = matchmaker->rules_by_type + i; 1199 1200 if (p->rules_by_iface == NULL) 1201 break; 1202 else 1203 _dbus_hash_table_unref (p->rules_by_iface); 1204 } 1205 dbus_free (matchmaker); 1206 1207 return NULL; 1208 } 1209 1210 static DBusList ** 1211 bus_matchmaker_get_rules (BusMatchmaker *matchmaker, 1212 int message_type, 1213 const char *interface, 1214 dbus_bool_t create) 1215 { 1216 RulePool *p; 1217 1218 _dbus_assert (message_type >= 0); 1219 _dbus_assert (message_type < DBUS_NUM_MESSAGE_TYPES); 1220 1221 _dbus_verbose ("Looking up rules for message_type %d, interface %s\n", 1222 message_type, 1223 interface != NULL ? interface : "<null>"); 1224 1225 p = matchmaker->rules_by_type + message_type; 1226 1227 if (interface == NULL) 1228 { 1229 return &p->rules_without_iface; 1230 } 1231 else 1232 { 1233 DBusList **list; 1234 1235 list = _dbus_hash_table_lookup_string (p->rules_by_iface, interface); 1236 1237 if (list == NULL && create) 1238 { 1239 char *dupped_interface; 1240 1241 list = dbus_new0 (DBusList *, 1); 1242 if (list == NULL) 1243 return NULL; 1244 1245 dupped_interface = _dbus_strdup (interface); 1246 if (dupped_interface == NULL) 1247 { 1248 dbus_free (list); 1249 return NULL; 1250 } 1251 1252 _dbus_verbose ("Adding list for type %d, iface %s\n", message_type, 1253 interface); 1254 1255 if (!_dbus_hash_table_insert_string (p->rules_by_iface, 1256 dupped_interface, list)) 1257 { 1258 dbus_free (list); 1259 dbus_free (dupped_interface); 1260 return NULL; 1261 } 1262 } 1263 1264 return list; 1265 } 1266 } 1267 1268 static void 1269 bus_matchmaker_gc_rules (BusMatchmaker *matchmaker, 1270 int message_type, 1271 const char *interface, 1272 DBusList **rules) 1273 { 1274 RulePool *p; 1275 1276 if (interface == NULL) 1277 return; 1278 1279 if (*rules != NULL) 1280 return; 1281 1282 _dbus_verbose ("GCing HT entry for message_type %u, interface %s\n", 1283 message_type, interface); 1284 1285 p = matchmaker->rules_by_type + message_type; 1286 1287 _dbus_assert (_dbus_hash_table_lookup_string (p->rules_by_iface, interface) 1288 == rules); 1289 1290 _dbus_hash_table_remove_string (p->rules_by_iface, interface); 1291 } 1292 1293 BusMatchmaker * 1294 bus_matchmaker_ref (BusMatchmaker *matchmaker) 1295 { 1296 _dbus_assert (matchmaker->refcount > 0); 1297 1298 matchmaker->refcount += 1; 1299 1300 return matchmaker; 1301 } 1302 1303 void 1304 bus_matchmaker_unref (BusMatchmaker *matchmaker) 1305 { 1306 _dbus_assert (matchmaker->refcount > 0); 1307 1308 matchmaker->refcount -= 1; 1309 if (matchmaker->refcount == 0) 1310 { 1311 int i; 1312 1313 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++) 1314 { 1315 RulePool *p = matchmaker->rules_by_type + i; 1316 1317 _dbus_hash_table_unref (p->rules_by_iface); 1318 rule_list_free (&p->rules_without_iface); 1319 } 1320 1321 dbus_free (matchmaker); 1322 } 1323 } 1324 1325 /* The rule can't be modified after it's added. */ 1326 dbus_bool_t 1327 bus_matchmaker_add_rule (BusMatchmaker *matchmaker, 1328 BusMatchRule *rule) 1329 { 1330 DBusList **rules; 1331 1332 _dbus_assert (bus_connection_is_active (rule->matches_go_to)); 1333 1334 _dbus_verbose ("Adding rule with message_type %d, interface %s\n", 1335 rule->message_type, 1336 rule->interface != NULL ? rule->interface : "<null>"); 1337 1338 rules = bus_matchmaker_get_rules (matchmaker, rule->message_type, 1339 rule->interface, TRUE); 1340 1341 if (rules == NULL) 1342 return FALSE; 1343 1344 if (!_dbus_list_append (rules, rule)) 1345 return FALSE; 1346 1347 if (!bus_connection_add_match_rule (rule->matches_go_to, rule)) 1348 { 1349 _dbus_list_remove_last (rules, rule); 1350 bus_matchmaker_gc_rules (matchmaker, rule->message_type, 1351 rule->interface, rules); 1352 return FALSE; 1353 } 1354 1355 bus_match_rule_ref (rule); 1356 1357 #ifdef DBUS_ENABLE_VERBOSE_MODE 1358 { 1359 char *s = match_rule_to_string (rule); 1360 1361 _dbus_verbose ("Added match rule %s to connection %p\n", 1362 s, rule->matches_go_to); 1363 dbus_free (s); 1364 } 1365 #endif 1366 1367 return TRUE; 1368 } 1369 1370 static dbus_bool_t 1371 match_rule_equal (BusMatchRule *a, 1372 BusMatchRule *b) 1373 { 1374 if (a->flags != b->flags) 1375 return FALSE; 1376 1377 if (a->matches_go_to != b->matches_go_to) 1378 return FALSE; 1379 1380 if ((a->flags & BUS_MATCH_MESSAGE_TYPE) && 1381 a->message_type != b->message_type) 1382 return FALSE; 1383 1384 if ((a->flags & BUS_MATCH_MEMBER) && 1385 strcmp (a->member, b->member) != 0) 1386 return FALSE; 1387 1388 if ((a->flags & BUS_MATCH_PATH) && 1389 strcmp (a->path, b->path) != 0) 1390 return FALSE; 1391 1392 if ((a->flags & BUS_MATCH_INTERFACE) && 1393 strcmp (a->interface, b->interface) != 0) 1394 return FALSE; 1395 1396 if ((a->flags & BUS_MATCH_SENDER) && 1397 strcmp (a->sender, b->sender) != 0) 1398 return FALSE; 1399 1400 if ((a->flags & BUS_MATCH_DESTINATION) && 1401 strcmp (a->destination, b->destination) != 0) 1402 return FALSE; 1403 1404 /* we already compared the value of flags, and 1405 * BUS_MATCH_CLIENT_IS_EAVESDROPPING does not have another struct member */ 1406 1407 if (a->flags & BUS_MATCH_ARGS) 1408 { 1409 int i; 1410 1411 if (a->args_len != b->args_len) 1412 return FALSE; 1413 1414 i = 0; 1415 while (i < a->args_len) 1416 { 1417 int length; 1418 1419 if ((a->args[i] != NULL) != (b->args[i] != NULL)) 1420 return FALSE; 1421 1422 if (a->arg_lens[i] != b->arg_lens[i]) 1423 return FALSE; 1424 1425 length = a->arg_lens[i] & ~BUS_MATCH_ARG_FLAGS; 1426 1427 if (a->args[i] != NULL) 1428 { 1429 _dbus_assert (b->args[i] != NULL); 1430 if (memcmp (a->args[i], b->args[i], length) != 0) 1431 return FALSE; 1432 } 1433 1434 ++i; 1435 } 1436 } 1437 1438 return TRUE; 1439 } 1440 1441 static void 1442 bus_matchmaker_remove_rule_link (DBusList **rules, 1443 DBusList *link) 1444 { 1445 BusMatchRule *rule = link->data; 1446 1447 bus_connection_remove_match_rule (rule->matches_go_to, rule); 1448 _dbus_list_remove_link (rules, link); 1449 1450 #ifdef DBUS_ENABLE_VERBOSE_MODE 1451 { 1452 char *s = match_rule_to_string (rule); 1453 1454 _dbus_verbose ("Removed match rule %s for connection %p\n", 1455 s, rule->matches_go_to); 1456 dbus_free (s); 1457 } 1458 #endif 1459 1460 bus_match_rule_unref (rule); 1461 } 1462 1463 void 1464 bus_matchmaker_remove_rule (BusMatchmaker *matchmaker, 1465 BusMatchRule *rule) 1466 { 1467 DBusList **rules; 1468 1469 _dbus_verbose ("Removing rule with message_type %d, interface %s\n", 1470 rule->message_type, 1471 rule->interface != NULL ? rule->interface : "<null>"); 1472 1473 bus_connection_remove_match_rule (rule->matches_go_to, rule); 1474 1475 rules = bus_matchmaker_get_rules (matchmaker, rule->message_type, 1476 rule->interface, FALSE); 1477 1478 /* We should only be asked to remove a rule by identity right after it was 1479 * added, so there should be a list for it. 1480 */ 1481 _dbus_assert (rules != NULL); 1482 1483 _dbus_list_remove (rules, rule); 1484 bus_matchmaker_gc_rules (matchmaker, rule->message_type, rule->interface, 1485 rules); 1486 1487 #ifdef DBUS_ENABLE_VERBOSE_MODE 1488 { 1489 char *s = match_rule_to_string (rule); 1490 1491 _dbus_verbose ("Removed match rule %s for connection %p\n", 1492 s, rule->matches_go_to); 1493 dbus_free (s); 1494 } 1495 #endif 1496 1497 bus_match_rule_unref (rule); 1498 } 1499 1500 /* Remove a single rule which is equal to the given rule by value */ 1501 dbus_bool_t 1502 bus_matchmaker_remove_rule_by_value (BusMatchmaker *matchmaker, 1503 BusMatchRule *value, 1504 DBusError *error) 1505 { 1506 DBusList **rules; 1507 DBusList *link = NULL; 1508 1509 _dbus_verbose ("Removing rule by value with message_type %d, interface %s\n", 1510 value->message_type, 1511 value->interface != NULL ? value->interface : "<null>"); 1512 1513 rules = bus_matchmaker_get_rules (matchmaker, value->message_type, 1514 value->interface, FALSE); 1515 1516 if (rules != NULL) 1517 { 1518 /* we traverse backward because bus_connection_remove_match_rule() 1519 * removes the most-recently-added rule 1520 */ 1521 link = _dbus_list_get_last_link (rules); 1522 while (link != NULL) 1523 { 1524 BusMatchRule *rule; 1525 DBusList *prev; 1526 1527 rule = link->data; 1528 prev = _dbus_list_get_prev_link (rules, link); 1529 1530 if (match_rule_equal (rule, value)) 1531 { 1532 bus_matchmaker_remove_rule_link (rules, link); 1533 break; 1534 } 1535 1536 link = prev; 1537 } 1538 } 1539 1540 if (link == NULL) 1541 { 1542 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_NOT_FOUND, 1543 "The given match rule wasn't found and can't be removed"); 1544 return FALSE; 1545 } 1546 1547 bus_matchmaker_gc_rules (matchmaker, value->message_type, value->interface, 1548 rules); 1549 1550 return TRUE; 1551 } 1552 1553 static void 1554 rule_list_remove_by_connection (DBusList **rules, 1555 DBusConnection *connection) 1556 { 1557 DBusList *link; 1558 1559 link = _dbus_list_get_first_link (rules); 1560 while (link != NULL) 1561 { 1562 BusMatchRule *rule; 1563 DBusList *next; 1564 1565 rule = link->data; 1566 next = _dbus_list_get_next_link (rules, link); 1567 1568 if (rule->matches_go_to == connection) 1569 { 1570 bus_matchmaker_remove_rule_link (rules, link); 1571 } 1572 else if (((rule->flags & BUS_MATCH_SENDER) && *rule->sender == ':') || 1573 ((rule->flags & BUS_MATCH_DESTINATION) && *rule->destination == ':')) 1574 { 1575 /* The rule matches to/from a base service, see if it's the 1576 * one being disconnected, since we know this service name 1577 * will never be recycled. 1578 */ 1579 const char *name; 1580 1581 name = bus_connection_get_name (connection); 1582 _dbus_assert (name != NULL); /* because we're an active connection */ 1583 1584 if (((rule->flags & BUS_MATCH_SENDER) && 1585 strcmp (rule->sender, name) == 0) || 1586 ((rule->flags & BUS_MATCH_DESTINATION) && 1587 strcmp (rule->destination, name) == 0)) 1588 { 1589 bus_matchmaker_remove_rule_link (rules, link); 1590 } 1591 } 1592 1593 link = next; 1594 } 1595 } 1596 1597 void 1598 bus_matchmaker_disconnected (BusMatchmaker *matchmaker, 1599 DBusConnection *connection) 1600 { 1601 int i; 1602 1603 /* FIXME 1604 * 1605 * This scans all match rules on the bus. We could avoid that 1606 * for the rules belonging to the connection, since we keep 1607 * a list of those; but for the rules that just refer to 1608 * the connection we'd need to do something more elaborate. 1609 */ 1610 1611 _dbus_assert (bus_connection_is_active (connection)); 1612 1613 _dbus_verbose ("Removing all rules for connection %p\n", connection); 1614 1615 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++) 1616 { 1617 RulePool *p = matchmaker->rules_by_type + i; 1618 DBusHashIter iter; 1619 1620 rule_list_remove_by_connection (&p->rules_without_iface, connection); 1621 1622 _dbus_hash_iter_init (p->rules_by_iface, &iter); 1623 while (_dbus_hash_iter_next (&iter)) 1624 { 1625 DBusList **items = _dbus_hash_iter_get_value (&iter); 1626 1627 rule_list_remove_by_connection (items, connection); 1628 1629 if (*items == NULL) 1630 _dbus_hash_iter_remove_entry (&iter); 1631 } 1632 } 1633 } 1634 1635 static dbus_bool_t 1636 connection_is_primary_owner (DBusConnection *connection, 1637 const char *service_name) 1638 { 1639 BusService *service; 1640 DBusString str; 1641 BusRegistry *registry; 1642 1643 _dbus_assert (connection != NULL); 1644 1645 registry = bus_connection_get_registry (connection); 1646 1647 _dbus_string_init_const (&str, service_name); 1648 service = bus_registry_lookup (registry, &str); 1649 1650 if (service == NULL) 1651 return FALSE; /* Service doesn't exist so connection can't own it. */ 1652 1653 return bus_service_get_primary_owners_connection (service) == connection; 1654 } 1655 1656 static dbus_bool_t 1657 str_has_prefix (const char *str, const char *prefix) 1658 { 1659 size_t prefix_len; 1660 prefix_len = strlen (prefix); 1661 if (strncmp (str, prefix, prefix_len) == 0) 1662 return TRUE; 1663 else 1664 return FALSE; 1665 } 1666 1667 static dbus_bool_t 1668 match_rule_matches (BusMatchRule *rule, 1669 DBusConnection *sender, 1670 DBusConnection *addressed_recipient, 1671 DBusMessage *message, 1672 BusMatchFlags already_matched) 1673 { 1674 dbus_bool_t wants_to_eavesdrop = FALSE; 1675 int flags; 1676 1677 /* All features of the match rule are AND'd together, 1678 * so FALSE if any of them don't match. 1679 */ 1680 1681 /* sender/addressed_recipient of #NULL may mean bus driver, 1682 * or for addressed_recipient may mean a message with no 1683 * specific recipient (i.e. a signal) 1684 */ 1685 1686 /* Don't bother re-matching features we've already checked implicitly. */ 1687 flags = rule->flags & (~already_matched); 1688 1689 if (flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING) 1690 wants_to_eavesdrop = TRUE; 1691 1692 if (flags & BUS_MATCH_MESSAGE_TYPE) 1693 { 1694 _dbus_assert (rule->message_type != DBUS_MESSAGE_TYPE_INVALID); 1695 1696 if (rule->message_type != dbus_message_get_type (message)) 1697 return FALSE; 1698 } 1699 1700 if (flags & BUS_MATCH_INTERFACE) 1701 { 1702 const char *iface; 1703 1704 _dbus_assert (rule->interface != NULL); 1705 1706 iface = dbus_message_get_interface (message); 1707 if (iface == NULL) 1708 return FALSE; 1709 1710 if (strcmp (iface, rule->interface) != 0) 1711 return FALSE; 1712 } 1713 1714 if (flags & BUS_MATCH_MEMBER) 1715 { 1716 const char *member; 1717 1718 _dbus_assert (rule->member != NULL); 1719 1720 member = dbus_message_get_member (message); 1721 if (member == NULL) 1722 return FALSE; 1723 1724 if (strcmp (member, rule->member) != 0) 1725 return FALSE; 1726 } 1727 1728 if (flags & BUS_MATCH_SENDER) 1729 { 1730 _dbus_assert (rule->sender != NULL); 1731 1732 if (sender == NULL) 1733 { 1734 if (strcmp (rule->sender, 1735 DBUS_SERVICE_DBUS) != 0) 1736 return FALSE; 1737 } 1738 else 1739 { 1740 if (!connection_is_primary_owner (sender, rule->sender)) 1741 return FALSE; 1742 } 1743 } 1744 1745 /* Note: this part is relevant for eavesdropper rules: 1746 * Two cases: 1747 * 1) rule has a destination to be matched 1748 * (flag BUS_MATCH_DESTINATION present). Rule will match if: 1749 * - rule->destination matches the addressed_recipient 1750 * AND 1751 * - wants_to_eavesdrop=TRUE 1752 * 1753 * Note: (the case in which addressed_recipient is the actual rule owner 1754 * is handled elsewere in dispatch.c:bus_dispatch_matches(). 1755 * 1756 * 2) rule has no destination. Rule will match if: 1757 * - message has no specified destination (ie broadcasts) 1758 * (Note: this will rule out unicast method calls and unicast signals, 1759 * fixing FDO#269748) 1760 * OR 1761 * - wants_to_eavesdrop=TRUE (destination-catch-all situation) 1762 */ 1763 if (flags & BUS_MATCH_DESTINATION) 1764 { 1765 const char *destination; 1766 1767 _dbus_assert (rule->destination != NULL); 1768 1769 destination = dbus_message_get_destination (message); 1770 if (destination == NULL) 1771 /* broadcast, but this rule specified a destination: no match */ 1772 return FALSE; 1773 1774 /* rule owner does not intend to eavesdrop: we'll deliver only msgs 1775 * directed to it, NOT MATCHING */ 1776 if (!wants_to_eavesdrop) 1777 return FALSE; 1778 1779 if (addressed_recipient == NULL) 1780 { 1781 if (strcmp (rule->destination, 1782 DBUS_SERVICE_DBUS) != 0) 1783 return FALSE; 1784 } 1785 else 1786 { 1787 if (!connection_is_primary_owner (addressed_recipient, rule->destination)) 1788 return FALSE; 1789 } 1790 } else { /* no destination in rule */ 1791 dbus_bool_t msg_is_broadcast; 1792 1793 _dbus_assert (rule->destination == NULL); 1794 1795 msg_is_broadcast = (dbus_message_get_destination (message) == NULL); 1796 1797 if (!wants_to_eavesdrop && !msg_is_broadcast) 1798 return FALSE; 1799 1800 /* if we are here rule owner intends to eavesdrop 1801 * OR 1802 * message is being broadcasted */ 1803 } 1804 1805 if (flags & BUS_MATCH_PATH) 1806 { 1807 const char *path; 1808 1809 _dbus_assert (rule->path != NULL); 1810 1811 path = dbus_message_get_path (message); 1812 if (path == NULL) 1813 return FALSE; 1814 1815 if (strcmp (path, rule->path) != 0) 1816 return FALSE; 1817 } 1818 1819 if (flags & BUS_MATCH_PATH_NAMESPACE) 1820 { 1821 const char *path; 1822 int len; 1823 1824 _dbus_assert (rule->path != NULL); 1825 1826 path = dbus_message_get_path (message); 1827 if (path == NULL) 1828 return FALSE; 1829 1830 if (!str_has_prefix (path, rule->path)) 1831 return FALSE; 1832 1833 len = strlen (rule->path); 1834 1835 /* Check that the actual argument is within the expected 1836 * namespace, rather than just starting with that string, 1837 * by checking that the matched prefix is followed by a '/' 1838 * or the end of the path. 1839 */ 1840 if (path[len] != '\0' && path[len] != '/') 1841 return FALSE; 1842 } 1843 1844 if (flags & BUS_MATCH_ARGS) 1845 { 1846 int i; 1847 DBusMessageIter iter; 1848 1849 _dbus_assert (rule->args != NULL); 1850 1851 dbus_message_iter_init (message, &iter); 1852 1853 i = 0; 1854 while (i < rule->args_len) 1855 { 1856 int current_type; 1857 const char *expected_arg; 1858 int expected_length; 1859 dbus_bool_t is_path, is_namespace; 1860 1861 expected_arg = rule->args[i]; 1862 expected_length = rule->arg_lens[i] & ~BUS_MATCH_ARG_FLAGS; 1863 is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0; 1864 is_namespace = (rule->arg_lens[i] & BUS_MATCH_ARG_NAMESPACE) != 0; 1865 1866 current_type = dbus_message_iter_get_arg_type (&iter); 1867 1868 if (expected_arg != NULL) 1869 { 1870 const char *actual_arg; 1871 int actual_length; 1872 1873 if (current_type != DBUS_TYPE_STRING && 1874 (!is_path || current_type != DBUS_TYPE_OBJECT_PATH)) 1875 return FALSE; 1876 1877 actual_arg = NULL; 1878 dbus_message_iter_get_basic (&iter, &actual_arg); 1879 _dbus_assert (actual_arg != NULL); 1880 1881 actual_length = strlen (actual_arg); 1882 1883 if (is_path) 1884 { 1885 if (actual_length < expected_length && 1886 actual_arg[actual_length - 1] != '/') 1887 return FALSE; 1888 1889 if (expected_length < actual_length && 1890 expected_arg[expected_length - 1] != '/') 1891 return FALSE; 1892 1893 if (memcmp (actual_arg, expected_arg, 1894 MIN (actual_length, expected_length)) != 0) 1895 return FALSE; 1896 } 1897 else if (is_namespace) 1898 { 1899 if (expected_length > actual_length) 1900 return FALSE; 1901 1902 /* If the actual argument doesn't start with the expected 1903 * namespace, then we don't match. 1904 */ 1905 if (memcmp (expected_arg, actual_arg, expected_length) != 0) 1906 return FALSE; 1907 1908 if (expected_length < actual_length) 1909 { 1910 /* Check that the actual argument is within the expected 1911 * namespace, rather than just starting with that string, 1912 * by checking that the matched prefix ends in a '.'. 1913 * 1914 * This doesn't stop "foo.bar." matching "foo.bar..baz" 1915 * which is an invalid namespace, but at some point the 1916 * daemon can't cover up for broken services. 1917 */ 1918 if (actual_arg[expected_length] != '.') 1919 return FALSE; 1920 } 1921 /* otherwise we had an exact match. */ 1922 } 1923 else 1924 { 1925 if (expected_length != actual_length || 1926 memcmp (expected_arg, actual_arg, expected_length) != 0) 1927 return FALSE; 1928 } 1929 1930 } 1931 1932 if (current_type != DBUS_TYPE_INVALID) 1933 dbus_message_iter_next (&iter); 1934 1935 ++i; 1936 } 1937 } 1938 1939 return TRUE; 1940 } 1941 1942 static dbus_bool_t 1943 get_recipients_from_list (DBusList **rules, 1944 DBusConnection *sender, 1945 DBusConnection *addressed_recipient, 1946 DBusMessage *message, 1947 DBusList **recipients_p) 1948 { 1949 DBusList *link; 1950 1951 if (rules == NULL) 1952 return TRUE; 1953 1954 link = _dbus_list_get_first_link (rules); 1955 while (link != NULL) 1956 { 1957 BusMatchRule *rule; 1958 1959 rule = link->data; 1960 1961 #ifdef DBUS_ENABLE_VERBOSE_MODE 1962 { 1963 char *s = match_rule_to_string (rule); 1964 1965 _dbus_verbose ("Checking whether message matches rule %s for connection %p\n", 1966 s, rule->matches_go_to); 1967 dbus_free (s); 1968 } 1969 #endif 1970 1971 if (match_rule_matches (rule, 1972 sender, addressed_recipient, message, 1973 BUS_MATCH_MESSAGE_TYPE | BUS_MATCH_INTERFACE)) 1974 { 1975 _dbus_verbose ("Rule matched\n"); 1976 1977 /* Append to the list if we haven't already */ 1978 if (bus_connection_mark_stamp (rule->matches_go_to)) 1979 { 1980 if (!_dbus_list_append (recipients_p, rule->matches_go_to)) 1981 return FALSE; 1982 } 1983 #ifdef DBUS_ENABLE_VERBOSE_MODE 1984 else 1985 { 1986 _dbus_verbose ("Connection already receiving this message, so not adding again\n"); 1987 } 1988 #endif /* DBUS_ENABLE_VERBOSE_MODE */ 1989 } 1990 1991 link = _dbus_list_get_next_link (rules, link); 1992 } 1993 1994 return TRUE; 1995 } 1996 1997 dbus_bool_t 1998 bus_matchmaker_get_recipients (BusMatchmaker *matchmaker, 1999 BusConnections *connections, 2000 DBusConnection *sender, 2001 DBusConnection *addressed_recipient, 2002 DBusMessage *message, 2003 DBusList **recipients_p) 2004 { 2005 int type; 2006 const char *interface; 2007 DBusList **neither, **just_type, **just_iface, **both; 2008 2009 _dbus_assert (*recipients_p == NULL); 2010 2011 /* This avoids sending same message to the same connection twice. 2012 * Purpose of the stamp instead of a bool is to avoid iterating over 2013 * all connections resetting the bool each time. 2014 */ 2015 bus_connections_increment_stamp (connections); 2016 2017 /* addressed_recipient is already receiving the message, don't add to list. 2018 * NULL addressed_recipient means either bus driver, or this is a signal 2019 * and thus lacks a specific addressed_recipient. 2020 */ 2021 if (addressed_recipient != NULL) 2022 bus_connection_mark_stamp (addressed_recipient); 2023 2024 type = dbus_message_get_type (message); 2025 interface = dbus_message_get_interface (message); 2026 2027 neither = bus_matchmaker_get_rules (matchmaker, DBUS_MESSAGE_TYPE_INVALID, 2028 NULL, FALSE); 2029 just_type = just_iface = both = NULL; 2030 2031 if (interface != NULL) 2032 just_iface = bus_matchmaker_get_rules (matchmaker, 2033 DBUS_MESSAGE_TYPE_INVALID, interface, FALSE); 2034 2035 if (type > DBUS_MESSAGE_TYPE_INVALID && type < DBUS_NUM_MESSAGE_TYPES) 2036 { 2037 just_type = bus_matchmaker_get_rules (matchmaker, type, NULL, FALSE); 2038 2039 if (interface != NULL) 2040 both = bus_matchmaker_get_rules (matchmaker, type, interface, FALSE); 2041 } 2042 2043 if (!(get_recipients_from_list (neither, sender, addressed_recipient, 2044 message, recipients_p) && 2045 get_recipients_from_list (just_iface, sender, addressed_recipient, 2046 message, recipients_p) && 2047 get_recipients_from_list (just_type, sender, addressed_recipient, 2048 message, recipients_p) && 2049 get_recipients_from_list (both, sender, addressed_recipient, 2050 message, recipients_p))) 2051 { 2052 _dbus_list_clear (recipients_p); 2053 return FALSE; 2054 } 2055 2056 return TRUE; 2057 } 2058 2059 #ifdef DBUS_BUILD_TESTS 2060 #include "test.h" 2061 #include <stdlib.h> 2062 2063 static BusMatchRule* 2064 check_parse (dbus_bool_t should_succeed, 2065 const char *text) 2066 { 2067 BusMatchRule *rule; 2068 DBusString str; 2069 DBusError error; 2070 2071 dbus_error_init (&error); 2072 2073 _dbus_string_init_const (&str, text); 2074 2075 rule = bus_match_rule_parse (NULL, &str, &error); 2076 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) 2077 { 2078 dbus_error_free (&error); 2079 return NULL; 2080 } 2081 2082 if (should_succeed && rule == NULL) 2083 { 2084 _dbus_warn ("Failed to parse: %s: %s: \"%s\"\n", 2085 error.name, error.message, 2086 _dbus_string_get_const_data (&str)); 2087 exit (1); 2088 } 2089 2090 if (!should_succeed && rule != NULL) 2091 { 2092 _dbus_warn ("Failed to fail to parse: \"%s\"\n", 2093 _dbus_string_get_const_data (&str)); 2094 exit (1); 2095 } 2096 2097 dbus_error_free (&error); 2098 2099 return rule; 2100 } 2101 2102 static void 2103 assert_large_rule (BusMatchRule *rule) 2104 { 2105 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE); 2106 _dbus_assert (rule->flags & BUS_MATCH_SENDER); 2107 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE); 2108 _dbus_assert (rule->flags & BUS_MATCH_MEMBER); 2109 _dbus_assert (rule->flags & BUS_MATCH_DESTINATION); 2110 _dbus_assert (rule->flags & BUS_MATCH_PATH); 2111 2112 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL); 2113 _dbus_assert (rule->interface != NULL); 2114 _dbus_assert (rule->member != NULL); 2115 _dbus_assert (rule->sender != NULL); 2116 _dbus_assert (rule->destination != NULL); 2117 _dbus_assert (rule->path != NULL); 2118 2119 _dbus_assert (strcmp (rule->interface, "org.freedesktop.DBusInterface") == 0); 2120 _dbus_assert (strcmp (rule->sender, "org.freedesktop.DBusSender") == 0); 2121 _dbus_assert (strcmp (rule->member, "Foo") == 0); 2122 _dbus_assert (strcmp (rule->path, "/bar/foo") == 0); 2123 _dbus_assert (strcmp (rule->destination, ":452345.34") == 0); 2124 } 2125 2126 static dbus_bool_t 2127 test_parsing (void *data) 2128 { 2129 BusMatchRule *rule; 2130 2131 rule = check_parse (TRUE, "type='signal',sender='org.freedesktop.DBusSender',interface='org.freedesktop.DBusInterface',member='Foo',path='/bar/foo',destination=':452345.34'"); 2132 if (rule != NULL) 2133 { 2134 assert_large_rule (rule); 2135 bus_match_rule_unref (rule); 2136 } 2137 2138 /* With extra whitespace and useless quotes */ 2139 rule = check_parse (TRUE, " type='signal', \tsender='org.freedes''ktop.DBusSender', interface='org.freedesktop.DBusInterface''''', \tmember='Foo',path='/bar/foo',destination=':452345.34'''''"); 2140 if (rule != NULL) 2141 { 2142 assert_large_rule (rule); 2143 bus_match_rule_unref (rule); 2144 } 2145 2146 2147 /* A simple signal connection */ 2148 rule = check_parse (TRUE, "type='signal',path='/foo',interface='org.Bar'"); 2149 if (rule != NULL) 2150 { 2151 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE); 2152 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE); 2153 _dbus_assert (rule->flags & BUS_MATCH_PATH); 2154 2155 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL); 2156 _dbus_assert (rule->interface != NULL); 2157 _dbus_assert (rule->path != NULL); 2158 2159 _dbus_assert (strcmp (rule->interface, "org.Bar") == 0); 2160 _dbus_assert (strcmp (rule->path, "/foo") == 0); 2161 2162 bus_match_rule_unref (rule); 2163 } 2164 2165 /* argN */ 2166 rule = check_parse (TRUE, "arg0='foo'"); 2167 if (rule != NULL) 2168 { 2169 _dbus_assert (rule->flags == BUS_MATCH_ARGS); 2170 _dbus_assert (rule->args != NULL); 2171 _dbus_assert (rule->args_len == 1); 2172 _dbus_assert (rule->args[0] != NULL); 2173 _dbus_assert (rule->args[1] == NULL); 2174 _dbus_assert (strcmp (rule->args[0], "foo") == 0); 2175 2176 bus_match_rule_unref (rule); 2177 } 2178 2179 rule = check_parse (TRUE, "arg1='foo'"); 2180 if (rule != NULL) 2181 { 2182 _dbus_assert (rule->flags == BUS_MATCH_ARGS); 2183 _dbus_assert (rule->args != NULL); 2184 _dbus_assert (rule->args_len == 2); 2185 _dbus_assert (rule->args[0] == NULL); 2186 _dbus_assert (rule->args[1] != NULL); 2187 _dbus_assert (rule->args[2] == NULL); 2188 _dbus_assert (strcmp (rule->args[1], "foo") == 0); 2189 2190 bus_match_rule_unref (rule); 2191 } 2192 2193 rule = check_parse (TRUE, "arg2='foo'"); 2194 if (rule != NULL) 2195 { 2196 _dbus_assert (rule->flags == BUS_MATCH_ARGS); 2197 _dbus_assert (rule->args != NULL); 2198 _dbus_assert (rule->args_len == 3); 2199 _dbus_assert (rule->args[0] == NULL); 2200 _dbus_assert (rule->args[1] == NULL); 2201 _dbus_assert (rule->args[2] != NULL); 2202 _dbus_assert (rule->args[3] == NULL); 2203 _dbus_assert (strcmp (rule->args[2], "foo") == 0); 2204 2205 bus_match_rule_unref (rule); 2206 } 2207 2208 rule = check_parse (TRUE, "arg40='foo'"); 2209 if (rule != NULL) 2210 { 2211 _dbus_assert (rule->flags == BUS_MATCH_ARGS); 2212 _dbus_assert (rule->args != NULL); 2213 _dbus_assert (rule->args_len == 41); 2214 _dbus_assert (rule->args[0] == NULL); 2215 _dbus_assert (rule->args[1] == NULL); 2216 _dbus_assert (rule->args[40] != NULL); 2217 _dbus_assert (rule->args[41] == NULL); 2218 _dbus_assert (strcmp (rule->args[40], "foo") == 0); 2219 2220 bus_match_rule_unref (rule); 2221 } 2222 2223 rule = check_parse (TRUE, "arg63='foo'"); 2224 if (rule != NULL) 2225 { 2226 _dbus_assert (rule->flags == BUS_MATCH_ARGS); 2227 _dbus_assert (rule->args != NULL); 2228 _dbus_assert (rule->args_len == 64); 2229 _dbus_assert (rule->args[0] == NULL); 2230 _dbus_assert (rule->args[1] == NULL); 2231 _dbus_assert (rule->args[63] != NULL); 2232 _dbus_assert (rule->args[64] == NULL); 2233 _dbus_assert (strcmp (rule->args[63], "foo") == 0); 2234 2235 bus_match_rule_unref (rule); 2236 } 2237 2238 rule = check_parse (TRUE, "arg7path='/foo'"); 2239 if (rule != NULL) 2240 { 2241 _dbus_assert (rule->flags = BUS_MATCH_ARGS); 2242 _dbus_assert (rule->args != NULL); 2243 _dbus_assert (rule->args_len == 8); 2244 _dbus_assert (rule->args[7] != NULL); 2245 _dbus_assert (rule->args[8] == NULL); 2246 _dbus_assert (strcmp (rule->args[7], "/foo") == 0); 2247 _dbus_assert ((rule->arg_lens[7] & BUS_MATCH_ARG_IS_PATH) 2248 == BUS_MATCH_ARG_IS_PATH); 2249 2250 bus_match_rule_unref (rule); 2251 } 2252 2253 /* Arg 0 namespace matches */ 2254 rule = check_parse (TRUE, "arg0namespace='foo'"); 2255 if (rule != NULL) 2256 { 2257 _dbus_assert (rule->flags == BUS_MATCH_ARGS); 2258 _dbus_assert (rule->args != NULL); 2259 _dbus_assert (rule->args_len == 1); 2260 _dbus_assert (strcmp (rule->args[0], "foo") == 0); 2261 _dbus_assert ((rule->arg_lens[0] & BUS_MATCH_ARG_NAMESPACE) 2262 == BUS_MATCH_ARG_NAMESPACE); 2263 2264 bus_match_rule_unref (rule); 2265 } 2266 2267 rule = check_parse (TRUE, "arg0namespace='foo.bar'"); 2268 if (rule != NULL) 2269 { 2270 _dbus_assert (rule->flags == BUS_MATCH_ARGS); 2271 _dbus_assert (rule->args != NULL); 2272 _dbus_assert (rule->args_len == 1); 2273 _dbus_assert (strcmp (rule->args[0], "foo.bar") == 0); 2274 _dbus_assert ((rule->arg_lens[0] & BUS_MATCH_ARG_NAMESPACE) 2275 == BUS_MATCH_ARG_NAMESPACE); 2276 2277 bus_match_rule_unref (rule); 2278 } 2279 2280 /* Only arg0namespace is supported. */ 2281 rule = check_parse (FALSE, "arg1namespace='foo'"); 2282 _dbus_assert (rule == NULL); 2283 2284 /* An empty string isn't a valid namespace prefix (you should just not 2285 * specify this key at all). 2286 */ 2287 rule = check_parse (FALSE, "arg0namespace=''"); 2288 _dbus_assert (rule == NULL); 2289 2290 /* Trailing periods aren't allowed (earlier versions of the arg0namespace 2291 * spec allowed a single trailing period, which altered the semantics) */ 2292 rule = check_parse (FALSE, "arg0namespace='foo.'"); 2293 _dbus_assert (rule == NULL); 2294 2295 rule = check_parse (FALSE, "arg0namespace='foo.bar.'"); 2296 _dbus_assert (rule == NULL); 2297 2298 rule = check_parse (FALSE, "arg0namespace='foo..'"); 2299 _dbus_assert (rule == NULL); 2300 2301 rule = check_parse (FALSE, "arg0namespace='foo.bar..'"); 2302 _dbus_assert (rule == NULL); 2303 2304 /* Too-large argN */ 2305 rule = check_parse (FALSE, "arg300='foo'"); 2306 _dbus_assert (rule == NULL); 2307 rule = check_parse (FALSE, "arg64='foo'"); 2308 _dbus_assert (rule == NULL); 2309 2310 /* No N in argN */ 2311 rule = check_parse (FALSE, "arg='foo'"); 2312 _dbus_assert (rule == NULL); 2313 rule = check_parse (FALSE, "argv='foo'"); 2314 _dbus_assert (rule == NULL); 2315 rule = check_parse (FALSE, "arg3junk='foo'"); 2316 _dbus_assert (rule == NULL); 2317 rule = check_parse (FALSE, "argument='foo'"); 2318 _dbus_assert (rule == NULL); 2319 2320 /* Reject duplicates */ 2321 rule = check_parse (FALSE, "type='signal',type='method_call'"); 2322 _dbus_assert (rule == NULL); 2323 2324 rule = check_parse (TRUE, "path_namespace='/foo/bar'"); 2325 if (rule != NULL) 2326 { 2327 _dbus_assert (rule->flags == BUS_MATCH_PATH_NAMESPACE); 2328 _dbus_assert (rule->path != NULL); 2329 _dbus_assert (strcmp (rule->path, "/foo/bar") == 0); 2330 2331 bus_match_rule_unref (rule); 2332 } 2333 2334 /* Almost a duplicate */ 2335 rule = check_parse (FALSE, "path='/foo',path_namespace='/foo'"); 2336 _dbus_assert (rule == NULL); 2337 2338 /* Trailing / was supported in the initial proposal, but now isn't */ 2339 rule = check_parse (FALSE, "path_namespace='/foo/'"); 2340 _dbus_assert (rule == NULL); 2341 2342 /* Duplicates with the argN code */ 2343 rule = check_parse (FALSE, "arg0='foo',arg0='bar'"); 2344 _dbus_assert (rule == NULL); 2345 rule = check_parse (FALSE, "arg3='foo',arg3='bar'"); 2346 _dbus_assert (rule == NULL); 2347 rule = check_parse (FALSE, "arg30='foo',arg30='bar'"); 2348 _dbus_assert (rule == NULL); 2349 2350 /* Reject broken keys */ 2351 rule = check_parse (FALSE, "blah='signal'"); 2352 _dbus_assert (rule == NULL); 2353 2354 /* Reject broken values */ 2355 rule = check_parse (FALSE, "type='chouin'"); 2356 _dbus_assert (rule == NULL); 2357 rule = check_parse (FALSE, "interface='abc@def++'"); 2358 _dbus_assert (rule == NULL); 2359 rule = check_parse (FALSE, "service='youpi'"); 2360 _dbus_assert (rule == NULL); 2361 2362 /* Allow empty rule */ 2363 rule = check_parse (TRUE, ""); 2364 if (rule != NULL) 2365 { 2366 _dbus_assert (rule->flags == 0); 2367 2368 bus_match_rule_unref (rule); 2369 } 2370 2371 /* All-whitespace rule is the same as empty */ 2372 rule = check_parse (TRUE, " \t"); 2373 if (rule != NULL) 2374 { 2375 _dbus_assert (rule->flags == 0); 2376 2377 bus_match_rule_unref (rule); 2378 } 2379 2380 /* But with non-whitespace chars and no =value, it's not OK */ 2381 rule = check_parse (FALSE, "type"); 2382 _dbus_assert (rule == NULL); 2383 2384 return TRUE; 2385 } 2386 2387 static struct { 2388 const char *first; 2389 const char *second; 2390 } equality_tests[] = { 2391 { "type='signal'", "type='signal'" }, 2392 { "type='signal',interface='foo.bar'", "interface='foo.bar',type='signal'" }, 2393 { "type='signal',member='bar'", "member='bar',type='signal'" }, 2394 { "type='method_call',sender=':1.0'", "sender=':1.0',type='method_call'" }, 2395 { "type='method_call',destination=':1.0'", "destination=':1.0',type='method_call'" }, 2396 { "type='method_call',path='/foo/bar'", "path='/foo/bar',type='method_call'" }, 2397 { "type='method_call',arg0='blah'", "arg0='blah',type='method_call'" }, 2398 { "type='method_call',arg0='boo'", "arg0='boo',type='method_call'" }, 2399 { "type='method_call',arg0='blah',arg1='baz'", "arg0='blah',arg1='baz',type='method_call'" }, 2400 { "type='method_call',arg3='foosh'", "arg3='foosh',type='method_call'" }, 2401 { "arg3='fool'", "arg3='fool'" }, 2402 { "arg0namespace='fool'", "arg0namespace='fool'" }, 2403 { "member='food'", "member='food'" } 2404 }; 2405 2406 static void 2407 test_equality (void) 2408 { 2409 int i; 2410 2411 i = 0; 2412 while (i < _DBUS_N_ELEMENTS (equality_tests)) 2413 { 2414 BusMatchRule *first; 2415 BusMatchRule *second; 2416 int j; 2417 2418 first = check_parse (TRUE, equality_tests[i].first); 2419 _dbus_assert (first != NULL); 2420 second = check_parse (TRUE, equality_tests[i].second); 2421 _dbus_assert (second != NULL); 2422 2423 if (!match_rule_equal (first, second)) 2424 { 2425 _dbus_warn ("rule %s and %s should have been equal\n", 2426 equality_tests[i].first, 2427 equality_tests[i].second); 2428 exit (1); 2429 } 2430 2431 bus_match_rule_unref (second); 2432 2433 /* Check that the rule is not equal to any of the 2434 * others besides its pair match 2435 */ 2436 j = 0; 2437 while (j < _DBUS_N_ELEMENTS (equality_tests)) 2438 { 2439 if (i != j) 2440 { 2441 second = check_parse (TRUE, equality_tests[j].second); 2442 2443 if (match_rule_equal (first, second)) 2444 { 2445 _dbus_warn ("rule %s and %s should not have been equal\n", 2446 equality_tests[i].first, 2447 equality_tests[j].second); 2448 exit (1); 2449 } 2450 2451 bus_match_rule_unref (second); 2452 } 2453 2454 ++j; 2455 } 2456 2457 bus_match_rule_unref (first); 2458 2459 ++i; 2460 } 2461 } 2462 2463 static const char* 2464 should_match_message_1[] = { 2465 "type='signal'", 2466 "member='Frobated'", 2467 "arg0='foobar'", 2468 "type='signal',member='Frobated'", 2469 "type='signal',member='Frobated',arg0='foobar'", 2470 "member='Frobated',arg0='foobar'", 2471 "type='signal',arg0='foobar'", 2472 /* The definition of argXpath matches says: "As with normal argument matches, 2473 * if the argument is exactly equal to the string given in the match rule 2474 * then the rule is satisfied." So this should match (even though the 2475 * argument is not a valid path)! 2476 */ 2477 "arg0path='foobar'", 2478 "arg0namespace='foobar'", 2479 NULL 2480 }; 2481 2482 static const char* 2483 should_not_match_message_1[] = { 2484 "type='method_call'", 2485 "type='error'", 2486 "type='method_return'", 2487 "type='signal',member='Oopsed'", 2488 "arg0='blah'", 2489 "arg1='foobar'", 2490 "arg2='foobar'", 2491 "arg3='foobar'", 2492 "arg0='3'", 2493 "arg1='3'", 2494 "arg0='foobar',arg1='abcdef'", 2495 "arg0='foobar',arg1='abcdef',arg2='abcdefghi',arg3='abcdefghi',arg4='abcdefghi'", 2496 "arg0='foobar',arg1='abcdef',arg4='abcdefghi',arg3='abcdefghi',arg2='abcdefghi'", 2497 "arg0path='foo'", 2498 "arg0path='foobar/'", 2499 "arg1path='3'", 2500 "arg0namespace='foo'", 2501 "arg0namespace='foo',arg1='abcdef'", 2502 "arg0namespace='moo'", 2503 NULL 2504 }; 2505 2506 #define EXAMPLE_NAME "com.example.backend.foo" 2507 2508 static const char * 2509 should_match_message_2[] = { 2510 /* EXAMPLE_NAME is in all of these namespaces */ 2511 "arg0namespace='com.example.backend'", 2512 "arg0namespace='com.example'", 2513 "arg0namespace='com'", 2514 2515 /* If the client specifies the name exactly, with no trailing period, then 2516 * it should match. 2517 */ 2518 "arg0namespace='com.example.backend.foo'", 2519 2520 NULL 2521 }; 2522 2523 static const char * 2524 should_not_match_message_2[] = { 2525 /* These are not even prefixes */ 2526 "arg0namespace='com.example.backend.foo.bar'", 2527 "arg0namespace='com.example.backend.foobar'", 2528 2529 /* These are prefixes, but they're not parent namespaces. */ 2530 "arg0namespace='com.example.backend.fo'", 2531 "arg0namespace='com.example.backen'", 2532 "arg0namespace='com.exampl'", 2533 "arg0namespace='co'", 2534 2535 NULL 2536 }; 2537 2538 static void 2539 check_matches (dbus_bool_t expected_to_match, 2540 int number, 2541 DBusMessage *message, 2542 const char *rule_text) 2543 { 2544 BusMatchRule *rule; 2545 dbus_bool_t matched; 2546 2547 rule = check_parse (TRUE, rule_text); 2548 _dbus_assert (rule != NULL); 2549 2550 /* We can't test sender/destination rules since we pass NULL here */ 2551 matched = match_rule_matches (rule, NULL, NULL, message, 0); 2552 2553 if (matched != expected_to_match) 2554 { 2555 _dbus_warn ("Expected rule %s to %s message %d, failed\n", 2556 rule_text, expected_to_match ? 2557 "match" : "not match", number); 2558 exit (1); 2559 } 2560 2561 bus_match_rule_unref (rule); 2562 } 2563 2564 static void 2565 check_matching (DBusMessage *message, 2566 int number, 2567 const char **should_match, 2568 const char **should_not_match) 2569 { 2570 int i; 2571 2572 i = 0; 2573 while (should_match[i] != NULL) 2574 { 2575 check_matches (TRUE, number, message, should_match[i]); 2576 ++i; 2577 } 2578 2579 i = 0; 2580 while (should_not_match[i] != NULL) 2581 { 2582 check_matches (FALSE, number, message, should_not_match[i]); 2583 ++i; 2584 } 2585 } 2586 2587 static void 2588 test_matching (void) 2589 { 2590 DBusMessage *message1, *message2; 2591 const char *v_STRING; 2592 dbus_int32_t v_INT32; 2593 2594 message1 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL); 2595 _dbus_assert (message1 != NULL); 2596 if (!dbus_message_set_member (message1, "Frobated")) 2597 _dbus_assert_not_reached ("oom"); 2598 2599 v_STRING = "foobar"; 2600 v_INT32 = 3; 2601 if (!dbus_message_append_args (message1, 2602 DBUS_TYPE_STRING, &v_STRING, 2603 DBUS_TYPE_INT32, &v_INT32, 2604 NULL)) 2605 _dbus_assert_not_reached ("oom"); 2606 2607 check_matching (message1, 1, 2608 should_match_message_1, 2609 should_not_match_message_1); 2610 2611 dbus_message_unref (message1); 2612 2613 message2 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL); 2614 _dbus_assert (message2 != NULL); 2615 if (!dbus_message_set_member (message2, "NameOwnerChanged")) 2616 _dbus_assert_not_reached ("oom"); 2617 2618 /* Obviously this isn't really a NameOwnerChanged signal. */ 2619 v_STRING = EXAMPLE_NAME; 2620 if (!dbus_message_append_args (message2, 2621 DBUS_TYPE_STRING, &v_STRING, 2622 NULL)) 2623 _dbus_assert_not_reached ("oom"); 2624 2625 check_matching (message2, 2, 2626 should_match_message_2, 2627 should_not_match_message_2); 2628 2629 dbus_message_unref (message2); 2630 } 2631 2632 #define PATH_MATCH_RULE "arg0path='/aa/bb/'" 2633 2634 /* This is a list of paths that should be matched by PATH_MATCH_RULE, taken 2635 * from the specification. Notice that not all of them are actually legal D-Bus 2636 * paths. 2637 * 2638 * The author of this test takes no responsibility for the semantics of 2639 * this match rule key. 2640 */ 2641 static const char *paths_that_should_be_matched[] = { 2642 "/aa/", 2643 "/aa/bb/", 2644 "/aa/bb/cc/", 2645 #define FIRST_VALID_PATH_WHICH_SHOULD_MATCH 3 2646 "/", 2647 "/aa/bb/cc", 2648 NULL 2649 }; 2650 2651 /* These paths should not be matched by PATH_MATCH_RULE. */ 2652 static const char *paths_that_should_not_be_matched[] = { 2653 "/aa/b", 2654 "/aa", 2655 /* or even... */ 2656 "/aa/bb", 2657 NULL 2658 }; 2659 2660 static void 2661 test_path_match (int type, 2662 const char *path, 2663 const char *rule_text, 2664 BusMatchRule *rule, 2665 dbus_bool_t should_match) 2666 { 2667 DBusMessage *message = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL); 2668 dbus_bool_t matched; 2669 2670 _dbus_assert (message != NULL); 2671 if (!dbus_message_set_member (message, "Foo")) 2672 _dbus_assert_not_reached ("oom"); 2673 2674 if (!dbus_message_append_args (message, 2675 type, &path, 2676 NULL)) 2677 _dbus_assert_not_reached ("oom"); 2678 2679 matched = match_rule_matches (rule, NULL, NULL, message, 0); 2680 2681 if (matched != should_match) 2682 { 2683 _dbus_warn ("Expected rule %s to %s message " 2684 "with first arg %s of type '%c', failed\n", 2685 rule_text, 2686 should_match ? "match" : "not match", 2687 path, 2688 (char) type); 2689 exit (1); 2690 } 2691 2692 dbus_message_unref (message); 2693 } 2694 2695 static void 2696 test_path_matching (void) 2697 { 2698 BusMatchRule *rule; 2699 const char **s; 2700 2701 rule = check_parse (TRUE, PATH_MATCH_RULE); 2702 _dbus_assert (rule != NULL); 2703 2704 for (s = paths_that_should_be_matched; *s != NULL; s++) 2705 test_path_match (DBUS_TYPE_STRING, *s, PATH_MATCH_RULE, rule, TRUE); 2706 2707 for (s = paths_that_should_be_matched + FIRST_VALID_PATH_WHICH_SHOULD_MATCH; 2708 *s != NULL; s++) 2709 test_path_match (DBUS_TYPE_OBJECT_PATH, *s, PATH_MATCH_RULE, rule, TRUE); 2710 2711 for (s = paths_that_should_not_be_matched; *s != NULL; s++) 2712 { 2713 test_path_match (DBUS_TYPE_STRING, *s, PATH_MATCH_RULE, rule, FALSE); 2714 test_path_match (DBUS_TYPE_OBJECT_PATH, *s, PATH_MATCH_RULE, rule, FALSE); 2715 } 2716 2717 bus_match_rule_unref (rule); 2718 } 2719 2720 static const char* 2721 path_namespace_should_match_message_1[] = { 2722 "type='signal',path_namespace='/foo'", 2723 "type='signal',path_namespace='/foo/TheObjectManager'", 2724 NULL 2725 }; 2726 2727 static const char* 2728 path_namespace_should_not_match_message_1[] = { 2729 "type='signal',path_namespace='/bar'", 2730 "type='signal',path_namespace='/bar/TheObjectManager'", 2731 NULL 2732 }; 2733 2734 static const char* 2735 path_namespace_should_match_message_2[] = { 2736 "type='signal',path_namespace='/foo/TheObjectManager'", 2737 NULL 2738 }; 2739 2740 static const char* 2741 path_namespace_should_not_match_message_2[] = { 2742 NULL 2743 }; 2744 2745 static const char* 2746 path_namespace_should_match_message_3[] = { 2747 NULL 2748 }; 2749 2750 static const char* 2751 path_namespace_should_not_match_message_3[] = { 2752 "type='signal',path_namespace='/foo/TheObjectManager'", 2753 NULL 2754 }; 2755 2756 static void 2757 test_matching_path_namespace (void) 2758 { 2759 DBusMessage *message1; 2760 DBusMessage *message2; 2761 DBusMessage *message3; 2762 2763 message1 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL); 2764 _dbus_assert (message1 != NULL); 2765 if (!dbus_message_set_path (message1, "/foo/TheObjectManager")) 2766 _dbus_assert_not_reached ("oom"); 2767 2768 message2 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL); 2769 _dbus_assert (message2 != NULL); 2770 if (!dbus_message_set_path (message2, "/foo/TheObjectManager/child_object")) 2771 _dbus_assert_not_reached ("oom"); 2772 2773 message3 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL); 2774 _dbus_assert (message3 != NULL); 2775 if (!dbus_message_set_path (message3, "/foo/TheObjectManagerOther")) 2776 _dbus_assert_not_reached ("oom"); 2777 2778 check_matching (message1, 1, 2779 path_namespace_should_match_message_1, 2780 path_namespace_should_not_match_message_1); 2781 check_matching (message2, 2, 2782 path_namespace_should_match_message_2, 2783 path_namespace_should_not_match_message_2); 2784 check_matching (message3, 3, 2785 path_namespace_should_match_message_3, 2786 path_namespace_should_not_match_message_3); 2787 2788 dbus_message_unref (message3); 2789 dbus_message_unref (message2); 2790 dbus_message_unref (message1); 2791 } 2792 2793 dbus_bool_t 2794 bus_signals_test (const DBusString *test_data_dir) 2795 { 2796 BusMatchmaker *matchmaker; 2797 2798 matchmaker = bus_matchmaker_new (); 2799 bus_matchmaker_ref (matchmaker); 2800 bus_matchmaker_unref (matchmaker); 2801 bus_matchmaker_unref (matchmaker); 2802 2803 if (!_dbus_test_oom_handling ("parsing match rules", test_parsing, NULL)) 2804 _dbus_assert_not_reached ("Parsing match rules test failed"); 2805 2806 test_equality (); 2807 test_matching (); 2808 test_path_matching (); 2809 test_matching_path_namespace (); 2810 2811 return TRUE; 2812 } 2813 2814 #endif /* DBUS_BUILD_TESTS */ 2815 2816