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_IS_PATH 0x8000000u 51 52 BusMatchRule* 53 bus_match_rule_new (DBusConnection *matches_go_to) 54 { 55 BusMatchRule *rule; 56 57 rule = dbus_new0 (BusMatchRule, 1); 58 if (rule == NULL) 59 return NULL; 60 61 rule->refcount = 1; 62 rule->matches_go_to = matches_go_to; 63 64 #ifndef DBUS_BUILD_TESTS 65 _dbus_assert (rule->matches_go_to != NULL); 66 #endif 67 68 return rule; 69 } 70 71 BusMatchRule * 72 bus_match_rule_ref (BusMatchRule *rule) 73 { 74 _dbus_assert (rule->refcount > 0); 75 76 rule->refcount += 1; 77 78 return rule; 79 } 80 81 void 82 bus_match_rule_unref (BusMatchRule *rule) 83 { 84 _dbus_assert (rule->refcount > 0); 85 86 rule->refcount -= 1; 87 if (rule->refcount == 0) 88 { 89 dbus_free (rule->interface); 90 dbus_free (rule->member); 91 dbus_free (rule->sender); 92 dbus_free (rule->destination); 93 dbus_free (rule->path); 94 dbus_free (rule->arg_lens); 95 96 /* can't use dbus_free_string_array() since there 97 * are embedded NULL 98 */ 99 if (rule->args) 100 { 101 int i; 102 103 i = 0; 104 while (i < rule->args_len) 105 { 106 if (rule->args[i]) 107 dbus_free (rule->args[i]); 108 ++i; 109 } 110 111 dbus_free (rule->args); 112 } 113 114 dbus_free (rule); 115 } 116 } 117 118 #ifdef DBUS_ENABLE_VERBOSE_MODE 119 /* Note this function does not do escaping, so it's only 120 * good for debug spew at the moment 121 */ 122 static char* 123 match_rule_to_string (BusMatchRule *rule) 124 { 125 DBusString str; 126 char *ret; 127 128 if (!_dbus_string_init (&str)) 129 { 130 char *s; 131 while ((s = _dbus_strdup ("nomem")) == NULL) 132 ; /* only OK for debug spew... */ 133 return s; 134 } 135 136 if (rule->flags & BUS_MATCH_MESSAGE_TYPE) 137 { 138 /* FIXME make type readable */ 139 if (!_dbus_string_append_printf (&str, "type='%d'", rule->message_type)) 140 goto nomem; 141 } 142 143 if (rule->flags & BUS_MATCH_INTERFACE) 144 { 145 if (_dbus_string_get_length (&str) > 0) 146 { 147 if (!_dbus_string_append (&str, ",")) 148 goto nomem; 149 } 150 151 if (!_dbus_string_append_printf (&str, "interface='%s'", rule->interface)) 152 goto nomem; 153 } 154 155 if (rule->flags & BUS_MATCH_MEMBER) 156 { 157 if (_dbus_string_get_length (&str) > 0) 158 { 159 if (!_dbus_string_append (&str, ",")) 160 goto nomem; 161 } 162 163 if (!_dbus_string_append_printf (&str, "member='%s'", rule->member)) 164 goto nomem; 165 } 166 167 if (rule->flags & BUS_MATCH_PATH) 168 { 169 if (_dbus_string_get_length (&str) > 0) 170 { 171 if (!_dbus_string_append (&str, ",")) 172 goto nomem; 173 } 174 175 if (!_dbus_string_append_printf (&str, "path='%s'", rule->path)) 176 goto nomem; 177 } 178 179 if (rule->flags & BUS_MATCH_SENDER) 180 { 181 if (_dbus_string_get_length (&str) > 0) 182 { 183 if (!_dbus_string_append (&str, ",")) 184 goto nomem; 185 } 186 187 if (!_dbus_string_append_printf (&str, "sender='%s'", rule->sender)) 188 goto nomem; 189 } 190 191 if (rule->flags & BUS_MATCH_DESTINATION) 192 { 193 if (_dbus_string_get_length (&str) > 0) 194 { 195 if (!_dbus_string_append (&str, ",")) 196 goto nomem; 197 } 198 199 if (!_dbus_string_append_printf (&str, "destination='%s'", rule->destination)) 200 goto nomem; 201 } 202 203 if (rule->flags & BUS_MATCH_ARGS) 204 { 205 int i; 206 207 _dbus_assert (rule->args != NULL); 208 209 i = 0; 210 while (i < rule->args_len) 211 { 212 if (rule->args[i] != NULL) 213 { 214 dbus_bool_t is_path; 215 216 if (_dbus_string_get_length (&str) > 0) 217 { 218 if (!_dbus_string_append (&str, ",")) 219 goto nomem; 220 } 221 222 is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0; 223 224 if (!_dbus_string_append_printf (&str, 225 "arg%d%s='%s'", 226 i, is_path ? "path" : "", 227 rule->args[i])) 228 goto nomem; 229 } 230 231 ++i; 232 } 233 } 234 235 if (!_dbus_string_steal_data (&str, &ret)) 236 goto nomem; 237 238 _dbus_string_free (&str); 239 return ret; 240 241 nomem: 242 _dbus_string_free (&str); 243 { 244 char *s; 245 while ((s = _dbus_strdup ("nomem")) == NULL) 246 ; /* only OK for debug spew... */ 247 return s; 248 } 249 } 250 #endif /* DBUS_ENABLE_VERBOSE_MODE */ 251 252 dbus_bool_t 253 bus_match_rule_set_message_type (BusMatchRule *rule, 254 int type) 255 { 256 rule->flags |= BUS_MATCH_MESSAGE_TYPE; 257 258 rule->message_type = type; 259 260 return TRUE; 261 } 262 263 dbus_bool_t 264 bus_match_rule_set_interface (BusMatchRule *rule, 265 const char *interface) 266 { 267 char *new; 268 269 _dbus_assert (interface != NULL); 270 271 new = _dbus_strdup (interface); 272 if (new == NULL) 273 return FALSE; 274 275 rule->flags |= BUS_MATCH_INTERFACE; 276 dbus_free (rule->interface); 277 rule->interface = new; 278 279 return TRUE; 280 } 281 282 dbus_bool_t 283 bus_match_rule_set_member (BusMatchRule *rule, 284 const char *member) 285 { 286 char *new; 287 288 _dbus_assert (member != NULL); 289 290 new = _dbus_strdup (member); 291 if (new == NULL) 292 return FALSE; 293 294 rule->flags |= BUS_MATCH_MEMBER; 295 dbus_free (rule->member); 296 rule->member = new; 297 298 return TRUE; 299 } 300 301 dbus_bool_t 302 bus_match_rule_set_sender (BusMatchRule *rule, 303 const char *sender) 304 { 305 char *new; 306 307 _dbus_assert (sender != NULL); 308 309 new = _dbus_strdup (sender); 310 if (new == NULL) 311 return FALSE; 312 313 rule->flags |= BUS_MATCH_SENDER; 314 dbus_free (rule->sender); 315 rule->sender = new; 316 317 return TRUE; 318 } 319 320 dbus_bool_t 321 bus_match_rule_set_destination (BusMatchRule *rule, 322 const char *destination) 323 { 324 char *new; 325 326 _dbus_assert (destination != NULL); 327 328 new = _dbus_strdup (destination); 329 if (new == NULL) 330 return FALSE; 331 332 rule->flags |= BUS_MATCH_DESTINATION; 333 dbus_free (rule->destination); 334 rule->destination = new; 335 336 return TRUE; 337 } 338 339 dbus_bool_t 340 bus_match_rule_set_path (BusMatchRule *rule, 341 const char *path) 342 { 343 char *new; 344 345 _dbus_assert (path != NULL); 346 347 new = _dbus_strdup (path); 348 if (new == NULL) 349 return FALSE; 350 351 rule->flags |= BUS_MATCH_PATH; 352 dbus_free (rule->path); 353 rule->path = new; 354 355 return TRUE; 356 } 357 358 dbus_bool_t 359 bus_match_rule_set_arg (BusMatchRule *rule, 360 int arg, 361 const DBusString *value, 362 dbus_bool_t is_path) 363 { 364 int length; 365 char *new; 366 367 _dbus_assert (value != NULL); 368 369 /* args_len is the number of args not including null termination 370 * in the char** 371 */ 372 if (arg >= rule->args_len) 373 { 374 unsigned int *new_arg_lens; 375 char **new_args; 376 int new_args_len; 377 int i; 378 379 new_args_len = arg + 1; 380 381 /* add another + 1 here for null termination */ 382 new_args = dbus_realloc (rule->args, 383 sizeof (char *) * (new_args_len + 1)); 384 if (new_args == NULL) 385 return FALSE; 386 387 /* NULL the new slots */ 388 i = rule->args_len; 389 while (i <= new_args_len) /* <= for null termination */ 390 { 391 new_args[i] = NULL; 392 ++i; 393 } 394 395 rule->args = new_args; 396 397 /* and now add to the lengths */ 398 new_arg_lens = dbus_realloc (rule->arg_lens, 399 sizeof (int) * (new_args_len + 1)); 400 401 if (new_arg_lens == NULL) 402 return FALSE; 403 404 /* zero the new slots */ 405 i = rule->args_len; 406 while (i <= new_args_len) /* <= for null termination */ 407 { 408 new_arg_lens[i] = 0; 409 ++i; 410 } 411 412 rule->arg_lens = new_arg_lens; 413 rule->args_len = new_args_len; 414 } 415 416 length = _dbus_string_get_length (value); 417 if (!_dbus_string_copy_data (value, &new)) 418 return FALSE; 419 420 rule->flags |= BUS_MATCH_ARGS; 421 422 dbus_free (rule->args[arg]); 423 rule->arg_lens[arg] = length; 424 rule->args[arg] = new; 425 426 if (is_path) 427 rule->arg_lens[arg] |= BUS_MATCH_ARG_IS_PATH; 428 429 /* NULL termination didn't get busted */ 430 _dbus_assert (rule->args[rule->args_len] == NULL); 431 _dbus_assert (rule->arg_lens[rule->args_len] == 0); 432 433 return TRUE; 434 } 435 436 #define ISWHITE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r')) 437 438 static dbus_bool_t 439 find_key (const DBusString *str, 440 int start, 441 DBusString *key, 442 int *value_pos, 443 DBusError *error) 444 { 445 const char *p; 446 const char *s; 447 const char *key_start; 448 const char *key_end; 449 450 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 451 452 s = _dbus_string_get_const_data (str); 453 454 p = s + start; 455 456 while (*p && ISWHITE (*p)) 457 ++p; 458 459 key_start = p; 460 461 while (*p && *p != '=' && !ISWHITE (*p)) 462 ++p; 463 464 key_end = p; 465 466 while (*p && ISWHITE (*p)) 467 ++p; 468 469 if (key_start == key_end) 470 { 471 /* Empty match rules or trailing whitespace are OK */ 472 *value_pos = p - s; 473 return TRUE; 474 } 475 476 if (*p != '=') 477 { 478 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 479 "Match rule has a key with no subsequent '=' character"); 480 return FALSE; 481 } 482 ++p; 483 484 if (!_dbus_string_append_len (key, key_start, key_end - key_start)) 485 { 486 BUS_SET_OOM (error); 487 return FALSE; 488 } 489 490 *value_pos = p - s; 491 492 return TRUE; 493 } 494 495 static dbus_bool_t 496 find_value (const DBusString *str, 497 int start, 498 const char *key, 499 DBusString *value, 500 int *value_end, 501 DBusError *error) 502 { 503 const char *p; 504 const char *s; 505 char quote_char; 506 int orig_len; 507 508 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 509 510 orig_len = _dbus_string_get_length (value); 511 512 s = _dbus_string_get_const_data (str); 513 514 p = s + start; 515 516 quote_char = '\0'; 517 518 while (*p) 519 { 520 if (quote_char == '\0') 521 { 522 switch (*p) 523 { 524 case '\0': 525 goto done; 526 527 case '\'': 528 quote_char = '\''; 529 goto next; 530 531 case ',': 532 ++p; 533 goto done; 534 535 case '\\': 536 quote_char = '\\'; 537 goto next; 538 539 default: 540 if (!_dbus_string_append_byte (value, *p)) 541 { 542 BUS_SET_OOM (error); 543 goto failed; 544 } 545 } 546 } 547 else if (quote_char == '\\') 548 { 549 /* \ only counts as an escape if escaping a quote mark */ 550 if (*p != '\'') 551 { 552 if (!_dbus_string_append_byte (value, '\\')) 553 { 554 BUS_SET_OOM (error); 555 goto failed; 556 } 557 } 558 559 if (!_dbus_string_append_byte (value, *p)) 560 { 561 BUS_SET_OOM (error); 562 goto failed; 563 } 564 565 quote_char = '\0'; 566 } 567 else 568 { 569 _dbus_assert (quote_char == '\''); 570 571 if (*p == '\'') 572 { 573 quote_char = '\0'; 574 } 575 else 576 { 577 if (!_dbus_string_append_byte (value, *p)) 578 { 579 BUS_SET_OOM (error); 580 goto failed; 581 } 582 } 583 } 584 585 next: 586 ++p; 587 } 588 589 done: 590 591 if (quote_char == '\\') 592 { 593 if (!_dbus_string_append_byte (value, '\\')) 594 { 595 BUS_SET_OOM (error); 596 goto failed; 597 } 598 } 599 else if (quote_char == '\'') 600 { 601 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 602 "Unbalanced quotation marks in match rule"); 603 goto failed; 604 } 605 else 606 _dbus_assert (quote_char == '\0'); 607 608 /* Zero-length values are allowed */ 609 610 *value_end = p - s; 611 612 return TRUE; 613 614 failed: 615 _DBUS_ASSERT_ERROR_IS_SET (error); 616 _dbus_string_set_length (value, orig_len); 617 return FALSE; 618 } 619 620 /* duplicates aren't allowed so the real legitimate max is only 6 or 621 * so. Leaving extra so we don't have to bother to update it. 622 * FIXME this is sort of busted now with arg matching, but we let 623 * you match on up to 10 args for now 624 */ 625 #define MAX_RULE_TOKENS 16 626 627 /* this is slightly too high level to be termed a "token" 628 * but let's not be pedantic. 629 */ 630 typedef struct 631 { 632 char *key; 633 char *value; 634 } RuleToken; 635 636 static dbus_bool_t 637 tokenize_rule (const DBusString *rule_text, 638 RuleToken tokens[MAX_RULE_TOKENS], 639 DBusError *error) 640 { 641 int i; 642 int pos; 643 DBusString key; 644 DBusString value; 645 dbus_bool_t retval; 646 647 retval = FALSE; 648 649 if (!_dbus_string_init (&key)) 650 { 651 BUS_SET_OOM (error); 652 return FALSE; 653 } 654 655 if (!_dbus_string_init (&value)) 656 { 657 _dbus_string_free (&key); 658 BUS_SET_OOM (error); 659 return FALSE; 660 } 661 662 i = 0; 663 pos = 0; 664 while (i < MAX_RULE_TOKENS && 665 pos < _dbus_string_get_length (rule_text)) 666 { 667 _dbus_assert (tokens[i].key == NULL); 668 _dbus_assert (tokens[i].value == NULL); 669 670 if (!find_key (rule_text, pos, &key, &pos, error)) 671 goto out; 672 673 if (_dbus_string_get_length (&key) == 0) 674 goto next; 675 676 if (!_dbus_string_steal_data (&key, &tokens[i].key)) 677 { 678 BUS_SET_OOM (error); 679 goto out; 680 } 681 682 if (!find_value (rule_text, pos, tokens[i].key, &value, &pos, error)) 683 goto out; 684 685 if (!_dbus_string_steal_data (&value, &tokens[i].value)) 686 { 687 BUS_SET_OOM (error); 688 goto out; 689 } 690 691 next: 692 ++i; 693 } 694 695 retval = TRUE; 696 697 out: 698 if (!retval) 699 { 700 i = 0; 701 while (tokens[i].key || tokens[i].value) 702 { 703 dbus_free (tokens[i].key); 704 dbus_free (tokens[i].value); 705 tokens[i].key = NULL; 706 tokens[i].value = NULL; 707 ++i; 708 } 709 } 710 711 _dbus_string_free (&key); 712 _dbus_string_free (&value); 713 714 return retval; 715 } 716 717 static dbus_bool_t 718 bus_match_rule_parse_arg_match (BusMatchRule *rule, 719 const char *key, 720 const DBusString *value, 721 DBusError *error) 722 { 723 dbus_bool_t is_path; 724 DBusString key_str; 725 unsigned long arg; 726 int length; 727 int end; 728 729 /* For now, arg0='foo' always implies that 'foo' is a 730 * DBUS_TYPE_STRING. Someday we could add an arg0type='int32' thing 731 * if we wanted, which would specify another type, in which case 732 * arg0='5' would have the 5 parsed as an int rather than string. 733 */ 734 735 /* First we need to parse arg0 = 0, arg27 = 27 */ 736 737 _dbus_string_init_const (&key_str, key); 738 length = _dbus_string_get_length (&key_str); 739 740 if (_dbus_string_get_length (&key_str) < 4) 741 { 742 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 743 "Key '%s' in match rule starts with 'arg' but lacks an arg number. Should be 'arg0' or 'arg7' for example.\n", key); 744 goto failed; 745 } 746 747 if (!_dbus_string_parse_uint (&key_str, 3, &arg, &end)) 748 { 749 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 750 "Key '%s' in match rule starts with 'arg' but could not parse arg number. Should be 'arg0' or 'arg7' for example.\n", key); 751 goto failed; 752 } 753 754 if (end != length && 755 ((end + 4) != length || 756 !_dbus_string_ends_with_c_str (&key_str, "path"))) 757 { 758 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 759 "Key '%s' in match rule contains junk after argument number. Only 'path' is optionally valid ('arg0path' for example).\n", key); 760 goto failed; 761 } 762 763 is_path = end != length; 764 765 /* If we didn't check this we could allocate a huge amount of RAM */ 766 if (arg > DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER) 767 { 768 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 769 "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); 770 goto failed; 771 } 772 773 if ((rule->flags & BUS_MATCH_ARGS) && 774 rule->args_len > (int) arg && 775 rule->args[arg] != NULL) 776 { 777 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 778 "Argument %d matched more than once in match rule\n", key); 779 goto failed; 780 } 781 782 if (!bus_match_rule_set_arg (rule, arg, value, is_path)) 783 { 784 BUS_SET_OOM (error); 785 goto failed; 786 } 787 788 return TRUE; 789 790 failed: 791 _DBUS_ASSERT_ERROR_IS_SET (error); 792 return FALSE; 793 } 794 795 /* 796 * The format is comma-separated with strings quoted with single quotes 797 * as for the shell (to escape a literal single quote, use '\''). 798 * 799 * type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo', 800 * path='/bar/foo',destination=':452345.34' 801 * 802 */ 803 BusMatchRule* 804 bus_match_rule_parse (DBusConnection *matches_go_to, 805 const DBusString *rule_text, 806 DBusError *error) 807 { 808 BusMatchRule *rule; 809 RuleToken tokens[MAX_RULE_TOKENS+1]; /* NULL termination + 1 */ 810 int i; 811 812 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 813 814 if (_dbus_string_get_length (rule_text) > DBUS_MAXIMUM_MATCH_RULE_LENGTH) 815 { 816 dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, 817 "Match rule text is %d bytes, maximum is %d", 818 _dbus_string_get_length (rule_text), 819 DBUS_MAXIMUM_MATCH_RULE_LENGTH); 820 return NULL; 821 } 822 823 memset (tokens, '\0', sizeof (tokens)); 824 825 rule = bus_match_rule_new (matches_go_to); 826 if (rule == NULL) 827 { 828 BUS_SET_OOM (error); 829 goto failed; 830 } 831 832 if (!tokenize_rule (rule_text, tokens, error)) 833 goto failed; 834 835 i = 0; 836 while (tokens[i].key != NULL) 837 { 838 DBusString tmp_str; 839 int len; 840 const char *key = tokens[i].key; 841 const char *value = tokens[i].value; 842 843 _dbus_string_init_const (&tmp_str, value); 844 len = _dbus_string_get_length (&tmp_str); 845 846 if (strcmp (key, "type") == 0) 847 { 848 int t; 849 850 if (rule->flags & BUS_MATCH_MESSAGE_TYPE) 851 { 852 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 853 "Key %s specified twice in match rule\n", key); 854 goto failed; 855 } 856 857 t = dbus_message_type_from_string (value); 858 859 if (t == DBUS_MESSAGE_TYPE_INVALID) 860 { 861 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 862 "Invalid message type (%s) in match rule\n", value); 863 goto failed; 864 } 865 866 if (!bus_match_rule_set_message_type (rule, t)) 867 { 868 BUS_SET_OOM (error); 869 goto failed; 870 } 871 } 872 else if (strcmp (key, "sender") == 0) 873 { 874 if (rule->flags & BUS_MATCH_SENDER) 875 { 876 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 877 "Key %s specified twice in match rule\n", key); 878 goto failed; 879 } 880 881 if (!_dbus_validate_bus_name (&tmp_str, 0, len)) 882 { 883 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 884 "Sender name '%s' is invalid\n", value); 885 goto failed; 886 } 887 888 if (!bus_match_rule_set_sender (rule, value)) 889 { 890 BUS_SET_OOM (error); 891 goto failed; 892 } 893 } 894 else if (strcmp (key, "interface") == 0) 895 { 896 if (rule->flags & BUS_MATCH_INTERFACE) 897 { 898 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 899 "Key %s specified twice in match rule\n", key); 900 goto failed; 901 } 902 903 if (!_dbus_validate_interface (&tmp_str, 0, len)) 904 { 905 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 906 "Interface name '%s' is invalid\n", value); 907 goto failed; 908 } 909 910 if (!bus_match_rule_set_interface (rule, value)) 911 { 912 BUS_SET_OOM (error); 913 goto failed; 914 } 915 } 916 else if (strcmp (key, "member") == 0) 917 { 918 if (rule->flags & BUS_MATCH_MEMBER) 919 { 920 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 921 "Key %s specified twice in match rule\n", key); 922 goto failed; 923 } 924 925 if (!_dbus_validate_member (&tmp_str, 0, len)) 926 { 927 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 928 "Member name '%s' is invalid\n", value); 929 goto failed; 930 } 931 932 if (!bus_match_rule_set_member (rule, value)) 933 { 934 BUS_SET_OOM (error); 935 goto failed; 936 } 937 } 938 else if (strcmp (key, "path") == 0) 939 { 940 if (rule->flags & BUS_MATCH_PATH) 941 { 942 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 943 "Key %s specified twice in match rule\n", key); 944 goto failed; 945 } 946 947 if (!_dbus_validate_path (&tmp_str, 0, len)) 948 { 949 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 950 "Path '%s' is invalid\n", value); 951 goto failed; 952 } 953 954 if (!bus_match_rule_set_path (rule, value)) 955 { 956 BUS_SET_OOM (error); 957 goto failed; 958 } 959 } 960 else if (strcmp (key, "destination") == 0) 961 { 962 if (rule->flags & BUS_MATCH_DESTINATION) 963 { 964 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 965 "Key %s specified twice in match rule\n", key); 966 goto failed; 967 } 968 969 if (!_dbus_validate_bus_name (&tmp_str, 0, len)) 970 { 971 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 972 "Destination name '%s' is invalid\n", value); 973 goto failed; 974 } 975 976 if (!bus_match_rule_set_destination (rule, value)) 977 { 978 BUS_SET_OOM (error); 979 goto failed; 980 } 981 } 982 else if (strncmp (key, "arg", 3) == 0) 983 { 984 if (!bus_match_rule_parse_arg_match (rule, key, &tmp_str, error)) 985 goto failed; 986 } 987 else 988 { 989 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, 990 "Unknown key \"%s\" in match rule", 991 key); 992 goto failed; 993 } 994 995 ++i; 996 } 997 998 999 goto out; 1000 1001 failed: 1002 _DBUS_ASSERT_ERROR_IS_SET (error); 1003 if (rule) 1004 { 1005 bus_match_rule_unref (rule); 1006 rule = NULL; 1007 } 1008 1009 out: 1010 1011 i = 0; 1012 while (tokens[i].key || tokens[i].value) 1013 { 1014 _dbus_assert (i < MAX_RULE_TOKENS); 1015 dbus_free (tokens[i].key); 1016 dbus_free (tokens[i].value); 1017 ++i; 1018 } 1019 1020 return rule; 1021 } 1022 1023 typedef struct RulePool RulePool; 1024 struct RulePool 1025 { 1026 /* Maps non-NULL interface names to non-NULL (DBusList **)s */ 1027 DBusHashTable *rules_by_iface; 1028 1029 /* List of BusMatchRules which don't specify an interface */ 1030 DBusList *rules_without_iface; 1031 }; 1032 1033 struct BusMatchmaker 1034 { 1035 int refcount; 1036 1037 /* Pools of rules, grouped by the type of message they match. 0 1038 * (DBUS_MESSAGE_TYPE_INVALID) represents rules that do not specify a message 1039 * type. 1040 */ 1041 RulePool rules_by_type[DBUS_NUM_MESSAGE_TYPES]; 1042 }; 1043 1044 static void 1045 rule_list_free (DBusList **rules) 1046 { 1047 while (*rules != NULL) 1048 { 1049 BusMatchRule *rule; 1050 1051 rule = (*rules)->data; 1052 bus_match_rule_unref (rule); 1053 _dbus_list_remove_link (rules, *rules); 1054 } 1055 } 1056 1057 static void 1058 rule_list_ptr_free (DBusList **list) 1059 { 1060 /* We have to cope with NULL because the hash table frees the "existing" 1061 * value (which is NULL) when creating a new table entry... 1062 */ 1063 if (list != NULL) 1064 { 1065 rule_list_free (list); 1066 dbus_free (list); 1067 } 1068 } 1069 1070 BusMatchmaker* 1071 bus_matchmaker_new (void) 1072 { 1073 BusMatchmaker *matchmaker; 1074 int i; 1075 1076 matchmaker = dbus_new0 (BusMatchmaker, 1); 1077 if (matchmaker == NULL) 1078 return NULL; 1079 1080 matchmaker->refcount = 1; 1081 1082 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++) 1083 { 1084 RulePool *p = matchmaker->rules_by_type + i; 1085 1086 p->rules_by_iface = _dbus_hash_table_new (DBUS_HASH_STRING, 1087 dbus_free, (DBusFreeFunction) rule_list_ptr_free); 1088 1089 if (p->rules_by_iface == NULL) 1090 goto nomem; 1091 } 1092 1093 return matchmaker; 1094 1095 nomem: 1096 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++) 1097 { 1098 RulePool *p = matchmaker->rules_by_type + i; 1099 1100 if (p->rules_by_iface == NULL) 1101 break; 1102 else 1103 _dbus_hash_table_unref (p->rules_by_iface); 1104 } 1105 1106 return NULL; 1107 } 1108 1109 static DBusList ** 1110 bus_matchmaker_get_rules (BusMatchmaker *matchmaker, 1111 int message_type, 1112 const char *interface, 1113 dbus_bool_t create) 1114 { 1115 RulePool *p; 1116 1117 _dbus_assert (message_type >= 0); 1118 _dbus_assert (message_type < DBUS_NUM_MESSAGE_TYPES); 1119 1120 _dbus_verbose ("Looking up rules for message_type %d, interface %s\n", 1121 message_type, 1122 interface != NULL ? interface : "<null>"); 1123 1124 p = matchmaker->rules_by_type + message_type; 1125 1126 if (interface == NULL) 1127 { 1128 return &p->rules_without_iface; 1129 } 1130 else 1131 { 1132 DBusList **list; 1133 1134 list = _dbus_hash_table_lookup_string (p->rules_by_iface, interface); 1135 1136 if (list == NULL && create) 1137 { 1138 char *dupped_interface; 1139 1140 list = dbus_new0 (DBusList *, 1); 1141 if (list == NULL) 1142 return NULL; 1143 1144 dupped_interface = _dbus_strdup (interface); 1145 if (dupped_interface == NULL) 1146 { 1147 dbus_free (list); 1148 return NULL; 1149 } 1150 1151 _dbus_verbose ("Adding list for type %d, iface %s\n", message_type, 1152 interface); 1153 1154 if (!_dbus_hash_table_insert_string (p->rules_by_iface, 1155 dupped_interface, list)) 1156 { 1157 dbus_free (list); 1158 dbus_free (dupped_interface); 1159 return NULL; 1160 } 1161 } 1162 1163 return list; 1164 } 1165 } 1166 1167 static void 1168 bus_matchmaker_gc_rules (BusMatchmaker *matchmaker, 1169 int message_type, 1170 const char *interface, 1171 DBusList **rules) 1172 { 1173 RulePool *p; 1174 1175 if (interface == NULL) 1176 return; 1177 1178 if (*rules != NULL) 1179 return; 1180 1181 _dbus_verbose ("GCing HT entry for message_type %u, interface %s\n", 1182 message_type, interface); 1183 1184 p = matchmaker->rules_by_type + message_type; 1185 1186 _dbus_assert (_dbus_hash_table_lookup_string (p->rules_by_iface, interface) 1187 == rules); 1188 1189 _dbus_hash_table_remove_string (p->rules_by_iface, interface); 1190 } 1191 1192 BusMatchmaker * 1193 bus_matchmaker_ref (BusMatchmaker *matchmaker) 1194 { 1195 _dbus_assert (matchmaker->refcount > 0); 1196 1197 matchmaker->refcount += 1; 1198 1199 return matchmaker; 1200 } 1201 1202 void 1203 bus_matchmaker_unref (BusMatchmaker *matchmaker) 1204 { 1205 _dbus_assert (matchmaker->refcount > 0); 1206 1207 matchmaker->refcount -= 1; 1208 if (matchmaker->refcount == 0) 1209 { 1210 int i; 1211 1212 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++) 1213 { 1214 RulePool *p = matchmaker->rules_by_type + i; 1215 1216 _dbus_hash_table_unref (p->rules_by_iface); 1217 rule_list_free (&p->rules_without_iface); 1218 } 1219 1220 dbus_free (matchmaker); 1221 } 1222 } 1223 1224 /* The rule can't be modified after it's added. */ 1225 dbus_bool_t 1226 bus_matchmaker_add_rule (BusMatchmaker *matchmaker, 1227 BusMatchRule *rule) 1228 { 1229 DBusList **rules; 1230 1231 _dbus_assert (bus_connection_is_active (rule->matches_go_to)); 1232 1233 _dbus_verbose ("Adding rule with message_type %d, interface %s\n", 1234 rule->message_type, 1235 rule->interface != NULL ? rule->interface : "<null>"); 1236 1237 rules = bus_matchmaker_get_rules (matchmaker, rule->message_type, 1238 rule->interface, TRUE); 1239 1240 if (rules == NULL) 1241 return FALSE; 1242 1243 if (!_dbus_list_append (rules, rule)) 1244 return FALSE; 1245 1246 if (!bus_connection_add_match_rule (rule->matches_go_to, rule)) 1247 { 1248 _dbus_list_remove_last (rules, rule); 1249 bus_matchmaker_gc_rules (matchmaker, rule->message_type, 1250 rule->interface, rules); 1251 return FALSE; 1252 } 1253 1254 bus_match_rule_ref (rule); 1255 1256 #ifdef DBUS_ENABLE_VERBOSE_MODE 1257 { 1258 char *s = match_rule_to_string (rule); 1259 1260 _dbus_verbose ("Added match rule %s to connection %p\n", 1261 s, rule->matches_go_to); 1262 dbus_free (s); 1263 } 1264 #endif 1265 1266 return TRUE; 1267 } 1268 1269 static dbus_bool_t 1270 match_rule_equal (BusMatchRule *a, 1271 BusMatchRule *b) 1272 { 1273 if (a->flags != b->flags) 1274 return FALSE; 1275 1276 if (a->matches_go_to != b->matches_go_to) 1277 return FALSE; 1278 1279 if ((a->flags & BUS_MATCH_MESSAGE_TYPE) && 1280 a->message_type != b->message_type) 1281 return FALSE; 1282 1283 if ((a->flags & BUS_MATCH_MEMBER) && 1284 strcmp (a->member, b->member) != 0) 1285 return FALSE; 1286 1287 if ((a->flags & BUS_MATCH_PATH) && 1288 strcmp (a->path, b->path) != 0) 1289 return FALSE; 1290 1291 if ((a->flags & BUS_MATCH_INTERFACE) && 1292 strcmp (a->interface, b->interface) != 0) 1293 return FALSE; 1294 1295 if ((a->flags & BUS_MATCH_SENDER) && 1296 strcmp (a->sender, b->sender) != 0) 1297 return FALSE; 1298 1299 if ((a->flags & BUS_MATCH_DESTINATION) && 1300 strcmp (a->destination, b->destination) != 0) 1301 return FALSE; 1302 1303 if (a->flags & BUS_MATCH_ARGS) 1304 { 1305 int i; 1306 1307 if (a->args_len != b->args_len) 1308 return FALSE; 1309 1310 i = 0; 1311 while (i < a->args_len) 1312 { 1313 int length; 1314 1315 if ((a->args[i] != NULL) != (b->args[i] != NULL)) 1316 return FALSE; 1317 1318 if (a->arg_lens[i] != b->arg_lens[i]) 1319 return FALSE; 1320 1321 length = a->arg_lens[i] & ~BUS_MATCH_ARG_IS_PATH; 1322 1323 if (a->args[i] != NULL) 1324 { 1325 _dbus_assert (b->args[i] != NULL); 1326 if (memcmp (a->args[i], b->args[i], length) != 0) 1327 return FALSE; 1328 } 1329 1330 ++i; 1331 } 1332 } 1333 1334 return TRUE; 1335 } 1336 1337 static void 1338 bus_matchmaker_remove_rule_link (DBusList **rules, 1339 DBusList *link) 1340 { 1341 BusMatchRule *rule = link->data; 1342 1343 bus_connection_remove_match_rule (rule->matches_go_to, rule); 1344 _dbus_list_remove_link (rules, link); 1345 1346 #ifdef DBUS_ENABLE_VERBOSE_MODE 1347 { 1348 char *s = match_rule_to_string (rule); 1349 1350 _dbus_verbose ("Removed match rule %s for connection %p\n", 1351 s, rule->matches_go_to); 1352 dbus_free (s); 1353 } 1354 #endif 1355 1356 bus_match_rule_unref (rule); 1357 } 1358 1359 void 1360 bus_matchmaker_remove_rule (BusMatchmaker *matchmaker, 1361 BusMatchRule *rule) 1362 { 1363 DBusList **rules; 1364 1365 _dbus_verbose ("Removing rule with message_type %d, interface %s\n", 1366 rule->message_type, 1367 rule->interface != NULL ? rule->interface : "<null>"); 1368 1369 bus_connection_remove_match_rule (rule->matches_go_to, rule); 1370 1371 rules = bus_matchmaker_get_rules (matchmaker, rule->message_type, 1372 rule->interface, FALSE); 1373 1374 /* We should only be asked to remove a rule by identity right after it was 1375 * added, so there should be a list for it. 1376 */ 1377 _dbus_assert (rules != NULL); 1378 1379 _dbus_list_remove (rules, rule); 1380 bus_matchmaker_gc_rules (matchmaker, rule->message_type, rule->interface, 1381 rules); 1382 1383 #ifdef DBUS_ENABLE_VERBOSE_MODE 1384 { 1385 char *s = match_rule_to_string (rule); 1386 1387 _dbus_verbose ("Removed match rule %s for connection %p\n", 1388 s, rule->matches_go_to); 1389 dbus_free (s); 1390 } 1391 #endif 1392 1393 bus_match_rule_unref (rule); 1394 } 1395 1396 /* Remove a single rule which is equal to the given rule by value */ 1397 dbus_bool_t 1398 bus_matchmaker_remove_rule_by_value (BusMatchmaker *matchmaker, 1399 BusMatchRule *value, 1400 DBusError *error) 1401 { 1402 DBusList **rules; 1403 DBusList *link = NULL; 1404 1405 _dbus_verbose ("Removing rule by value with message_type %d, interface %s\n", 1406 value->message_type, 1407 value->interface != NULL ? value->interface : "<null>"); 1408 1409 rules = bus_matchmaker_get_rules (matchmaker, value->message_type, 1410 value->interface, FALSE); 1411 1412 if (rules != NULL) 1413 { 1414 /* we traverse backward because bus_connection_remove_match_rule() 1415 * removes the most-recently-added rule 1416 */ 1417 link = _dbus_list_get_last_link (rules); 1418 while (link != NULL) 1419 { 1420 BusMatchRule *rule; 1421 DBusList *prev; 1422 1423 rule = link->data; 1424 prev = _dbus_list_get_prev_link (rules, link); 1425 1426 if (match_rule_equal (rule, value)) 1427 { 1428 bus_matchmaker_remove_rule_link (rules, link); 1429 break; 1430 } 1431 1432 link = prev; 1433 } 1434 } 1435 1436 if (link == NULL) 1437 { 1438 dbus_set_error (error, DBUS_ERROR_MATCH_RULE_NOT_FOUND, 1439 "The given match rule wasn't found and can't be removed"); 1440 return FALSE; 1441 } 1442 1443 bus_matchmaker_gc_rules (matchmaker, value->message_type, value->interface, 1444 rules); 1445 1446 return TRUE; 1447 } 1448 1449 static void 1450 rule_list_remove_by_connection (DBusList **rules, 1451 DBusConnection *connection) 1452 { 1453 DBusList *link; 1454 1455 link = _dbus_list_get_first_link (rules); 1456 while (link != NULL) 1457 { 1458 BusMatchRule *rule; 1459 DBusList *next; 1460 1461 rule = link->data; 1462 next = _dbus_list_get_next_link (rules, link); 1463 1464 if (rule->matches_go_to == connection) 1465 { 1466 bus_matchmaker_remove_rule_link (rules, link); 1467 } 1468 else if (((rule->flags & BUS_MATCH_SENDER) && *rule->sender == ':') || 1469 ((rule->flags & BUS_MATCH_DESTINATION) && *rule->destination == ':')) 1470 { 1471 /* The rule matches to/from a base service, see if it's the 1472 * one being disconnected, since we know this service name 1473 * will never be recycled. 1474 */ 1475 const char *name; 1476 1477 name = bus_connection_get_name (connection); 1478 _dbus_assert (name != NULL); /* because we're an active connection */ 1479 1480 if (((rule->flags & BUS_MATCH_SENDER) && 1481 strcmp (rule->sender, name) == 0) || 1482 ((rule->flags & BUS_MATCH_DESTINATION) && 1483 strcmp (rule->destination, name) == 0)) 1484 { 1485 bus_matchmaker_remove_rule_link (rules, link); 1486 } 1487 } 1488 1489 link = next; 1490 } 1491 } 1492 1493 void 1494 bus_matchmaker_disconnected (BusMatchmaker *matchmaker, 1495 DBusConnection *connection) 1496 { 1497 int i; 1498 1499 /* FIXME 1500 * 1501 * This scans all match rules on the bus. We could avoid that 1502 * for the rules belonging to the connection, since we keep 1503 * a list of those; but for the rules that just refer to 1504 * the connection we'd need to do something more elaborate. 1505 */ 1506 1507 _dbus_assert (bus_connection_is_active (connection)); 1508 1509 _dbus_verbose ("Removing all rules for connection %p\n", connection); 1510 1511 for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++) 1512 { 1513 RulePool *p = matchmaker->rules_by_type + i; 1514 DBusHashIter iter; 1515 1516 rule_list_remove_by_connection (&p->rules_without_iface, connection); 1517 1518 _dbus_hash_iter_init (p->rules_by_iface, &iter); 1519 while (_dbus_hash_iter_next (&iter)) 1520 { 1521 DBusList **items = _dbus_hash_iter_get_value (&iter); 1522 1523 rule_list_remove_by_connection (items, connection); 1524 1525 if (*items == NULL) 1526 _dbus_hash_iter_remove_entry (&iter); 1527 } 1528 } 1529 } 1530 1531 static dbus_bool_t 1532 connection_is_primary_owner (DBusConnection *connection, 1533 const char *service_name) 1534 { 1535 BusService *service; 1536 DBusString str; 1537 BusRegistry *registry; 1538 1539 _dbus_assert (connection != NULL); 1540 1541 registry = bus_connection_get_registry (connection); 1542 1543 _dbus_string_init_const (&str, service_name); 1544 service = bus_registry_lookup (registry, &str); 1545 1546 if (service == NULL) 1547 return FALSE; /* Service doesn't exist so connection can't own it. */ 1548 1549 return bus_service_get_primary_owners_connection (service) == connection; 1550 } 1551 1552 static dbus_bool_t 1553 match_rule_matches (BusMatchRule *rule, 1554 DBusConnection *sender, 1555 DBusConnection *addressed_recipient, 1556 DBusMessage *message, 1557 BusMatchFlags already_matched) 1558 { 1559 int flags; 1560 1561 /* All features of the match rule are AND'd together, 1562 * so FALSE if any of them don't match. 1563 */ 1564 1565 /* sender/addressed_recipient of #NULL may mean bus driver, 1566 * or for addressed_recipient may mean a message with no 1567 * specific recipient (i.e. a signal) 1568 */ 1569 1570 /* Don't bother re-matching features we've already checked implicitly. */ 1571 flags = rule->flags & (~already_matched); 1572 1573 if (flags & BUS_MATCH_MESSAGE_TYPE) 1574 { 1575 _dbus_assert (rule->message_type != DBUS_MESSAGE_TYPE_INVALID); 1576 1577 if (rule->message_type != dbus_message_get_type (message)) 1578 return FALSE; 1579 } 1580 1581 if (flags & BUS_MATCH_INTERFACE) 1582 { 1583 const char *iface; 1584 1585 _dbus_assert (rule->interface != NULL); 1586 1587 iface = dbus_message_get_interface (message); 1588 if (iface == NULL) 1589 return FALSE; 1590 1591 if (strcmp (iface, rule->interface) != 0) 1592 return FALSE; 1593 } 1594 1595 if (flags & BUS_MATCH_MEMBER) 1596 { 1597 const char *member; 1598 1599 _dbus_assert (rule->member != NULL); 1600 1601 member = dbus_message_get_member (message); 1602 if (member == NULL) 1603 return FALSE; 1604 1605 if (strcmp (member, rule->member) != 0) 1606 return FALSE; 1607 } 1608 1609 if (flags & BUS_MATCH_SENDER) 1610 { 1611 _dbus_assert (rule->sender != NULL); 1612 1613 if (sender == NULL) 1614 { 1615 if (strcmp (rule->sender, 1616 DBUS_SERVICE_DBUS) != 0) 1617 return FALSE; 1618 } 1619 else 1620 { 1621 if (!connection_is_primary_owner (sender, rule->sender)) 1622 return FALSE; 1623 } 1624 } 1625 1626 if (flags & BUS_MATCH_DESTINATION) 1627 { 1628 const char *destination; 1629 1630 _dbus_assert (rule->destination != NULL); 1631 1632 destination = dbus_message_get_destination (message); 1633 if (destination == NULL) 1634 return FALSE; 1635 1636 if (addressed_recipient == NULL) 1637 { 1638 if (strcmp (rule->destination, 1639 DBUS_SERVICE_DBUS) != 0) 1640 return FALSE; 1641 } 1642 else 1643 { 1644 if (!connection_is_primary_owner (addressed_recipient, rule->destination)) 1645 return FALSE; 1646 } 1647 } 1648 1649 if (flags & BUS_MATCH_PATH) 1650 { 1651 const char *path; 1652 1653 _dbus_assert (rule->path != NULL); 1654 1655 path = dbus_message_get_path (message); 1656 if (path == NULL) 1657 return FALSE; 1658 1659 if (strcmp (path, rule->path) != 0) 1660 return FALSE; 1661 } 1662 1663 if (flags & BUS_MATCH_ARGS) 1664 { 1665 int i; 1666 DBusMessageIter iter; 1667 1668 _dbus_assert (rule->args != NULL); 1669 1670 dbus_message_iter_init (message, &iter); 1671 1672 i = 0; 1673 while (i < rule->args_len) 1674 { 1675 int current_type; 1676 const char *expected_arg; 1677 int expected_length; 1678 dbus_bool_t is_path; 1679 1680 expected_arg = rule->args[i]; 1681 expected_length = rule->arg_lens[i] & ~BUS_MATCH_ARG_IS_PATH; 1682 is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0; 1683 1684 current_type = dbus_message_iter_get_arg_type (&iter); 1685 1686 if (expected_arg != NULL) 1687 { 1688 const char *actual_arg; 1689 int actual_length; 1690 1691 if (current_type != DBUS_TYPE_STRING) 1692 return FALSE; 1693 1694 actual_arg = NULL; 1695 dbus_message_iter_get_basic (&iter, &actual_arg); 1696 _dbus_assert (actual_arg != NULL); 1697 1698 actual_length = strlen (actual_arg); 1699 1700 if (is_path) 1701 { 1702 if (actual_length < expected_length && 1703 actual_arg[actual_length - 1] != '/') 1704 return FALSE; 1705 1706 if (expected_length < actual_length && 1707 expected_arg[expected_length - 1] != '/') 1708 return FALSE; 1709 1710 if (memcmp (actual_arg, expected_arg, 1711 MIN (actual_length, expected_length)) != 0) 1712 return FALSE; 1713 } 1714 else 1715 { 1716 if (expected_length != actual_length || 1717 memcmp (expected_arg, actual_arg, expected_length) != 0) 1718 return FALSE; 1719 } 1720 1721 } 1722 1723 if (current_type != DBUS_TYPE_INVALID) 1724 dbus_message_iter_next (&iter); 1725 1726 ++i; 1727 } 1728 } 1729 1730 return TRUE; 1731 } 1732 1733 static dbus_bool_t 1734 get_recipients_from_list (DBusList **rules, 1735 DBusConnection *sender, 1736 DBusConnection *addressed_recipient, 1737 DBusMessage *message, 1738 DBusList **recipients_p) 1739 { 1740 DBusList *link; 1741 1742 if (rules == NULL) 1743 return TRUE; 1744 1745 link = _dbus_list_get_first_link (rules); 1746 while (link != NULL) 1747 { 1748 BusMatchRule *rule; 1749 1750 rule = link->data; 1751 1752 #ifdef DBUS_ENABLE_VERBOSE_MODE 1753 { 1754 char *s = match_rule_to_string (rule); 1755 1756 _dbus_verbose ("Checking whether message matches rule %s for connection %p\n", 1757 s, rule->matches_go_to); 1758 dbus_free (s); 1759 } 1760 #endif 1761 1762 if (match_rule_matches (rule, 1763 sender, addressed_recipient, message, 1764 BUS_MATCH_MESSAGE_TYPE | BUS_MATCH_INTERFACE)) 1765 { 1766 _dbus_verbose ("Rule matched\n"); 1767 1768 /* Append to the list if we haven't already */ 1769 if (bus_connection_mark_stamp (rule->matches_go_to)) 1770 { 1771 if (!_dbus_list_append (recipients_p, rule->matches_go_to)) 1772 return FALSE; 1773 } 1774 #ifdef DBUS_ENABLE_VERBOSE_MODE 1775 else 1776 { 1777 _dbus_verbose ("Connection already receiving this message, so not adding again\n"); 1778 } 1779 #endif /* DBUS_ENABLE_VERBOSE_MODE */ 1780 } 1781 1782 link = _dbus_list_get_next_link (rules, link); 1783 } 1784 1785 return TRUE; 1786 } 1787 1788 dbus_bool_t 1789 bus_matchmaker_get_recipients (BusMatchmaker *matchmaker, 1790 BusConnections *connections, 1791 DBusConnection *sender, 1792 DBusConnection *addressed_recipient, 1793 DBusMessage *message, 1794 DBusList **recipients_p) 1795 { 1796 int type; 1797 const char *interface; 1798 DBusList **neither, **just_type, **just_iface, **both; 1799 1800 _dbus_assert (*recipients_p == NULL); 1801 1802 /* This avoids sending same message to the same connection twice. 1803 * Purpose of the stamp instead of a bool is to avoid iterating over 1804 * all connections resetting the bool each time. 1805 */ 1806 bus_connections_increment_stamp (connections); 1807 1808 /* addressed_recipient is already receiving the message, don't add to list. 1809 * NULL addressed_recipient means either bus driver, or this is a signal 1810 * and thus lacks a specific addressed_recipient. 1811 */ 1812 if (addressed_recipient != NULL) 1813 bus_connection_mark_stamp (addressed_recipient); 1814 1815 type = dbus_message_get_type (message); 1816 interface = dbus_message_get_interface (message); 1817 1818 neither = bus_matchmaker_get_rules (matchmaker, DBUS_MESSAGE_TYPE_INVALID, 1819 NULL, FALSE); 1820 just_type = just_iface = both = NULL; 1821 1822 if (interface != NULL) 1823 just_iface = bus_matchmaker_get_rules (matchmaker, 1824 DBUS_MESSAGE_TYPE_INVALID, interface, FALSE); 1825 1826 if (type > DBUS_MESSAGE_TYPE_INVALID && type < DBUS_NUM_MESSAGE_TYPES) 1827 { 1828 just_type = bus_matchmaker_get_rules (matchmaker, type, NULL, FALSE); 1829 1830 if (interface != NULL) 1831 both = bus_matchmaker_get_rules (matchmaker, type, interface, FALSE); 1832 } 1833 1834 if (!(get_recipients_from_list (neither, sender, addressed_recipient, 1835 message, recipients_p) && 1836 get_recipients_from_list (just_iface, sender, addressed_recipient, 1837 message, recipients_p) && 1838 get_recipients_from_list (just_type, sender, addressed_recipient, 1839 message, recipients_p) && 1840 get_recipients_from_list (both, sender, addressed_recipient, 1841 message, recipients_p))) 1842 { 1843 _dbus_list_clear (recipients_p); 1844 return FALSE; 1845 } 1846 1847 return TRUE; 1848 } 1849 1850 #ifdef DBUS_BUILD_TESTS 1851 #include "test.h" 1852 #include <stdlib.h> 1853 1854 static BusMatchRule* 1855 check_parse (dbus_bool_t should_succeed, 1856 const char *text) 1857 { 1858 BusMatchRule *rule; 1859 DBusString str; 1860 DBusError error; 1861 1862 dbus_error_init (&error); 1863 1864 _dbus_string_init_const (&str, text); 1865 1866 rule = bus_match_rule_parse (NULL, &str, &error); 1867 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) 1868 { 1869 dbus_error_free (&error); 1870 return NULL; 1871 } 1872 1873 if (should_succeed && rule == NULL) 1874 { 1875 _dbus_warn ("Failed to parse: %s: %s: \"%s\"\n", 1876 error.name, error.message, 1877 _dbus_string_get_const_data (&str)); 1878 exit (1); 1879 } 1880 1881 if (!should_succeed && rule != NULL) 1882 { 1883 _dbus_warn ("Failed to fail to parse: \"%s\"\n", 1884 _dbus_string_get_const_data (&str)); 1885 exit (1); 1886 } 1887 1888 dbus_error_free (&error); 1889 1890 return rule; 1891 } 1892 1893 static void 1894 assert_large_rule (BusMatchRule *rule) 1895 { 1896 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE); 1897 _dbus_assert (rule->flags & BUS_MATCH_SENDER); 1898 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE); 1899 _dbus_assert (rule->flags & BUS_MATCH_MEMBER); 1900 _dbus_assert (rule->flags & BUS_MATCH_DESTINATION); 1901 _dbus_assert (rule->flags & BUS_MATCH_PATH); 1902 1903 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL); 1904 _dbus_assert (rule->interface != NULL); 1905 _dbus_assert (rule->member != NULL); 1906 _dbus_assert (rule->sender != NULL); 1907 _dbus_assert (rule->destination != NULL); 1908 _dbus_assert (rule->path != NULL); 1909 1910 _dbus_assert (strcmp (rule->interface, "org.freedesktop.DBusInterface") == 0); 1911 _dbus_assert (strcmp (rule->sender, "org.freedesktop.DBusSender") == 0); 1912 _dbus_assert (strcmp (rule->member, "Foo") == 0); 1913 _dbus_assert (strcmp (rule->path, "/bar/foo") == 0); 1914 _dbus_assert (strcmp (rule->destination, ":452345.34") == 0); 1915 } 1916 1917 static dbus_bool_t 1918 test_parsing (void *data) 1919 { 1920 BusMatchRule *rule; 1921 1922 rule = check_parse (TRUE, "type='signal',sender='org.freedesktop.DBusSender',interface='org.freedesktop.DBusInterface',member='Foo',path='/bar/foo',destination=':452345.34'"); 1923 if (rule != NULL) 1924 { 1925 assert_large_rule (rule); 1926 bus_match_rule_unref (rule); 1927 } 1928 1929 /* With extra whitespace and useless quotes */ 1930 rule = check_parse (TRUE, " type='signal', \tsender='org.freedes''ktop.DBusSender', interface='org.freedesktop.DBusInterface''''', \tmember='Foo',path='/bar/foo',destination=':452345.34'''''"); 1931 if (rule != NULL) 1932 { 1933 assert_large_rule (rule); 1934 bus_match_rule_unref (rule); 1935 } 1936 1937 1938 /* A simple signal connection */ 1939 rule = check_parse (TRUE, "type='signal',path='/foo',interface='org.Bar'"); 1940 if (rule != NULL) 1941 { 1942 _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE); 1943 _dbus_assert (rule->flags & BUS_MATCH_INTERFACE); 1944 _dbus_assert (rule->flags & BUS_MATCH_PATH); 1945 1946 _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL); 1947 _dbus_assert (rule->interface != NULL); 1948 _dbus_assert (rule->path != NULL); 1949 1950 _dbus_assert (strcmp (rule->interface, "org.Bar") == 0); 1951 _dbus_assert (strcmp (rule->path, "/foo") == 0); 1952 1953 bus_match_rule_unref (rule); 1954 } 1955 1956 /* argN */ 1957 rule = check_parse (TRUE, "arg0='foo'"); 1958 if (rule != NULL) 1959 { 1960 _dbus_assert (rule->flags == BUS_MATCH_ARGS); 1961 _dbus_assert (rule->args != NULL); 1962 _dbus_assert (rule->args_len == 1); 1963 _dbus_assert (rule->args[0] != NULL); 1964 _dbus_assert (rule->args[1] == NULL); 1965 _dbus_assert (strcmp (rule->args[0], "foo") == 0); 1966 1967 bus_match_rule_unref (rule); 1968 } 1969 1970 rule = check_parse (TRUE, "arg1='foo'"); 1971 if (rule != NULL) 1972 { 1973 _dbus_assert (rule->flags == BUS_MATCH_ARGS); 1974 _dbus_assert (rule->args != NULL); 1975 _dbus_assert (rule->args_len == 2); 1976 _dbus_assert (rule->args[0] == NULL); 1977 _dbus_assert (rule->args[1] != NULL); 1978 _dbus_assert (rule->args[2] == NULL); 1979 _dbus_assert (strcmp (rule->args[1], "foo") == 0); 1980 1981 bus_match_rule_unref (rule); 1982 } 1983 1984 rule = check_parse (TRUE, "arg2='foo'"); 1985 if (rule != NULL) 1986 { 1987 _dbus_assert (rule->flags == BUS_MATCH_ARGS); 1988 _dbus_assert (rule->args != NULL); 1989 _dbus_assert (rule->args_len == 3); 1990 _dbus_assert (rule->args[0] == NULL); 1991 _dbus_assert (rule->args[1] == NULL); 1992 _dbus_assert (rule->args[2] != NULL); 1993 _dbus_assert (rule->args[3] == NULL); 1994 _dbus_assert (strcmp (rule->args[2], "foo") == 0); 1995 1996 bus_match_rule_unref (rule); 1997 } 1998 1999 rule = check_parse (TRUE, "arg40='foo'"); 2000 if (rule != NULL) 2001 { 2002 _dbus_assert (rule->flags == BUS_MATCH_ARGS); 2003 _dbus_assert (rule->args != NULL); 2004 _dbus_assert (rule->args_len == 41); 2005 _dbus_assert (rule->args[0] == NULL); 2006 _dbus_assert (rule->args[1] == NULL); 2007 _dbus_assert (rule->args[40] != NULL); 2008 _dbus_assert (rule->args[41] == NULL); 2009 _dbus_assert (strcmp (rule->args[40], "foo") == 0); 2010 2011 bus_match_rule_unref (rule); 2012 } 2013 2014 rule = check_parse (TRUE, "arg63='foo'"); 2015 if (rule != NULL) 2016 { 2017 _dbus_assert (rule->flags == BUS_MATCH_ARGS); 2018 _dbus_assert (rule->args != NULL); 2019 _dbus_assert (rule->args_len == 64); 2020 _dbus_assert (rule->args[0] == NULL); 2021 _dbus_assert (rule->args[1] == NULL); 2022 _dbus_assert (rule->args[63] != NULL); 2023 _dbus_assert (rule->args[64] == NULL); 2024 _dbus_assert (strcmp (rule->args[63], "foo") == 0); 2025 2026 bus_match_rule_unref (rule); 2027 } 2028 2029 /* Too-large argN */ 2030 rule = check_parse (FALSE, "arg300='foo'"); 2031 _dbus_assert (rule == NULL); 2032 rule = check_parse (FALSE, "arg64='foo'"); 2033 _dbus_assert (rule == NULL); 2034 2035 /* No N in argN */ 2036 rule = check_parse (FALSE, "arg='foo'"); 2037 _dbus_assert (rule == NULL); 2038 rule = check_parse (FALSE, "argv='foo'"); 2039 _dbus_assert (rule == NULL); 2040 rule = check_parse (FALSE, "arg3junk='foo'"); 2041 _dbus_assert (rule == NULL); 2042 rule = check_parse (FALSE, "argument='foo'"); 2043 _dbus_assert (rule == NULL); 2044 2045 /* Reject duplicates */ 2046 rule = check_parse (FALSE, "type='signal',type='method_call'"); 2047 _dbus_assert (rule == NULL); 2048 2049 /* Duplicates with the argN code */ 2050 rule = check_parse (FALSE, "arg0='foo',arg0='bar'"); 2051 _dbus_assert (rule == NULL); 2052 rule = check_parse (FALSE, "arg3='foo',arg3='bar'"); 2053 _dbus_assert (rule == NULL); 2054 rule = check_parse (FALSE, "arg30='foo',arg30='bar'"); 2055 _dbus_assert (rule == NULL); 2056 2057 /* Reject broken keys */ 2058 rule = check_parse (FALSE, "blah='signal'"); 2059 _dbus_assert (rule == NULL); 2060 2061 /* Reject broken values */ 2062 rule = check_parse (FALSE, "type='chouin'"); 2063 _dbus_assert (rule == NULL); 2064 rule = check_parse (FALSE, "interface='abc@def++'"); 2065 _dbus_assert (rule == NULL); 2066 rule = check_parse (FALSE, "service='youpi'"); 2067 _dbus_assert (rule == NULL); 2068 2069 /* Allow empty rule */ 2070 rule = check_parse (TRUE, ""); 2071 if (rule != NULL) 2072 { 2073 _dbus_assert (rule->flags == 0); 2074 2075 bus_match_rule_unref (rule); 2076 } 2077 2078 /* All-whitespace rule is the same as empty */ 2079 rule = check_parse (TRUE, " \t"); 2080 if (rule != NULL) 2081 { 2082 _dbus_assert (rule->flags == 0); 2083 2084 bus_match_rule_unref (rule); 2085 } 2086 2087 /* But with non-whitespace chars and no =value, it's not OK */ 2088 rule = check_parse (FALSE, "type"); 2089 _dbus_assert (rule == NULL); 2090 2091 return TRUE; 2092 } 2093 2094 static struct { 2095 const char *first; 2096 const char *second; 2097 } equality_tests[] = { 2098 { "type='signal'", "type='signal'" }, 2099 { "type='signal',interface='foo.bar'", "interface='foo.bar',type='signal'" }, 2100 { "type='signal',member='bar'", "member='bar',type='signal'" }, 2101 { "type='method_call',sender=':1.0'", "sender=':1.0',type='method_call'" }, 2102 { "type='method_call',destination=':1.0'", "destination=':1.0',type='method_call'" }, 2103 { "type='method_call',path='/foo/bar'", "path='/foo/bar',type='method_call'" }, 2104 { "type='method_call',arg0='blah'", "arg0='blah',type='method_call'" }, 2105 { "type='method_call',arg0='boo'", "arg0='boo',type='method_call'" }, 2106 { "type='method_call',arg0='blah',arg1='baz'", "arg0='blah',arg1='baz',type='method_call'" }, 2107 { "type='method_call',arg3='foosh'", "arg3='foosh',type='method_call'" }, 2108 { "arg3='fool'", "arg3='fool'" }, 2109 { "member='food'", "member='food'" } 2110 }; 2111 2112 static void 2113 test_equality (void) 2114 { 2115 int i; 2116 2117 i = 0; 2118 while (i < _DBUS_N_ELEMENTS (equality_tests)) 2119 { 2120 BusMatchRule *first; 2121 BusMatchRule *second; 2122 int j; 2123 2124 first = check_parse (TRUE, equality_tests[i].first); 2125 _dbus_assert (first != NULL); 2126 second = check_parse (TRUE, equality_tests[i].second); 2127 _dbus_assert (second != NULL); 2128 2129 if (!match_rule_equal (first, second)) 2130 { 2131 _dbus_warn ("rule %s and %s should have been equal\n", 2132 equality_tests[i].first, 2133 equality_tests[i].second); 2134 exit (1); 2135 } 2136 2137 bus_match_rule_unref (second); 2138 2139 /* Check that the rule is not equal to any of the 2140 * others besides its pair match 2141 */ 2142 j = 0; 2143 while (j < _DBUS_N_ELEMENTS (equality_tests)) 2144 { 2145 if (i != j) 2146 { 2147 second = check_parse (TRUE, equality_tests[j].second); 2148 2149 if (match_rule_equal (first, second)) 2150 { 2151 _dbus_warn ("rule %s and %s should not have been equal\n", 2152 equality_tests[i].first, 2153 equality_tests[j].second); 2154 exit (1); 2155 } 2156 2157 bus_match_rule_unref (second); 2158 } 2159 2160 ++j; 2161 } 2162 2163 bus_match_rule_unref (first); 2164 2165 ++i; 2166 } 2167 } 2168 2169 static const char* 2170 should_match_message_1[] = { 2171 "type='signal'", 2172 "member='Frobated'", 2173 "arg0='foobar'", 2174 "type='signal',member='Frobated'", 2175 "type='signal',member='Frobated',arg0='foobar'", 2176 "member='Frobated',arg0='foobar'", 2177 "type='signal',arg0='foobar'", 2178 NULL 2179 }; 2180 2181 static const char* 2182 should_not_match_message_1[] = { 2183 "type='method_call'", 2184 "type='error'", 2185 "type='method_return'", 2186 "type='signal',member='Oopsed'", 2187 "arg0='blah'", 2188 "arg1='foobar'", 2189 "arg2='foobar'", 2190 "arg3='foobar'", 2191 "arg0='3'", 2192 "arg1='3'", 2193 "arg0='foobar',arg1='abcdef'", 2194 "arg0='foobar',arg1='abcdef',arg2='abcdefghi',arg3='abcdefghi',arg4='abcdefghi'", 2195 "arg0='foobar',arg1='abcdef',arg4='abcdefghi',arg3='abcdefghi',arg2='abcdefghi'", 2196 NULL 2197 }; 2198 2199 static void 2200 check_matches (dbus_bool_t expected_to_match, 2201 int number, 2202 DBusMessage *message, 2203 const char *rule_text) 2204 { 2205 BusMatchRule *rule; 2206 dbus_bool_t matched; 2207 2208 rule = check_parse (TRUE, rule_text); 2209 _dbus_assert (rule != NULL); 2210 2211 /* We can't test sender/destination rules since we pass NULL here */ 2212 matched = match_rule_matches (rule, NULL, NULL, message, 0); 2213 2214 if (matched != expected_to_match) 2215 { 2216 _dbus_warn ("Expected rule %s to %s message %d, failed\n", 2217 rule_text, expected_to_match ? 2218 "match" : "not match", number); 2219 exit (1); 2220 } 2221 2222 bus_match_rule_unref (rule); 2223 } 2224 2225 static void 2226 check_matching (DBusMessage *message, 2227 int number, 2228 const char **should_match, 2229 const char **should_not_match) 2230 { 2231 int i; 2232 2233 i = 0; 2234 while (should_match[i] != NULL) 2235 { 2236 check_matches (TRUE, number, message, should_match[i]); 2237 ++i; 2238 } 2239 2240 i = 0; 2241 while (should_not_match[i] != NULL) 2242 { 2243 check_matches (FALSE, number, message, should_not_match[i]); 2244 ++i; 2245 } 2246 } 2247 2248 static void 2249 test_matching (void) 2250 { 2251 DBusMessage *message1; 2252 const char *v_STRING; 2253 dbus_int32_t v_INT32; 2254 2255 message1 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL); 2256 _dbus_assert (message1 != NULL); 2257 if (!dbus_message_set_member (message1, "Frobated")) 2258 _dbus_assert_not_reached ("oom"); 2259 2260 v_STRING = "foobar"; 2261 v_INT32 = 3; 2262 if (!dbus_message_append_args (message1, 2263 DBUS_TYPE_STRING, &v_STRING, 2264 DBUS_TYPE_INT32, &v_INT32, 2265 NULL)) 2266 _dbus_assert_not_reached ("oom"); 2267 2268 check_matching (message1, 1, 2269 should_match_message_1, 2270 should_not_match_message_1); 2271 2272 dbus_message_unref (message1); 2273 } 2274 2275 dbus_bool_t 2276 bus_signals_test (const DBusString *test_data_dir) 2277 { 2278 BusMatchmaker *matchmaker; 2279 2280 matchmaker = bus_matchmaker_new (); 2281 bus_matchmaker_ref (matchmaker); 2282 bus_matchmaker_unref (matchmaker); 2283 bus_matchmaker_unref (matchmaker); 2284 2285 if (!_dbus_test_oom_handling ("parsing match rules", test_parsing, NULL)) 2286 _dbus_assert_not_reached ("Parsing match rules test failed"); 2287 2288 test_equality (); 2289 2290 test_matching (); 2291 2292 return TRUE; 2293 } 2294 2295 #endif /* DBUS_BUILD_TESTS */ 2296 2297