1 /* -*- mode: C; c-file-style: "gnu" -*- */ 2 /* config-parser.c XML-library-agnostic configuration file parser 3 * 4 * Copyright (C) 2003, 2004 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * 22 */ 23 #include "config-parser.h" 24 #include "test.h" 25 #include "utils.h" 26 #include "policy.h" 27 #include "selinux.h" 28 #include <dbus/dbus-list.h> 29 #include <dbus/dbus-internals.h> 30 #include <string.h> 31 32 typedef enum 33 { 34 ELEMENT_NONE, 35 ELEMENT_BUSCONFIG, 36 ELEMENT_INCLUDE, 37 ELEMENT_USER, 38 ELEMENT_LISTEN, 39 ELEMENT_AUTH, 40 ELEMENT_POLICY, 41 ELEMENT_LIMIT, 42 ELEMENT_ALLOW, 43 ELEMENT_DENY, 44 ELEMENT_FORK, 45 ELEMENT_PIDFILE, 46 ELEMENT_SERVICEDIR, 47 ELEMENT_INCLUDEDIR, 48 ELEMENT_TYPE, 49 ELEMENT_SELINUX, 50 ELEMENT_ASSOCIATE, 51 ELEMENT_STANDARD_SESSION_SERVICEDIRS 52 } ElementType; 53 54 typedef enum 55 { 56 /* we ignore policies for unknown groups/users */ 57 POLICY_IGNORED, 58 59 /* non-ignored */ 60 POLICY_DEFAULT, 61 POLICY_MANDATORY, 62 POLICY_USER, 63 POLICY_GROUP, 64 POLICY_CONSOLE 65 } PolicyType; 66 67 typedef struct 68 { 69 ElementType type; 70 71 unsigned int had_content : 1; 72 73 union 74 { 75 struct 76 { 77 unsigned int ignore_missing : 1; 78 unsigned int if_selinux_enabled : 1; 79 unsigned int selinux_root_relative : 1; 80 } include; 81 82 struct 83 { 84 PolicyType type; 85 unsigned long gid_uid_or_at_console; 86 } policy; 87 88 struct 89 { 90 char *name; 91 long value; 92 } limit; 93 94 } d; 95 96 } Element; 97 98 /** 99 * Parser for bus configuration file. 100 */ 101 struct BusConfigParser 102 { 103 int refcount; /**< Reference count */ 104 105 DBusString basedir; /**< Directory we resolve paths relative to */ 106 107 DBusList *stack; /**< stack of Element */ 108 109 char *user; /**< user to run as */ 110 111 char *bus_type; /**< Message bus type */ 112 113 DBusList *listen_on; /**< List of addresses to listen to */ 114 115 DBusList *mechanisms; /**< Auth mechanisms */ 116 117 DBusList *service_dirs; /**< Directories to look for services in */ 118 119 DBusList *conf_dirs; /**< Directories to look for policy configuration in */ 120 121 BusPolicy *policy; /**< Security policy */ 122 123 BusLimits limits; /**< Limits */ 124 125 char *pidfile; /**< PID file */ 126 127 DBusList *included_files; /**< Included files stack */ 128 129 DBusHashTable *service_context_table; /**< Map service names to SELinux contexts */ 130 131 unsigned int fork : 1; /**< TRUE to fork into daemon mode */ 132 133 unsigned int is_toplevel : 1; /**< FALSE if we are a sub-config-file inside another one */ 134 }; 135 136 static const char* 137 element_type_to_name (ElementType type) 138 { 139 switch (type) 140 { 141 case ELEMENT_NONE: 142 return NULL; 143 case ELEMENT_BUSCONFIG: 144 return "busconfig"; 145 case ELEMENT_INCLUDE: 146 return "include"; 147 case ELEMENT_USER: 148 return "user"; 149 case ELEMENT_LISTEN: 150 return "listen"; 151 case ELEMENT_AUTH: 152 return "auth"; 153 case ELEMENT_POLICY: 154 return "policy"; 155 case ELEMENT_LIMIT: 156 return "limit"; 157 case ELEMENT_ALLOW: 158 return "allow"; 159 case ELEMENT_DENY: 160 return "deny"; 161 case ELEMENT_FORK: 162 return "fork"; 163 case ELEMENT_PIDFILE: 164 return "pidfile"; 165 case ELEMENT_STANDARD_SESSION_SERVICEDIRS: 166 return "standard_session_servicedirs"; 167 case ELEMENT_SERVICEDIR: 168 return "servicedir"; 169 case ELEMENT_INCLUDEDIR: 170 return "includedir"; 171 case ELEMENT_TYPE: 172 return "type"; 173 case ELEMENT_SELINUX: 174 return "selinux"; 175 case ELEMENT_ASSOCIATE: 176 return "associate"; 177 } 178 179 _dbus_assert_not_reached ("bad element type"); 180 181 return NULL; 182 } 183 184 static Element* 185 push_element (BusConfigParser *parser, 186 ElementType type) 187 { 188 Element *e; 189 190 _dbus_assert (type != ELEMENT_NONE); 191 192 e = dbus_new0 (Element, 1); 193 if (e == NULL) 194 return NULL; 195 196 if (!_dbus_list_append (&parser->stack, e)) 197 { 198 dbus_free (e); 199 return NULL; 200 } 201 202 e->type = type; 203 204 return e; 205 } 206 207 static void 208 element_free (Element *e) 209 { 210 if (e->type == ELEMENT_LIMIT) 211 dbus_free (e->d.limit.name); 212 213 dbus_free (e); 214 } 215 216 static void 217 pop_element (BusConfigParser *parser) 218 { 219 Element *e; 220 221 e = _dbus_list_pop_last (&parser->stack); 222 223 element_free (e); 224 } 225 226 static Element* 227 peek_element (BusConfigParser *parser) 228 { 229 Element *e; 230 231 e = _dbus_list_get_last (&parser->stack); 232 233 return e; 234 } 235 236 static ElementType 237 top_element_type (BusConfigParser *parser) 238 { 239 Element *e; 240 241 e = _dbus_list_get_last (&parser->stack); 242 243 if (e) 244 return e->type; 245 else 246 return ELEMENT_NONE; 247 } 248 249 static dbus_bool_t 250 merge_service_context_hash (DBusHashTable *dest, 251 DBusHashTable *from) 252 { 253 DBusHashIter iter; 254 char *service_copy; 255 char *context_copy; 256 257 service_copy = NULL; 258 context_copy = NULL; 259 260 _dbus_hash_iter_init (from, &iter); 261 while (_dbus_hash_iter_next (&iter)) 262 { 263 const char *service = _dbus_hash_iter_get_string_key (&iter); 264 const char *context = _dbus_hash_iter_get_value (&iter); 265 266 service_copy = _dbus_strdup (service); 267 if (service_copy == NULL) 268 goto fail; 269 context_copy = _dbus_strdup (context); 270 if (context_copy == NULL) 271 goto fail; 272 273 if (!_dbus_hash_table_insert_string (dest, service_copy, context_copy)) 274 goto fail; 275 276 service_copy = NULL; 277 context_copy = NULL; 278 } 279 280 return TRUE; 281 282 fail: 283 if (service_copy) 284 dbus_free (service_copy); 285 286 if (context_copy) 287 dbus_free (context_copy); 288 289 return FALSE; 290 } 291 292 static dbus_bool_t 293 service_dirs_find_dir (DBusList **service_dirs, 294 const char *dir) 295 { 296 DBusList *link; 297 298 _dbus_assert (dir != NULL); 299 300 for (link = *service_dirs; link; link = _dbus_list_get_next_link(service_dirs, link)) 301 { 302 const char *link_dir; 303 304 link_dir = (const char *)link->data; 305 if (strcmp (dir, link_dir) == 0) 306 return TRUE; 307 } 308 309 return FALSE; 310 } 311 312 static dbus_bool_t 313 service_dirs_append_unique_or_free (DBusList **service_dirs, 314 char *dir) 315 { 316 if (!service_dirs_find_dir (service_dirs, dir)) 317 return _dbus_list_append (service_dirs, dir); 318 319 dbus_free (dir); 320 return TRUE; 321 } 322 323 static void 324 service_dirs_append_link_unique_or_free (DBusList **service_dirs, 325 DBusList *dir_link) 326 { 327 if (!service_dirs_find_dir (service_dirs, dir_link->data)) 328 { 329 _dbus_list_append_link (service_dirs, dir_link); 330 } 331 else 332 { 333 dbus_free (dir_link->data); 334 _dbus_list_free_link (dir_link); 335 } 336 } 337 338 static dbus_bool_t 339 merge_included (BusConfigParser *parser, 340 BusConfigParser *included, 341 DBusError *error) 342 { 343 DBusList *link; 344 345 if (!bus_policy_merge (parser->policy, 346 included->policy)) 347 { 348 BUS_SET_OOM (error); 349 return FALSE; 350 } 351 352 if (!merge_service_context_hash (parser->service_context_table, 353 included->service_context_table)) 354 { 355 BUS_SET_OOM (error); 356 return FALSE; 357 } 358 359 if (included->user != NULL) 360 { 361 dbus_free (parser->user); 362 parser->user = included->user; 363 included->user = NULL; 364 } 365 366 if (included->bus_type != NULL) 367 { 368 dbus_free (parser->bus_type); 369 parser->bus_type = included->bus_type; 370 included->bus_type = NULL; 371 } 372 373 if (included->fork) 374 parser->fork = TRUE; 375 376 if (included->pidfile != NULL) 377 { 378 dbus_free (parser->pidfile); 379 parser->pidfile = included->pidfile; 380 included->pidfile = NULL; 381 } 382 383 while ((link = _dbus_list_pop_first_link (&included->listen_on))) 384 _dbus_list_append_link (&parser->listen_on, link); 385 386 while ((link = _dbus_list_pop_first_link (&included->mechanisms))) 387 _dbus_list_append_link (&parser->mechanisms, link); 388 389 while ((link = _dbus_list_pop_first_link (&included->service_dirs))) 390 service_dirs_append_link_unique_or_free (&parser->service_dirs, link); 391 392 while ((link = _dbus_list_pop_first_link (&included->conf_dirs))) 393 _dbus_list_append_link (&parser->conf_dirs, link); 394 395 return TRUE; 396 } 397 398 static dbus_bool_t 399 seen_include (BusConfigParser *parser, 400 const DBusString *file) 401 { 402 DBusList *iter; 403 404 iter = parser->included_files; 405 while (iter != NULL) 406 { 407 if (! strcmp (_dbus_string_get_const_data (file), iter->data)) 408 return TRUE; 409 410 iter = _dbus_list_get_next_link (&parser->included_files, iter); 411 } 412 413 return FALSE; 414 } 415 416 BusConfigParser* 417 bus_config_parser_new (const DBusString *basedir, 418 dbus_bool_t is_toplevel, 419 const BusConfigParser *parent) 420 { 421 BusConfigParser *parser; 422 423 parser = dbus_new0 (BusConfigParser, 1); 424 if (parser == NULL) 425 return NULL; 426 427 parser->is_toplevel = !!is_toplevel; 428 429 if (!_dbus_string_init (&parser->basedir)) 430 { 431 dbus_free (parser); 432 return NULL; 433 } 434 435 if (((parser->policy = bus_policy_new ()) == NULL) || 436 !_dbus_string_copy (basedir, 0, &parser->basedir, 0) || 437 ((parser->service_context_table = _dbus_hash_table_new (DBUS_HASH_STRING, 438 dbus_free, 439 dbus_free)) == NULL)) 440 { 441 if (parser->policy) 442 bus_policy_unref (parser->policy); 443 444 _dbus_string_free (&parser->basedir); 445 446 dbus_free (parser); 447 return NULL; 448 } 449 450 if (parent != NULL) 451 { 452 /* Initialize the parser's limits from the parent. */ 453 parser->limits = parent->limits; 454 455 /* Use the parent's list of included_files to avoid 456 circular inclusions. */ 457 parser->included_files = parent->included_files; 458 } 459 else 460 { 461 462 /* Make up some numbers! woot! */ 463 parser->limits.max_incoming_bytes = _DBUS_ONE_MEGABYTE * 63; 464 parser->limits.max_outgoing_bytes = _DBUS_ONE_MEGABYTE * 63; 465 parser->limits.max_message_size = _DBUS_ONE_MEGABYTE * 32; 466 467 /* Making this long means the user has to wait longer for an error 468 * message if something screws up, but making it too short means 469 * they might see a false failure. 470 */ 471 parser->limits.activation_timeout = 25000; /* 25 seconds */ 472 473 /* Making this long risks making a DOS attack easier, but too short 474 * and legitimate auth will fail. If interactive auth (ask user for 475 * password) is allowed, then potentially it has to be quite long. 476 */ 477 parser->limits.auth_timeout = 30000; /* 30 seconds */ 478 479 parser->limits.max_incomplete_connections = 32; 480 parser->limits.max_connections_per_user = 128; 481 482 /* Note that max_completed_connections / max_connections_per_user 483 * is the number of users that would have to work together to 484 * DOS all the other users. 485 */ 486 parser->limits.max_completed_connections = 1024; 487 488 parser->limits.max_pending_activations = 256; 489 parser->limits.max_services_per_connection = 256; 490 491 parser->limits.max_match_rules_per_connection = 512; 492 493 parser->limits.reply_timeout = 5 * 60 * 1000; /* 5 minutes */ 494 parser->limits.max_replies_per_connection = 32; 495 } 496 497 parser->refcount = 1; 498 499 return parser; 500 } 501 502 BusConfigParser * 503 bus_config_parser_ref (BusConfigParser *parser) 504 { 505 _dbus_assert (parser->refcount > 0); 506 507 parser->refcount += 1; 508 509 return parser; 510 } 511 512 void 513 bus_config_parser_unref (BusConfigParser *parser) 514 { 515 _dbus_assert (parser->refcount > 0); 516 517 parser->refcount -= 1; 518 519 if (parser->refcount == 0) 520 { 521 while (parser->stack != NULL) 522 pop_element (parser); 523 524 dbus_free (parser->user); 525 dbus_free (parser->bus_type); 526 dbus_free (parser->pidfile); 527 528 _dbus_list_foreach (&parser->listen_on, 529 (DBusForeachFunction) dbus_free, 530 NULL); 531 532 _dbus_list_clear (&parser->listen_on); 533 534 _dbus_list_foreach (&parser->service_dirs, 535 (DBusForeachFunction) dbus_free, 536 NULL); 537 538 _dbus_list_clear (&parser->service_dirs); 539 540 _dbus_list_foreach (&parser->conf_dirs, 541 (DBusForeachFunction) dbus_free, 542 NULL); 543 544 _dbus_list_clear (&parser->conf_dirs); 545 546 _dbus_list_foreach (&parser->mechanisms, 547 (DBusForeachFunction) dbus_free, 548 NULL); 549 550 _dbus_list_clear (&parser->mechanisms); 551 552 _dbus_string_free (&parser->basedir); 553 554 if (parser->policy) 555 bus_policy_unref (parser->policy); 556 557 if (parser->service_context_table) 558 _dbus_hash_table_unref (parser->service_context_table); 559 560 dbus_free (parser); 561 } 562 } 563 564 dbus_bool_t 565 bus_config_parser_check_doctype (BusConfigParser *parser, 566 const char *doctype, 567 DBusError *error) 568 { 569 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 570 571 if (strcmp (doctype, "busconfig") != 0) 572 { 573 dbus_set_error (error, 574 DBUS_ERROR_FAILED, 575 "Configuration file has the wrong document type %s", 576 doctype); 577 return FALSE; 578 } 579 else 580 return TRUE; 581 } 582 583 typedef struct 584 { 585 const char *name; 586 const char **retloc; 587 } LocateAttr; 588 589 static dbus_bool_t 590 locate_attributes (BusConfigParser *parser, 591 const char *element_name, 592 const char **attribute_names, 593 const char **attribute_values, 594 DBusError *error, 595 const char *first_attribute_name, 596 const char **first_attribute_retloc, 597 ...) 598 { 599 va_list args; 600 const char *name; 601 const char **retloc; 602 int n_attrs; 603 #define MAX_ATTRS 24 604 LocateAttr attrs[MAX_ATTRS]; 605 dbus_bool_t retval; 606 int i; 607 608 _dbus_assert (first_attribute_name != NULL); 609 _dbus_assert (first_attribute_retloc != NULL); 610 611 retval = TRUE; 612 613 n_attrs = 1; 614 attrs[0].name = first_attribute_name; 615 attrs[0].retloc = first_attribute_retloc; 616 *first_attribute_retloc = NULL; 617 618 va_start (args, first_attribute_retloc); 619 620 name = va_arg (args, const char*); 621 retloc = va_arg (args, const char**); 622 623 while (name != NULL) 624 { 625 _dbus_assert (retloc != NULL); 626 _dbus_assert (n_attrs < MAX_ATTRS); 627 628 attrs[n_attrs].name = name; 629 attrs[n_attrs].retloc = retloc; 630 n_attrs += 1; 631 *retloc = NULL; 632 633 name = va_arg (args, const char*); 634 retloc = va_arg (args, const char**); 635 } 636 637 va_end (args); 638 639 if (!retval) 640 return retval; 641 642 i = 0; 643 while (attribute_names[i]) 644 { 645 int j; 646 dbus_bool_t found; 647 648 found = FALSE; 649 j = 0; 650 while (j < n_attrs) 651 { 652 if (strcmp (attrs[j].name, attribute_names[i]) == 0) 653 { 654 retloc = attrs[j].retloc; 655 656 if (*retloc != NULL) 657 { 658 dbus_set_error (error, DBUS_ERROR_FAILED, 659 "Attribute \"%s\" repeated twice on the same <%s> element", 660 attrs[j].name, element_name); 661 retval = FALSE; 662 goto out; 663 } 664 665 *retloc = attribute_values[i]; 666 found = TRUE; 667 } 668 669 ++j; 670 } 671 672 if (!found) 673 { 674 dbus_set_error (error, DBUS_ERROR_FAILED, 675 "Attribute \"%s\" is invalid on <%s> element in this context", 676 attribute_names[i], element_name); 677 retval = FALSE; 678 goto out; 679 } 680 681 ++i; 682 } 683 684 out: 685 return retval; 686 } 687 688 static dbus_bool_t 689 check_no_attributes (BusConfigParser *parser, 690 const char *element_name, 691 const char **attribute_names, 692 const char **attribute_values, 693 DBusError *error) 694 { 695 if (attribute_names[0] != NULL) 696 { 697 dbus_set_error (error, DBUS_ERROR_FAILED, 698 "Attribute \"%s\" is invalid on <%s> element in this context", 699 attribute_names[0], element_name); 700 return FALSE; 701 } 702 703 return TRUE; 704 } 705 706 static dbus_bool_t 707 start_busconfig_child (BusConfigParser *parser, 708 const char *element_name, 709 const char **attribute_names, 710 const char **attribute_values, 711 DBusError *error) 712 { 713 if (strcmp (element_name, "user") == 0) 714 { 715 if (!check_no_attributes (parser, "user", attribute_names, attribute_values, error)) 716 return FALSE; 717 718 if (push_element (parser, ELEMENT_USER) == NULL) 719 { 720 BUS_SET_OOM (error); 721 return FALSE; 722 } 723 724 return TRUE; 725 } 726 else if (strcmp (element_name, "type") == 0) 727 { 728 if (!check_no_attributes (parser, "type", attribute_names, attribute_values, error)) 729 return FALSE; 730 731 if (push_element (parser, ELEMENT_TYPE) == NULL) 732 { 733 BUS_SET_OOM (error); 734 return FALSE; 735 } 736 737 return TRUE; 738 } 739 else if (strcmp (element_name, "fork") == 0) 740 { 741 if (!check_no_attributes (parser, "fork", attribute_names, attribute_values, error)) 742 return FALSE; 743 744 if (push_element (parser, ELEMENT_FORK) == NULL) 745 { 746 BUS_SET_OOM (error); 747 return FALSE; 748 } 749 750 parser->fork = TRUE; 751 752 return TRUE; 753 } 754 else if (strcmp (element_name, "pidfile") == 0) 755 { 756 if (!check_no_attributes (parser, "pidfile", attribute_names, attribute_values, error)) 757 return FALSE; 758 759 if (push_element (parser, ELEMENT_PIDFILE) == NULL) 760 { 761 BUS_SET_OOM (error); 762 return FALSE; 763 } 764 765 return TRUE; 766 } 767 else if (strcmp (element_name, "listen") == 0) 768 { 769 if (!check_no_attributes (parser, "listen", attribute_names, attribute_values, error)) 770 return FALSE; 771 772 if (push_element (parser, ELEMENT_LISTEN) == NULL) 773 { 774 BUS_SET_OOM (error); 775 return FALSE; 776 } 777 778 return TRUE; 779 } 780 else if (strcmp (element_name, "auth") == 0) 781 { 782 if (!check_no_attributes (parser, "auth", attribute_names, attribute_values, error)) 783 return FALSE; 784 785 if (push_element (parser, ELEMENT_AUTH) == NULL) 786 { 787 BUS_SET_OOM (error); 788 return FALSE; 789 } 790 791 return TRUE; 792 } 793 else if (strcmp (element_name, "includedir") == 0) 794 { 795 if (!check_no_attributes (parser, "includedir", attribute_names, attribute_values, error)) 796 return FALSE; 797 798 if (push_element (parser, ELEMENT_INCLUDEDIR) == NULL) 799 { 800 BUS_SET_OOM (error); 801 return FALSE; 802 } 803 804 return TRUE; 805 } 806 else if (strcmp (element_name, "standard_session_servicedirs") == 0) 807 { 808 DBusList *link; 809 DBusList *dirs; 810 dirs = NULL; 811 812 if (!check_no_attributes (parser, "standard_session_servicedirs", attribute_names, attribute_values, error)) 813 return FALSE; 814 815 if (push_element (parser, ELEMENT_STANDARD_SESSION_SERVICEDIRS) == NULL) 816 { 817 BUS_SET_OOM (error); 818 return FALSE; 819 } 820 821 if (!_dbus_get_standard_session_servicedirs (&dirs)) 822 { 823 BUS_SET_OOM (error); 824 return FALSE; 825 } 826 827 while ((link = _dbus_list_pop_first_link (&dirs))) 828 service_dirs_append_link_unique_or_free (&parser->service_dirs, link); 829 830 return TRUE; 831 } 832 else if (strcmp (element_name, "servicedir") == 0) 833 { 834 if (!check_no_attributes (parser, "servicedir", attribute_names, attribute_values, error)) 835 return FALSE; 836 837 if (push_element (parser, ELEMENT_SERVICEDIR) == NULL) 838 { 839 BUS_SET_OOM (error); 840 return FALSE; 841 } 842 843 return TRUE; 844 } 845 else if (strcmp (element_name, "include") == 0) 846 { 847 Element *e; 848 const char *if_selinux_enabled; 849 const char *ignore_missing; 850 const char *selinux_root_relative; 851 852 if ((e = push_element (parser, ELEMENT_INCLUDE)) == NULL) 853 { 854 BUS_SET_OOM (error); 855 return FALSE; 856 } 857 858 e->d.include.ignore_missing = FALSE; 859 e->d.include.if_selinux_enabled = FALSE; 860 e->d.include.selinux_root_relative = FALSE; 861 862 if (!locate_attributes (parser, "include", 863 attribute_names, 864 attribute_values, 865 error, 866 "ignore_missing", &ignore_missing, 867 "if_selinux_enabled", &if_selinux_enabled, 868 "selinux_root_relative", &selinux_root_relative, 869 NULL)) 870 return FALSE; 871 872 if (ignore_missing != NULL) 873 { 874 if (strcmp (ignore_missing, "yes") == 0) 875 e->d.include.ignore_missing = TRUE; 876 else if (strcmp (ignore_missing, "no") == 0) 877 e->d.include.ignore_missing = FALSE; 878 else 879 { 880 dbus_set_error (error, DBUS_ERROR_FAILED, 881 "ignore_missing attribute must have value \"yes\" or \"no\""); 882 return FALSE; 883 } 884 } 885 886 if (if_selinux_enabled != NULL) 887 { 888 if (strcmp (if_selinux_enabled, "yes") == 0) 889 e->d.include.if_selinux_enabled = TRUE; 890 else if (strcmp (if_selinux_enabled, "no") == 0) 891 e->d.include.if_selinux_enabled = FALSE; 892 else 893 { 894 dbus_set_error (error, DBUS_ERROR_FAILED, 895 "if_selinux_enabled attribute must have value" 896 " \"yes\" or \"no\""); 897 return FALSE; 898 } 899 } 900 901 if (selinux_root_relative != NULL) 902 { 903 if (strcmp (selinux_root_relative, "yes") == 0) 904 e->d.include.selinux_root_relative = TRUE; 905 else if (strcmp (selinux_root_relative, "no") == 0) 906 e->d.include.selinux_root_relative = FALSE; 907 else 908 { 909 dbus_set_error (error, DBUS_ERROR_FAILED, 910 "selinux_root_relative attribute must have value" 911 " \"yes\" or \"no\""); 912 return FALSE; 913 } 914 } 915 916 return TRUE; 917 } 918 else if (strcmp (element_name, "policy") == 0) 919 { 920 Element *e; 921 const char *context; 922 const char *user; 923 const char *group; 924 const char *at_console; 925 926 if ((e = push_element (parser, ELEMENT_POLICY)) == NULL) 927 { 928 BUS_SET_OOM (error); 929 return FALSE; 930 } 931 932 e->d.policy.type = POLICY_IGNORED; 933 934 if (!locate_attributes (parser, "policy", 935 attribute_names, 936 attribute_values, 937 error, 938 "context", &context, 939 "user", &user, 940 "group", &group, 941 "at_console", &at_console, 942 NULL)) 943 return FALSE; 944 945 if (((context && user) || 946 (context && group) || 947 (context && at_console)) || 948 ((user && group) || 949 (user && at_console)) || 950 (group && at_console) || 951 !(context || user || group || at_console)) 952 { 953 dbus_set_error (error, DBUS_ERROR_FAILED, 954 "<policy> element must have exactly one of (context|user|group|at_console) attributes"); 955 return FALSE; 956 } 957 958 if (context != NULL) 959 { 960 if (strcmp (context, "default") == 0) 961 { 962 e->d.policy.type = POLICY_DEFAULT; 963 } 964 else if (strcmp (context, "mandatory") == 0) 965 { 966 e->d.policy.type = POLICY_MANDATORY; 967 } 968 else 969 { 970 dbus_set_error (error, DBUS_ERROR_FAILED, 971 "context attribute on <policy> must have the value \"default\" or \"mandatory\", not \"%s\"", 972 context); 973 return FALSE; 974 } 975 } 976 else if (user != NULL) 977 { 978 DBusString username; 979 _dbus_string_init_const (&username, user); 980 981 if (_dbus_get_user_id (&username, 982 &e->d.policy.gid_uid_or_at_console)) 983 e->d.policy.type = POLICY_USER; 984 else 985 _dbus_warn ("Unknown username \"%s\" in message bus configuration file\n", 986 user); 987 } 988 else if (group != NULL) 989 { 990 DBusString group_name; 991 _dbus_string_init_const (&group_name, group); 992 993 if (_dbus_get_group_id (&group_name, 994 &e->d.policy.gid_uid_or_at_console)) 995 e->d.policy.type = POLICY_GROUP; 996 else 997 _dbus_warn ("Unknown group \"%s\" in message bus configuration file\n", 998 group); 999 } 1000 else if (at_console != NULL) 1001 { 1002 dbus_bool_t t; 1003 t = (strcmp (at_console, "true") == 0); 1004 if (t || strcmp (at_console, "false") == 0) 1005 { 1006 e->d.policy.gid_uid_or_at_console = t; 1007 e->d.policy.type = POLICY_CONSOLE; 1008 } 1009 else 1010 { 1011 dbus_set_error (error, DBUS_ERROR_FAILED, 1012 "Unknown value \"%s\" for at_console in message bus configuration file", 1013 at_console); 1014 1015 return FALSE; 1016 } 1017 } 1018 else 1019 { 1020 _dbus_assert_not_reached ("all <policy> attributes null and we didn't set error"); 1021 } 1022 1023 return TRUE; 1024 } 1025 else if (strcmp (element_name, "limit") == 0) 1026 { 1027 Element *e; 1028 const char *name; 1029 1030 if ((e = push_element (parser, ELEMENT_LIMIT)) == NULL) 1031 { 1032 BUS_SET_OOM (error); 1033 return FALSE; 1034 } 1035 1036 if (!locate_attributes (parser, "limit", 1037 attribute_names, 1038 attribute_values, 1039 error, 1040 "name", &name, 1041 NULL)) 1042 return FALSE; 1043 1044 if (name == NULL) 1045 { 1046 dbus_set_error (error, DBUS_ERROR_FAILED, 1047 "<limit> element must have a \"name\" attribute"); 1048 return FALSE; 1049 } 1050 1051 e->d.limit.name = _dbus_strdup (name); 1052 if (e->d.limit.name == NULL) 1053 { 1054 BUS_SET_OOM (error); 1055 return FALSE; 1056 } 1057 1058 return TRUE; 1059 } 1060 else if (strcmp (element_name, "selinux") == 0) 1061 { 1062 if (!check_no_attributes (parser, "selinux", attribute_names, attribute_values, error)) 1063 return FALSE; 1064 1065 if (push_element (parser, ELEMENT_SELINUX) == NULL) 1066 { 1067 BUS_SET_OOM (error); 1068 return FALSE; 1069 } 1070 1071 return TRUE; 1072 } 1073 else 1074 { 1075 dbus_set_error (error, DBUS_ERROR_FAILED, 1076 "Element <%s> not allowed inside <%s> in configuration file", 1077 element_name, "busconfig"); 1078 return FALSE; 1079 } 1080 } 1081 1082 static dbus_bool_t 1083 append_rule_from_element (BusConfigParser *parser, 1084 const char *element_name, 1085 const char **attribute_names, 1086 const char **attribute_values, 1087 dbus_bool_t allow, 1088 DBusError *error) 1089 { 1090 const char *send_interface; 1091 const char *send_member; 1092 const char *send_error; 1093 const char *send_destination; 1094 const char *send_path; 1095 const char *send_type; 1096 const char *receive_interface; 1097 const char *receive_member; 1098 const char *receive_error; 1099 const char *receive_sender; 1100 const char *receive_path; 1101 const char *receive_type; 1102 const char *eavesdrop; 1103 const char *send_requested_reply; 1104 const char *receive_requested_reply; 1105 const char *own; 1106 const char *user; 1107 const char *group; 1108 1109 BusPolicyRule *rule; 1110 1111 if (!locate_attributes (parser, element_name, 1112 attribute_names, 1113 attribute_values, 1114 error, 1115 "send_interface", &send_interface, 1116 "send_member", &send_member, 1117 "send_error", &send_error, 1118 "send_destination", &send_destination, 1119 "send_path", &send_path, 1120 "send_type", &send_type, 1121 "receive_interface", &receive_interface, 1122 "receive_member", &receive_member, 1123 "receive_error", &receive_error, 1124 "receive_sender", &receive_sender, 1125 "receive_path", &receive_path, 1126 "receive_type", &receive_type, 1127 "eavesdrop", &eavesdrop, 1128 "send_requested_reply", &send_requested_reply, 1129 "receive_requested_reply", &receive_requested_reply, 1130 "own", &own, 1131 "user", &user, 1132 "group", &group, 1133 NULL)) 1134 return FALSE; 1135 1136 if (!(send_interface || send_member || send_error || send_destination || 1137 send_type || send_path || 1138 receive_interface || receive_member || receive_error || receive_sender || 1139 receive_type || receive_path || eavesdrop || 1140 send_requested_reply || receive_requested_reply || 1141 own || user || group)) 1142 { 1143 dbus_set_error (error, DBUS_ERROR_FAILED, 1144 "Element <%s> must have one or more attributes", 1145 element_name); 1146 return FALSE; 1147 } 1148 1149 if ((send_member && (send_interface == NULL && send_path == NULL)) || 1150 (receive_member && (receive_interface == NULL && receive_path == NULL))) 1151 { 1152 dbus_set_error (error, DBUS_ERROR_FAILED, 1153 "On element <%s>, if you specify a member you must specify an interface or a path. Keep in mind that not all messages have an interface field.", 1154 element_name); 1155 return FALSE; 1156 } 1157 1158 /* Allowed combinations of elements are: 1159 * 1160 * base, must be all send or all receive: 1161 * nothing 1162 * interface 1163 * interface + member 1164 * error 1165 * 1166 * base send_ can combine with send_destination, send_path, send_type, send_requested_reply 1167 * base receive_ with receive_sender, receive_path, receive_type, receive_requested_reply, eavesdrop 1168 * 1169 * user, group, own must occur alone 1170 * 1171 * Pretty sure the below stuff is broken, FIXME think about it more. 1172 */ 1173 1174 if (((send_interface && send_error) || 1175 (send_interface && receive_interface) || 1176 (send_interface && receive_member) || 1177 (send_interface && receive_error) || 1178 (send_interface && receive_sender) || 1179 (send_interface && eavesdrop) || 1180 (send_interface && receive_requested_reply) || 1181 (send_interface && own) || 1182 (send_interface && user) || 1183 (send_interface && group)) || 1184 1185 ((send_member && send_error) || 1186 (send_member && receive_interface) || 1187 (send_member && receive_member) || 1188 (send_member && receive_error) || 1189 (send_member && receive_sender) || 1190 (send_member && eavesdrop) || 1191 (send_member && receive_requested_reply) || 1192 (send_member && own) || 1193 (send_member && user) || 1194 (send_member && group)) || 1195 1196 ((send_error && receive_interface) || 1197 (send_error && receive_member) || 1198 (send_error && receive_error) || 1199 (send_error && receive_sender) || 1200 (send_error && eavesdrop) || 1201 (send_error && receive_requested_reply) || 1202 (send_error && own) || 1203 (send_error && user) || 1204 (send_error && group)) || 1205 1206 ((send_destination && receive_interface) || 1207 (send_destination && receive_member) || 1208 (send_destination && receive_error) || 1209 (send_destination && receive_sender) || 1210 (send_destination && eavesdrop) || 1211 (send_destination && receive_requested_reply) || 1212 (send_destination && own) || 1213 (send_destination && user) || 1214 (send_destination && group)) || 1215 1216 ((send_type && receive_interface) || 1217 (send_type && receive_member) || 1218 (send_type && receive_error) || 1219 (send_type && receive_sender) || 1220 (send_type && eavesdrop) || 1221 (send_type && receive_requested_reply) || 1222 (send_type && own) || 1223 (send_type && user) || 1224 (send_type && group)) || 1225 1226 ((send_path && receive_interface) || 1227 (send_path && receive_member) || 1228 (send_path && receive_error) || 1229 (send_path && receive_sender) || 1230 (send_path && eavesdrop) || 1231 (send_path && receive_requested_reply) || 1232 (send_path && own) || 1233 (send_path && user) || 1234 (send_path && group)) || 1235 1236 ((send_requested_reply && receive_interface) || 1237 (send_requested_reply && receive_member) || 1238 (send_requested_reply && receive_error) || 1239 (send_requested_reply && receive_sender) || 1240 (send_requested_reply && eavesdrop) || 1241 (send_requested_reply && receive_requested_reply) || 1242 (send_requested_reply && own) || 1243 (send_requested_reply && user) || 1244 (send_requested_reply && group)) || 1245 1246 ((receive_interface && receive_error) || 1247 (receive_interface && own) || 1248 (receive_interface && user) || 1249 (receive_interface && group)) || 1250 1251 ((receive_member && receive_error) || 1252 (receive_member && own) || 1253 (receive_member && user) || 1254 (receive_member && group)) || 1255 1256 ((receive_error && own) || 1257 (receive_error && user) || 1258 (receive_error && group)) || 1259 1260 ((eavesdrop && own) || 1261 (eavesdrop && user) || 1262 (eavesdrop && group)) || 1263 1264 ((receive_requested_reply && own) || 1265 (receive_requested_reply && user) || 1266 (receive_requested_reply && group)) || 1267 1268 ((own && user) || 1269 (own && group)) || 1270 1271 ((user && group))) 1272 { 1273 dbus_set_error (error, DBUS_ERROR_FAILED, 1274 "Invalid combination of attributes on element <%s>", 1275 element_name); 1276 return FALSE; 1277 } 1278 1279 rule = NULL; 1280 1281 /* In BusPolicyRule, NULL represents wildcard. 1282 * In the config file, '*' represents it. 1283 */ 1284 #define IS_WILDCARD(str) ((str) && ((str)[0]) == '*' && ((str)[1]) == '\0') 1285 1286 if (send_interface || send_member || send_error || send_destination || 1287 send_path || send_type || send_requested_reply) 1288 { 1289 int message_type; 1290 1291 if (IS_WILDCARD (send_interface)) 1292 send_interface = NULL; 1293 if (IS_WILDCARD (send_member)) 1294 send_member = NULL; 1295 if (IS_WILDCARD (send_error)) 1296 send_error = NULL; 1297 if (IS_WILDCARD (send_destination)) 1298 send_destination = NULL; 1299 if (IS_WILDCARD (send_path)) 1300 send_path = NULL; 1301 if (IS_WILDCARD (send_type)) 1302 send_type = NULL; 1303 1304 message_type = DBUS_MESSAGE_TYPE_INVALID; 1305 if (send_type != NULL) 1306 { 1307 message_type = dbus_message_type_from_string (send_type); 1308 if (message_type == DBUS_MESSAGE_TYPE_INVALID) 1309 { 1310 dbus_set_error (error, DBUS_ERROR_FAILED, 1311 "Bad message type \"%s\"", 1312 send_type); 1313 return FALSE; 1314 } 1315 } 1316 1317 if (send_requested_reply && 1318 !(strcmp (send_requested_reply, "true") == 0 || 1319 strcmp (send_requested_reply, "false") == 0)) 1320 { 1321 dbus_set_error (error, DBUS_ERROR_FAILED, 1322 "Bad value \"%s\" for %s attribute, must be true or false", 1323 "send_requested_reply", send_requested_reply); 1324 return FALSE; 1325 } 1326 1327 rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow); 1328 if (rule == NULL) 1329 goto nomem; 1330 1331 if (send_requested_reply) 1332 rule->d.send.requested_reply = (strcmp (send_requested_reply, "true") == 0); 1333 1334 rule->d.send.message_type = message_type; 1335 rule->d.send.path = _dbus_strdup (send_path); 1336 rule->d.send.interface = _dbus_strdup (send_interface); 1337 rule->d.send.member = _dbus_strdup (send_member); 1338 rule->d.send.error = _dbus_strdup (send_error); 1339 rule->d.send.destination = _dbus_strdup (send_destination); 1340 if (send_path && rule->d.send.path == NULL) 1341 goto nomem; 1342 if (send_interface && rule->d.send.interface == NULL) 1343 goto nomem; 1344 if (send_member && rule->d.send.member == NULL) 1345 goto nomem; 1346 if (send_error && rule->d.send.error == NULL) 1347 goto nomem; 1348 if (send_destination && rule->d.send.destination == NULL) 1349 goto nomem; 1350 } 1351 else if (receive_interface || receive_member || receive_error || receive_sender || 1352 receive_path || receive_type || eavesdrop || receive_requested_reply) 1353 { 1354 int message_type; 1355 1356 if (IS_WILDCARD (receive_interface)) 1357 receive_interface = NULL; 1358 if (IS_WILDCARD (receive_member)) 1359 receive_member = NULL; 1360 if (IS_WILDCARD (receive_error)) 1361 receive_error = NULL; 1362 if (IS_WILDCARD (receive_sender)) 1363 receive_sender = NULL; 1364 if (IS_WILDCARD (receive_path)) 1365 receive_path = NULL; 1366 if (IS_WILDCARD (receive_type)) 1367 receive_type = NULL; 1368 1369 message_type = DBUS_MESSAGE_TYPE_INVALID; 1370 if (receive_type != NULL) 1371 { 1372 message_type = dbus_message_type_from_string (receive_type); 1373 if (message_type == DBUS_MESSAGE_TYPE_INVALID) 1374 { 1375 dbus_set_error (error, DBUS_ERROR_FAILED, 1376 "Bad message type \"%s\"", 1377 receive_type); 1378 return FALSE; 1379 } 1380 } 1381 1382 1383 if (eavesdrop && 1384 !(strcmp (eavesdrop, "true") == 0 || 1385 strcmp (eavesdrop, "false") == 0)) 1386 { 1387 dbus_set_error (error, DBUS_ERROR_FAILED, 1388 "Bad value \"%s\" for %s attribute, must be true or false", 1389 "eavesdrop", eavesdrop); 1390 return FALSE; 1391 } 1392 1393 if (receive_requested_reply && 1394 !(strcmp (receive_requested_reply, "true") == 0 || 1395 strcmp (receive_requested_reply, "false") == 0)) 1396 { 1397 dbus_set_error (error, DBUS_ERROR_FAILED, 1398 "Bad value \"%s\" for %s attribute, must be true or false", 1399 "receive_requested_reply", receive_requested_reply); 1400 return FALSE; 1401 } 1402 1403 rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow); 1404 if (rule == NULL) 1405 goto nomem; 1406 1407 if (eavesdrop) 1408 rule->d.receive.eavesdrop = (strcmp (eavesdrop, "true") == 0); 1409 1410 if (receive_requested_reply) 1411 rule->d.receive.requested_reply = (strcmp (receive_requested_reply, "true") == 0); 1412 1413 rule->d.receive.message_type = message_type; 1414 rule->d.receive.path = _dbus_strdup (receive_path); 1415 rule->d.receive.interface = _dbus_strdup (receive_interface); 1416 rule->d.receive.member = _dbus_strdup (receive_member); 1417 rule->d.receive.error = _dbus_strdup (receive_error); 1418 rule->d.receive.origin = _dbus_strdup (receive_sender); 1419 1420 if (receive_path && rule->d.receive.path == NULL) 1421 goto nomem; 1422 if (receive_interface && rule->d.receive.interface == NULL) 1423 goto nomem; 1424 if (receive_member && rule->d.receive.member == NULL) 1425 goto nomem; 1426 if (receive_error && rule->d.receive.error == NULL) 1427 goto nomem; 1428 if (receive_sender && rule->d.receive.origin == NULL) 1429 goto nomem; 1430 } 1431 else if (own) 1432 { 1433 rule = bus_policy_rule_new (BUS_POLICY_RULE_OWN, allow); 1434 if (rule == NULL) 1435 goto nomem; 1436 1437 if (IS_WILDCARD (own)) 1438 own = NULL; 1439 1440 rule->d.own.service_name = _dbus_strdup (own); 1441 if (own && rule->d.own.service_name == NULL) 1442 goto nomem; 1443 } 1444 else if (user) 1445 { 1446 if (IS_WILDCARD (user)) 1447 { 1448 rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow); 1449 if (rule == NULL) 1450 goto nomem; 1451 1452 rule->d.user.uid = DBUS_UID_UNSET; 1453 } 1454 else 1455 { 1456 DBusString username; 1457 dbus_uid_t uid; 1458 1459 _dbus_string_init_const (&username, user); 1460 1461 if (_dbus_get_user_id (&username, &uid)) 1462 { 1463 rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow); 1464 if (rule == NULL) 1465 goto nomem; 1466 1467 rule->d.user.uid = uid; 1468 } 1469 else 1470 { 1471 _dbus_warn ("Unknown username \"%s\" on element <%s>\n", 1472 user, element_name); 1473 } 1474 } 1475 } 1476 else if (group) 1477 { 1478 if (IS_WILDCARD (group)) 1479 { 1480 rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow); 1481 if (rule == NULL) 1482 goto nomem; 1483 1484 rule->d.group.gid = DBUS_GID_UNSET; 1485 } 1486 else 1487 { 1488 DBusString groupname; 1489 dbus_gid_t gid; 1490 1491 _dbus_string_init_const (&groupname, group); 1492 1493 if (_dbus_get_user_id (&groupname, &gid)) 1494 { 1495 rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow); 1496 if (rule == NULL) 1497 goto nomem; 1498 1499 rule->d.group.gid = gid; 1500 } 1501 else 1502 { 1503 _dbus_warn ("Unknown group \"%s\" on element <%s>\n", 1504 group, element_name); 1505 } 1506 } 1507 } 1508 else 1509 _dbus_assert_not_reached ("Did not handle some combination of attributes on <allow> or <deny>"); 1510 1511 if (rule != NULL) 1512 { 1513 Element *pe; 1514 1515 pe = peek_element (parser); 1516 _dbus_assert (pe != NULL); 1517 _dbus_assert (pe->type == ELEMENT_POLICY); 1518 1519 switch (pe->d.policy.type) 1520 { 1521 case POLICY_IGNORED: 1522 /* drop the rule on the floor */ 1523 break; 1524 1525 case POLICY_DEFAULT: 1526 if (!bus_policy_append_default_rule (parser->policy, rule)) 1527 goto nomem; 1528 break; 1529 case POLICY_MANDATORY: 1530 if (!bus_policy_append_mandatory_rule (parser->policy, rule)) 1531 goto nomem; 1532 break; 1533 case POLICY_USER: 1534 if (!BUS_POLICY_RULE_IS_PER_CLIENT (rule)) 1535 { 1536 dbus_set_error (error, DBUS_ERROR_FAILED, 1537 "<%s> rule cannot be per-user because it has bus-global semantics", 1538 element_name); 1539 goto failed; 1540 } 1541 1542 if (!bus_policy_append_user_rule (parser->policy, pe->d.policy.gid_uid_or_at_console, 1543 rule)) 1544 goto nomem; 1545 break; 1546 case POLICY_GROUP: 1547 if (!BUS_POLICY_RULE_IS_PER_CLIENT (rule)) 1548 { 1549 dbus_set_error (error, DBUS_ERROR_FAILED, 1550 "<%s> rule cannot be per-group because it has bus-global semantics", 1551 element_name); 1552 goto failed; 1553 } 1554 1555 if (!bus_policy_append_group_rule (parser->policy, pe->d.policy.gid_uid_or_at_console, 1556 rule)) 1557 goto nomem; 1558 break; 1559 1560 1561 case POLICY_CONSOLE: 1562 if (!bus_policy_append_console_rule (parser->policy, pe->d.policy.gid_uid_or_at_console, 1563 rule)) 1564 goto nomem; 1565 break; 1566 } 1567 1568 bus_policy_rule_unref (rule); 1569 rule = NULL; 1570 } 1571 1572 return TRUE; 1573 1574 nomem: 1575 BUS_SET_OOM (error); 1576 failed: 1577 if (rule) 1578 bus_policy_rule_unref (rule); 1579 return FALSE; 1580 } 1581 1582 static dbus_bool_t 1583 start_policy_child (BusConfigParser *parser, 1584 const char *element_name, 1585 const char **attribute_names, 1586 const char **attribute_values, 1587 DBusError *error) 1588 { 1589 if (strcmp (element_name, "allow") == 0) 1590 { 1591 if (!append_rule_from_element (parser, element_name, 1592 attribute_names, attribute_values, 1593 TRUE, error)) 1594 return FALSE; 1595 1596 if (push_element (parser, ELEMENT_ALLOW) == NULL) 1597 { 1598 BUS_SET_OOM (error); 1599 return FALSE; 1600 } 1601 1602 return TRUE; 1603 } 1604 else if (strcmp (element_name, "deny") == 0) 1605 { 1606 if (!append_rule_from_element (parser, element_name, 1607 attribute_names, attribute_values, 1608 FALSE, error)) 1609 return FALSE; 1610 1611 if (push_element (parser, ELEMENT_DENY) == NULL) 1612 { 1613 BUS_SET_OOM (error); 1614 return FALSE; 1615 } 1616 1617 return TRUE; 1618 } 1619 else 1620 { 1621 dbus_set_error (error, DBUS_ERROR_FAILED, 1622 "Element <%s> not allowed inside <%s> in configuration file", 1623 element_name, "policy"); 1624 return FALSE; 1625 } 1626 } 1627 1628 static dbus_bool_t 1629 start_selinux_child (BusConfigParser *parser, 1630 const char *element_name, 1631 const char **attribute_names, 1632 const char **attribute_values, 1633 DBusError *error) 1634 { 1635 char *own_copy; 1636 char *context_copy; 1637 1638 own_copy = NULL; 1639 context_copy = NULL; 1640 1641 if (strcmp (element_name, "associate") == 0) 1642 { 1643 const char *own; 1644 const char *context; 1645 1646 if (!locate_attributes (parser, "associate", 1647 attribute_names, 1648 attribute_values, 1649 error, 1650 "own", &own, 1651 "context", &context, 1652 NULL)) 1653 return FALSE; 1654 1655 if (push_element (parser, ELEMENT_ASSOCIATE) == NULL) 1656 { 1657 BUS_SET_OOM (error); 1658 return FALSE; 1659 } 1660 1661 if (own == NULL || context == NULL) 1662 { 1663 dbus_set_error (error, DBUS_ERROR_FAILED, 1664 "Element <associate> must have attributes own=\"<servicename>\" and context=\"<selinux context>\""); 1665 return FALSE; 1666 } 1667 1668 own_copy = _dbus_strdup (own); 1669 if (own_copy == NULL) 1670 goto oom; 1671 context_copy = _dbus_strdup (context); 1672 if (context_copy == NULL) 1673 goto oom; 1674 1675 if (!_dbus_hash_table_insert_string (parser->service_context_table, 1676 own_copy, context_copy)) 1677 goto oom; 1678 1679 return TRUE; 1680 } 1681 else 1682 { 1683 dbus_set_error (error, DBUS_ERROR_FAILED, 1684 "Element <%s> not allowed inside <%s> in configuration file", 1685 element_name, "selinux"); 1686 return FALSE; 1687 } 1688 1689 oom: 1690 if (own_copy) 1691 dbus_free (own_copy); 1692 1693 if (context_copy) 1694 dbus_free (context_copy); 1695 1696 BUS_SET_OOM (error); 1697 return FALSE; 1698 } 1699 1700 dbus_bool_t 1701 bus_config_parser_start_element (BusConfigParser *parser, 1702 const char *element_name, 1703 const char **attribute_names, 1704 const char **attribute_values, 1705 DBusError *error) 1706 { 1707 ElementType t; 1708 1709 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 1710 1711 /* printf ("START: %s\n", element_name); */ 1712 1713 t = top_element_type (parser); 1714 1715 if (t == ELEMENT_NONE) 1716 { 1717 if (strcmp (element_name, "busconfig") == 0) 1718 { 1719 if (!check_no_attributes (parser, "busconfig", attribute_names, attribute_values, error)) 1720 return FALSE; 1721 1722 if (push_element (parser, ELEMENT_BUSCONFIG) == NULL) 1723 { 1724 BUS_SET_OOM (error); 1725 return FALSE; 1726 } 1727 1728 return TRUE; 1729 } 1730 else 1731 { 1732 dbus_set_error (error, DBUS_ERROR_FAILED, 1733 "Unknown element <%s> at root of configuration file", 1734 element_name); 1735 return FALSE; 1736 } 1737 } 1738 else if (t == ELEMENT_BUSCONFIG) 1739 { 1740 return start_busconfig_child (parser, element_name, 1741 attribute_names, attribute_values, 1742 error); 1743 } 1744 else if (t == ELEMENT_POLICY) 1745 { 1746 return start_policy_child (parser, element_name, 1747 attribute_names, attribute_values, 1748 error); 1749 } 1750 else if (t == ELEMENT_SELINUX) 1751 { 1752 return start_selinux_child (parser, element_name, 1753 attribute_names, attribute_values, 1754 error); 1755 } 1756 else 1757 { 1758 dbus_set_error (error, DBUS_ERROR_FAILED, 1759 "Element <%s> is not allowed in this context", 1760 element_name); 1761 return FALSE; 1762 } 1763 } 1764 1765 static dbus_bool_t 1766 set_limit (BusConfigParser *parser, 1767 const char *name, 1768 long value, 1769 DBusError *error) 1770 { 1771 dbus_bool_t must_be_positive; 1772 dbus_bool_t must_be_int; 1773 1774 must_be_int = FALSE; 1775 must_be_positive = FALSE; 1776 1777 if (strcmp (name, "max_incoming_bytes") == 0) 1778 { 1779 must_be_positive = TRUE; 1780 parser->limits.max_incoming_bytes = value; 1781 } 1782 else if (strcmp (name, "max_outgoing_bytes") == 0) 1783 { 1784 must_be_positive = TRUE; 1785 parser->limits.max_outgoing_bytes = value; 1786 } 1787 else if (strcmp (name, "max_message_size") == 0) 1788 { 1789 must_be_positive = TRUE; 1790 parser->limits.max_message_size = value; 1791 } 1792 else if (strcmp (name, "service_start_timeout") == 0) 1793 { 1794 must_be_positive = TRUE; 1795 must_be_int = TRUE; 1796 parser->limits.activation_timeout = value; 1797 } 1798 else if (strcmp (name, "auth_timeout") == 0) 1799 { 1800 must_be_positive = TRUE; 1801 must_be_int = TRUE; 1802 parser->limits.auth_timeout = value; 1803 } 1804 else if (strcmp (name, "reply_timeout") == 0) 1805 { 1806 must_be_positive = TRUE; 1807 must_be_int = TRUE; 1808 parser->limits.reply_timeout = value; 1809 } 1810 else if (strcmp (name, "max_completed_connections") == 0) 1811 { 1812 must_be_positive = TRUE; 1813 must_be_int = TRUE; 1814 parser->limits.max_completed_connections = value; 1815 } 1816 else if (strcmp (name, "max_incomplete_connections") == 0) 1817 { 1818 must_be_positive = TRUE; 1819 must_be_int = TRUE; 1820 parser->limits.max_incomplete_connections = value; 1821 } 1822 else if (strcmp (name, "max_connections_per_user") == 0) 1823 { 1824 must_be_positive = TRUE; 1825 must_be_int = TRUE; 1826 parser->limits.max_connections_per_user = value; 1827 } 1828 else if (strcmp (name, "max_pending_service_starts") == 0) 1829 { 1830 must_be_positive = TRUE; 1831 must_be_int = TRUE; 1832 parser->limits.max_pending_activations = value; 1833 } 1834 else if (strcmp (name, "max_names_per_connection") == 0) 1835 { 1836 must_be_positive = TRUE; 1837 must_be_int = TRUE; 1838 parser->limits.max_services_per_connection = value; 1839 } 1840 else if (strcmp (name, "max_match_rules_per_connection") == 0) 1841 { 1842 must_be_positive = TRUE; 1843 must_be_int = TRUE; 1844 parser->limits.max_match_rules_per_connection = value; 1845 } 1846 else if (strcmp (name, "max_replies_per_connection") == 0) 1847 { 1848 must_be_positive = TRUE; 1849 must_be_int = TRUE; 1850 parser->limits.max_replies_per_connection = value; 1851 } 1852 else 1853 { 1854 dbus_set_error (error, DBUS_ERROR_FAILED, 1855 "There is no limit called \"%s\"\n", 1856 name); 1857 return FALSE; 1858 } 1859 1860 if (must_be_positive && value < 0) 1861 { 1862 dbus_set_error (error, DBUS_ERROR_FAILED, 1863 "<limit name=\"%s\"> must be a positive number\n", 1864 name); 1865 return FALSE; 1866 } 1867 1868 if (must_be_int && 1869 (value < _DBUS_INT_MIN || value > _DBUS_INT_MAX)) 1870 { 1871 dbus_set_error (error, DBUS_ERROR_FAILED, 1872 "<limit name=\"%s\"> value is too large\n", 1873 name); 1874 return FALSE; 1875 } 1876 1877 return TRUE; 1878 } 1879 1880 dbus_bool_t 1881 bus_config_parser_end_element (BusConfigParser *parser, 1882 const char *element_name, 1883 DBusError *error) 1884 { 1885 ElementType t; 1886 const char *n; 1887 Element *e; 1888 1889 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 1890 1891 /* printf ("END: %s\n", element_name); */ 1892 1893 t = top_element_type (parser); 1894 1895 if (t == ELEMENT_NONE) 1896 { 1897 /* should probably be an assertion failure but 1898 * being paranoid about XML parsers 1899 */ 1900 dbus_set_error (error, DBUS_ERROR_FAILED, 1901 "XML parser ended element with no element on the stack"); 1902 return FALSE; 1903 } 1904 1905 n = element_type_to_name (t); 1906 _dbus_assert (n != NULL); 1907 if (strcmp (n, element_name) != 0) 1908 { 1909 /* should probably be an assertion failure but 1910 * being paranoid about XML parsers 1911 */ 1912 dbus_set_error (error, DBUS_ERROR_FAILED, 1913 "XML element <%s> ended but topmost element on the stack was <%s>", 1914 element_name, n); 1915 return FALSE; 1916 } 1917 1918 e = peek_element (parser); 1919 _dbus_assert (e != NULL); 1920 1921 switch (e->type) 1922 { 1923 case ELEMENT_NONE: 1924 _dbus_assert_not_reached ("element in stack has no type"); 1925 break; 1926 1927 case ELEMENT_INCLUDE: 1928 case ELEMENT_USER: 1929 case ELEMENT_TYPE: 1930 case ELEMENT_LISTEN: 1931 case ELEMENT_PIDFILE: 1932 case ELEMENT_AUTH: 1933 case ELEMENT_SERVICEDIR: 1934 case ELEMENT_INCLUDEDIR: 1935 case ELEMENT_LIMIT: 1936 if (!e->had_content) 1937 { 1938 dbus_set_error (error, DBUS_ERROR_FAILED, 1939 "XML element <%s> was expected to have content inside it", 1940 element_type_to_name (e->type)); 1941 return FALSE; 1942 } 1943 1944 if (e->type == ELEMENT_LIMIT) 1945 { 1946 if (!set_limit (parser, e->d.limit.name, e->d.limit.value, 1947 error)) 1948 return FALSE; 1949 } 1950 break; 1951 1952 case ELEMENT_BUSCONFIG: 1953 case ELEMENT_POLICY: 1954 case ELEMENT_ALLOW: 1955 case ELEMENT_DENY: 1956 case ELEMENT_FORK: 1957 case ELEMENT_SELINUX: 1958 case ELEMENT_ASSOCIATE: 1959 case ELEMENT_STANDARD_SESSION_SERVICEDIRS: 1960 break; 1961 } 1962 1963 pop_element (parser); 1964 1965 return TRUE; 1966 } 1967 1968 static dbus_bool_t 1969 all_whitespace (const DBusString *str) 1970 { 1971 int i; 1972 1973 _dbus_string_skip_white (str, 0, &i); 1974 1975 return i == _dbus_string_get_length (str); 1976 } 1977 1978 static dbus_bool_t 1979 make_full_path (const DBusString *basedir, 1980 const DBusString *filename, 1981 DBusString *full_path) 1982 { 1983 if (_dbus_path_is_absolute (filename)) 1984 { 1985 return _dbus_string_copy (filename, 0, full_path, 0); 1986 } 1987 else 1988 { 1989 if (!_dbus_string_copy (basedir, 0, full_path, 0)) 1990 return FALSE; 1991 1992 if (!_dbus_concat_dir_and_file (full_path, filename)) 1993 return FALSE; 1994 1995 return TRUE; 1996 } 1997 } 1998 1999 static dbus_bool_t 2000 include_file (BusConfigParser *parser, 2001 const DBusString *filename, 2002 dbus_bool_t ignore_missing, 2003 DBusError *error) 2004 { 2005 /* FIXME good test case for this would load each config file in the 2006 * test suite both alone, and as an include, and check 2007 * that the result is the same 2008 */ 2009 BusConfigParser *included; 2010 const char *filename_str; 2011 DBusError tmp_error; 2012 2013 dbus_error_init (&tmp_error); 2014 2015 filename_str = _dbus_string_get_const_data (filename); 2016 2017 /* Check to make sure this file hasn't already been included. */ 2018 if (seen_include (parser, filename)) 2019 { 2020 dbus_set_error (error, DBUS_ERROR_FAILED, 2021 "Circular inclusion of file '%s'", 2022 filename_str); 2023 return FALSE; 2024 } 2025 2026 if (! _dbus_list_append (&parser->included_files, (void *) filename_str)) 2027 { 2028 BUS_SET_OOM (error); 2029 return FALSE; 2030 } 2031 2032 /* Since parser is passed in as the parent, included 2033 inherits parser's limits. */ 2034 included = bus_config_load (filename, FALSE, parser, &tmp_error); 2035 2036 _dbus_list_pop_last (&parser->included_files); 2037 2038 if (included == NULL) 2039 { 2040 _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); 2041 2042 if (dbus_error_has_name (&tmp_error, DBUS_ERROR_FILE_NOT_FOUND) && 2043 ignore_missing) 2044 { 2045 dbus_error_free (&tmp_error); 2046 return TRUE; 2047 } 2048 else 2049 { 2050 dbus_move_error (&tmp_error, error); 2051 return FALSE; 2052 } 2053 } 2054 else 2055 { 2056 _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); 2057 2058 if (!merge_included (parser, included, error)) 2059 { 2060 bus_config_parser_unref (included); 2061 return FALSE; 2062 } 2063 2064 /* Copy included's limits back to parser. */ 2065 parser->limits = included->limits; 2066 2067 bus_config_parser_unref (included); 2068 return TRUE; 2069 } 2070 } 2071 2072 static dbus_bool_t 2073 include_dir (BusConfigParser *parser, 2074 const DBusString *dirname, 2075 DBusError *error) 2076 { 2077 DBusString filename; 2078 dbus_bool_t retval; 2079 DBusError tmp_error; 2080 DBusDirIter *dir; 2081 char *s; 2082 2083 if (!_dbus_string_init (&filename)) 2084 { 2085 BUS_SET_OOM (error); 2086 return FALSE; 2087 } 2088 2089 retval = FALSE; 2090 2091 dir = _dbus_directory_open (dirname, error); 2092 2093 if (dir == NULL) 2094 goto failed; 2095 2096 dbus_error_init (&tmp_error); 2097 while (_dbus_directory_get_next_file (dir, &filename, &tmp_error)) 2098 { 2099 DBusString full_path; 2100 2101 if (!_dbus_string_init (&full_path)) 2102 { 2103 BUS_SET_OOM (error); 2104 goto failed; 2105 } 2106 2107 if (!_dbus_string_copy (dirname, 0, &full_path, 0)) 2108 { 2109 BUS_SET_OOM (error); 2110 _dbus_string_free (&full_path); 2111 goto failed; 2112 } 2113 2114 if (!_dbus_concat_dir_and_file (&full_path, &filename)) 2115 { 2116 BUS_SET_OOM (error); 2117 _dbus_string_free (&full_path); 2118 goto failed; 2119 } 2120 2121 if (_dbus_string_ends_with_c_str (&full_path, ".conf")) 2122 { 2123 if (!include_file (parser, &full_path, TRUE, error)) 2124 { 2125 _dbus_string_free (&full_path); 2126 goto failed; 2127 } 2128 } 2129 2130 _dbus_string_free (&full_path); 2131 } 2132 2133 if (dbus_error_is_set (&tmp_error)) 2134 { 2135 dbus_move_error (&tmp_error, error); 2136 goto failed; 2137 } 2138 2139 2140 if (!_dbus_string_copy_data (dirname, &s)) 2141 { 2142 BUS_SET_OOM (error); 2143 goto failed; 2144 } 2145 2146 if (!_dbus_list_append (&parser->conf_dirs, s)) 2147 { 2148 dbus_free (s); 2149 BUS_SET_OOM (error); 2150 goto failed; 2151 } 2152 2153 retval = TRUE; 2154 2155 failed: 2156 _dbus_string_free (&filename); 2157 2158 if (dir) 2159 _dbus_directory_close (dir); 2160 2161 return retval; 2162 } 2163 2164 dbus_bool_t 2165 bus_config_parser_content (BusConfigParser *parser, 2166 const DBusString *content, 2167 DBusError *error) 2168 { 2169 Element *e; 2170 2171 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 2172 2173 #if 0 2174 { 2175 const char *c_str; 2176 2177 _dbus_string_get_const_data (content, &c_str); 2178 2179 printf ("CONTENT %d bytes: %s\n", _dbus_string_get_length (content), c_str); 2180 } 2181 #endif 2182 2183 e = peek_element (parser); 2184 if (e == NULL) 2185 { 2186 dbus_set_error (error, DBUS_ERROR_FAILED, 2187 "Text content outside of any XML element in configuration file"); 2188 return FALSE; 2189 } 2190 else if (e->had_content) 2191 { 2192 _dbus_assert_not_reached ("Element had multiple content blocks"); 2193 return FALSE; 2194 } 2195 2196 switch (top_element_type (parser)) 2197 { 2198 case ELEMENT_NONE: 2199 _dbus_assert_not_reached ("element at top of stack has no type"); 2200 return FALSE; 2201 2202 case ELEMENT_BUSCONFIG: 2203 case ELEMENT_POLICY: 2204 case ELEMENT_ALLOW: 2205 case ELEMENT_DENY: 2206 case ELEMENT_FORK: 2207 case ELEMENT_STANDARD_SESSION_SERVICEDIRS: 2208 case ELEMENT_SELINUX: 2209 case ELEMENT_ASSOCIATE: 2210 if (all_whitespace (content)) 2211 return TRUE; 2212 else 2213 { 2214 dbus_set_error (error, DBUS_ERROR_FAILED, 2215 "No text content expected inside XML element %s in configuration file", 2216 element_type_to_name (top_element_type (parser))); 2217 return FALSE; 2218 } 2219 2220 case ELEMENT_PIDFILE: 2221 { 2222 char *s; 2223 2224 e->had_content = TRUE; 2225 2226 if (!_dbus_string_copy_data (content, &s)) 2227 goto nomem; 2228 2229 dbus_free (parser->pidfile); 2230 parser->pidfile = s; 2231 } 2232 break; 2233 2234 case ELEMENT_INCLUDE: 2235 { 2236 DBusString full_path, selinux_policy_root; 2237 2238 e->had_content = TRUE; 2239 2240 if (e->d.include.if_selinux_enabled 2241 && !bus_selinux_enabled ()) 2242 break; 2243 2244 if (!_dbus_string_init (&full_path)) 2245 goto nomem; 2246 2247 if (e->d.include.selinux_root_relative) 2248 { 2249 if (!bus_selinux_get_policy_root ()) 2250 { 2251 dbus_set_error (error, DBUS_ERROR_FAILED, 2252 "Could not determine SELinux policy root for relative inclusion"); 2253 _dbus_string_free (&full_path); 2254 return FALSE; 2255 } 2256 _dbus_string_init_const (&selinux_policy_root, 2257 bus_selinux_get_policy_root ()); 2258 if (!make_full_path (&selinux_policy_root, content, &full_path)) 2259 { 2260 _dbus_string_free (&full_path); 2261 goto nomem; 2262 } 2263 } 2264 else if (!make_full_path (&parser->basedir, content, &full_path)) 2265 { 2266 _dbus_string_free (&full_path); 2267 goto nomem; 2268 } 2269 2270 if (!include_file (parser, &full_path, 2271 e->d.include.ignore_missing, error)) 2272 { 2273 _dbus_string_free (&full_path); 2274 return FALSE; 2275 } 2276 2277 _dbus_string_free (&full_path); 2278 } 2279 break; 2280 2281 case ELEMENT_INCLUDEDIR: 2282 { 2283 DBusString full_path; 2284 2285 e->had_content = TRUE; 2286 2287 if (!_dbus_string_init (&full_path)) 2288 goto nomem; 2289 2290 if (!make_full_path (&parser->basedir, content, &full_path)) 2291 { 2292 _dbus_string_free (&full_path); 2293 goto nomem; 2294 } 2295 2296 if (!include_dir (parser, &full_path, error)) 2297 { 2298 _dbus_string_free (&full_path); 2299 return FALSE; 2300 } 2301 2302 _dbus_string_free (&full_path); 2303 } 2304 break; 2305 2306 case ELEMENT_USER: 2307 { 2308 char *s; 2309 2310 e->had_content = TRUE; 2311 2312 if (!_dbus_string_copy_data (content, &s)) 2313 goto nomem; 2314 2315 dbus_free (parser->user); 2316 parser->user = s; 2317 } 2318 break; 2319 2320 case ELEMENT_TYPE: 2321 { 2322 char *s; 2323 2324 e->had_content = TRUE; 2325 2326 if (!_dbus_string_copy_data (content, &s)) 2327 goto nomem; 2328 2329 dbus_free (parser->bus_type); 2330 parser->bus_type = s; 2331 } 2332 break; 2333 2334 case ELEMENT_LISTEN: 2335 { 2336 char *s; 2337 2338 e->had_content = TRUE; 2339 2340 if (!_dbus_string_copy_data (content, &s)) 2341 goto nomem; 2342 2343 if (!_dbus_list_append (&parser->listen_on, 2344 s)) 2345 { 2346 dbus_free (s); 2347 goto nomem; 2348 } 2349 } 2350 break; 2351 2352 case ELEMENT_AUTH: 2353 { 2354 char *s; 2355 2356 e->had_content = TRUE; 2357 2358 if (!_dbus_string_copy_data (content, &s)) 2359 goto nomem; 2360 2361 if (!_dbus_list_append (&parser->mechanisms, 2362 s)) 2363 { 2364 dbus_free (s); 2365 goto nomem; 2366 } 2367 } 2368 break; 2369 2370 case ELEMENT_SERVICEDIR: 2371 { 2372 char *s; 2373 DBusString full_path; 2374 2375 e->had_content = TRUE; 2376 2377 if (!_dbus_string_init (&full_path)) 2378 goto nomem; 2379 2380 if (!make_full_path (&parser->basedir, content, &full_path)) 2381 { 2382 _dbus_string_free (&full_path); 2383 goto nomem; 2384 } 2385 2386 if (!_dbus_string_copy_data (&full_path, &s)) 2387 { 2388 _dbus_string_free (&full_path); 2389 goto nomem; 2390 } 2391 2392 if (!service_dirs_append_unique_or_free (&parser->service_dirs, s)) 2393 { 2394 _dbus_string_free (&full_path); 2395 dbus_free (s); 2396 goto nomem; 2397 } 2398 2399 _dbus_string_free (&full_path); 2400 } 2401 break; 2402 2403 case ELEMENT_LIMIT: 2404 { 2405 long val; 2406 2407 e->had_content = TRUE; 2408 2409 val = 0; 2410 if (!_dbus_string_parse_int (content, 0, &val, NULL)) 2411 { 2412 dbus_set_error (error, DBUS_ERROR_FAILED, 2413 "<limit name=\"%s\"> element has invalid value (could not parse as integer)", 2414 e->d.limit.name); 2415 return FALSE; 2416 } 2417 2418 e->d.limit.value = val; 2419 2420 _dbus_verbose ("Loaded value %ld for limit %s\n", 2421 e->d.limit.value, 2422 e->d.limit.name); 2423 } 2424 break; 2425 } 2426 2427 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 2428 return TRUE; 2429 2430 nomem: 2431 BUS_SET_OOM (error); 2432 return FALSE; 2433 } 2434 2435 dbus_bool_t 2436 bus_config_parser_finished (BusConfigParser *parser, 2437 DBusError *error) 2438 { 2439 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 2440 2441 if (parser->stack != NULL) 2442 { 2443 dbus_set_error (error, DBUS_ERROR_FAILED, 2444 "Element <%s> was not closed in configuration file", 2445 element_type_to_name (top_element_type (parser))); 2446 2447 return FALSE; 2448 } 2449 2450 if (parser->is_toplevel && parser->listen_on == NULL) 2451 { 2452 dbus_set_error (error, DBUS_ERROR_FAILED, 2453 "Configuration file needs one or more <listen> elements giving addresses"); 2454 return FALSE; 2455 } 2456 2457 return TRUE; 2458 } 2459 2460 const char* 2461 bus_config_parser_get_user (BusConfigParser *parser) 2462 { 2463 return parser->user; 2464 } 2465 2466 const char* 2467 bus_config_parser_get_type (BusConfigParser *parser) 2468 { 2469 return parser->bus_type; 2470 } 2471 2472 DBusList** 2473 bus_config_parser_get_addresses (BusConfigParser *parser) 2474 { 2475 return &parser->listen_on; 2476 } 2477 2478 DBusList** 2479 bus_config_parser_get_mechanisms (BusConfigParser *parser) 2480 { 2481 return &parser->mechanisms; 2482 } 2483 2484 DBusList** 2485 bus_config_parser_get_service_dirs (BusConfigParser *parser) 2486 { 2487 return &parser->service_dirs; 2488 } 2489 2490 DBusList** 2491 bus_config_parser_get_conf_dirs (BusConfigParser *parser) 2492 { 2493 return &parser->conf_dirs; 2494 } 2495 2496 dbus_bool_t 2497 bus_config_parser_get_fork (BusConfigParser *parser) 2498 { 2499 return parser->fork; 2500 } 2501 2502 const char * 2503 bus_config_parser_get_pidfile (BusConfigParser *parser) 2504 { 2505 return parser->pidfile; 2506 } 2507 2508 BusPolicy* 2509 bus_config_parser_steal_policy (BusConfigParser *parser) 2510 { 2511 BusPolicy *policy; 2512 2513 _dbus_assert (parser->policy != NULL); /* can only steal the policy 1 time */ 2514 2515 policy = parser->policy; 2516 2517 parser->policy = NULL; 2518 2519 return policy; 2520 } 2521 2522 /* Overwrite any limits that were set in the configuration file */ 2523 void 2524 bus_config_parser_get_limits (BusConfigParser *parser, 2525 BusLimits *limits) 2526 { 2527 *limits = parser->limits; 2528 } 2529 2530 DBusHashTable* 2531 bus_config_parser_steal_service_context_table (BusConfigParser *parser) 2532 { 2533 DBusHashTable *table; 2534 2535 _dbus_assert (parser->service_context_table != NULL); /* can only steal once */ 2536 2537 table = parser->service_context_table; 2538 2539 parser->service_context_table = NULL; 2540 2541 return table; 2542 } 2543 2544 #ifdef DBUS_BUILD_TESTS 2545 #include <stdio.h> 2546 2547 typedef enum 2548 { 2549 VALID, 2550 INVALID, 2551 UNKNOWN 2552 } Validity; 2553 2554 static dbus_bool_t 2555 do_load (const DBusString *full_path, 2556 Validity validity, 2557 dbus_bool_t oom_possible) 2558 { 2559 BusConfigParser *parser; 2560 DBusError error; 2561 2562 dbus_error_init (&error); 2563 2564 parser = bus_config_load (full_path, TRUE, NULL, &error); 2565 if (parser == NULL) 2566 { 2567 _DBUS_ASSERT_ERROR_IS_SET (&error); 2568 2569 if (oom_possible && 2570 dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) 2571 { 2572 _dbus_verbose ("Failed to load valid file due to OOM\n"); 2573 dbus_error_free (&error); 2574 return TRUE; 2575 } 2576 else if (validity == VALID) 2577 { 2578 _dbus_warn ("Failed to load valid file but still had memory: %s\n", 2579 error.message); 2580 2581 dbus_error_free (&error); 2582 return FALSE; 2583 } 2584 else 2585 { 2586 dbus_error_free (&error); 2587 return TRUE; 2588 } 2589 } 2590 else 2591 { 2592 _DBUS_ASSERT_ERROR_IS_CLEAR (&error); 2593 2594 bus_config_parser_unref (parser); 2595 2596 if (validity == INVALID) 2597 { 2598 _dbus_warn ("Accepted invalid file\n"); 2599 return FALSE; 2600 } 2601 2602 return TRUE; 2603 } 2604 } 2605 2606 typedef struct 2607 { 2608 const DBusString *full_path; 2609 Validity validity; 2610 } LoaderOomData; 2611 2612 static dbus_bool_t 2613 check_loader_oom_func (void *data) 2614 { 2615 LoaderOomData *d = data; 2616 2617 return do_load (d->full_path, d->validity, TRUE); 2618 } 2619 2620 static dbus_bool_t 2621 process_test_valid_subdir (const DBusString *test_base_dir, 2622 const char *subdir, 2623 Validity validity) 2624 { 2625 DBusString test_directory; 2626 DBusString filename; 2627 DBusDirIter *dir; 2628 dbus_bool_t retval; 2629 DBusError error; 2630 2631 retval = FALSE; 2632 dir = NULL; 2633 2634 if (!_dbus_string_init (&test_directory)) 2635 _dbus_assert_not_reached ("didn't allocate test_directory\n"); 2636 2637 _dbus_string_init_const (&filename, subdir); 2638 2639 if (!_dbus_string_copy (test_base_dir, 0, 2640 &test_directory, 0)) 2641 _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory"); 2642 2643 if (!_dbus_concat_dir_and_file (&test_directory, &filename)) 2644 _dbus_assert_not_reached ("couldn't allocate full path"); 2645 2646 _dbus_string_free (&filename); 2647 if (!_dbus_string_init (&filename)) 2648 _dbus_assert_not_reached ("didn't allocate filename string\n"); 2649 2650 dbus_error_init (&error); 2651 dir = _dbus_directory_open (&test_directory, &error); 2652 if (dir == NULL) 2653 { 2654 _dbus_warn ("Could not open %s: %s\n", 2655 _dbus_string_get_const_data (&test_directory), 2656 error.message); 2657 dbus_error_free (&error); 2658 goto failed; 2659 } 2660 2661 if (validity == VALID) 2662 printf ("Testing valid files:\n"); 2663 else if (validity == INVALID) 2664 printf ("Testing invalid files:\n"); 2665 else 2666 printf ("Testing unknown files:\n"); 2667 2668 next: 2669 while (_dbus_directory_get_next_file (dir, &filename, &error)) 2670 { 2671 DBusString full_path; 2672 LoaderOomData d; 2673 2674 if (!_dbus_string_init (&full_path)) 2675 _dbus_assert_not_reached ("couldn't init string"); 2676 2677 if (!_dbus_string_copy (&test_directory, 0, &full_path, 0)) 2678 _dbus_assert_not_reached ("couldn't copy dir to full_path"); 2679 2680 if (!_dbus_concat_dir_and_file (&full_path, &filename)) 2681 _dbus_assert_not_reached ("couldn't concat file to dir"); 2682 2683 if (!_dbus_string_ends_with_c_str (&full_path, ".conf")) 2684 { 2685 _dbus_verbose ("Skipping non-.conf file %s\n", 2686 _dbus_string_get_const_data (&filename)); 2687 _dbus_string_free (&full_path); 2688 goto next; 2689 } 2690 2691 printf (" %s\n", _dbus_string_get_const_data (&filename)); 2692 2693 _dbus_verbose (" expecting %s\n", 2694 validity == VALID ? "valid" : 2695 (validity == INVALID ? "invalid" : 2696 (validity == UNKNOWN ? "unknown" : "???"))); 2697 2698 d.full_path = &full_path; 2699 d.validity = validity; 2700 2701 /* FIXME hackaround for an expat problem, see 2702 * https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=124747 2703 * http://freedesktop.org/pipermail/dbus/2004-May/001153.html 2704 */ 2705 /* if (!_dbus_test_oom_handling ("config-loader", check_loader_oom_func, &d)) */ 2706 if (!check_loader_oom_func (&d)) 2707 _dbus_assert_not_reached ("test failed"); 2708 2709 _dbus_string_free (&full_path); 2710 } 2711 2712 if (dbus_error_is_set (&error)) 2713 { 2714 _dbus_warn ("Could not get next file in %s: %s\n", 2715 _dbus_string_get_const_data (&test_directory), 2716 error.message); 2717 dbus_error_free (&error); 2718 goto failed; 2719 } 2720 2721 retval = TRUE; 2722 2723 failed: 2724 2725 if (dir) 2726 _dbus_directory_close (dir); 2727 _dbus_string_free (&test_directory); 2728 _dbus_string_free (&filename); 2729 2730 return retval; 2731 } 2732 2733 static dbus_bool_t 2734 bools_equal (dbus_bool_t a, 2735 dbus_bool_t b) 2736 { 2737 return a ? b : !b; 2738 } 2739 2740 static dbus_bool_t 2741 strings_equal_or_both_null (const char *a, 2742 const char *b) 2743 { 2744 if (a == NULL || b == NULL) 2745 return a == b; 2746 else 2747 return !strcmp (a, b); 2748 } 2749 2750 static dbus_bool_t 2751 elements_equal (const Element *a, 2752 const Element *b) 2753 { 2754 if (a->type != b->type) 2755 return FALSE; 2756 2757 if (!bools_equal (a->had_content, b->had_content)) 2758 return FALSE; 2759 2760 switch (a->type) 2761 { 2762 2763 case ELEMENT_INCLUDE: 2764 if (!bools_equal (a->d.include.ignore_missing, 2765 b->d.include.ignore_missing)) 2766 return FALSE; 2767 break; 2768 2769 case ELEMENT_POLICY: 2770 if (a->d.policy.type != b->d.policy.type) 2771 return FALSE; 2772 if (a->d.policy.gid_uid_or_at_console != b->d.policy.gid_uid_or_at_console) 2773 return FALSE; 2774 break; 2775 2776 case ELEMENT_LIMIT: 2777 if (strcmp (a->d.limit.name, b->d.limit.name)) 2778 return FALSE; 2779 if (a->d.limit.value != b->d.limit.value) 2780 return FALSE; 2781 break; 2782 2783 default: 2784 /* do nothing */ 2785 break; 2786 } 2787 2788 return TRUE; 2789 2790 } 2791 2792 static dbus_bool_t 2793 lists_of_elements_equal (DBusList *a, 2794 DBusList *b) 2795 { 2796 DBusList *ia; 2797 DBusList *ib; 2798 2799 ia = a; 2800 ib = b; 2801 2802 while (ia != NULL && ib != NULL) 2803 { 2804 if (elements_equal (ia->data, ib->data)) 2805 return FALSE; 2806 ia = _dbus_list_get_next_link (&a, ia); 2807 ib = _dbus_list_get_next_link (&b, ib); 2808 } 2809 2810 return ia == NULL && ib == NULL; 2811 } 2812 2813 static dbus_bool_t 2814 lists_of_c_strings_equal (DBusList *a, 2815 DBusList *b) 2816 { 2817 DBusList *ia; 2818 DBusList *ib; 2819 2820 ia = a; 2821 ib = b; 2822 2823 while (ia != NULL && ib != NULL) 2824 { 2825 if (strcmp (ia->data, ib->data)) 2826 return FALSE; 2827 ia = _dbus_list_get_next_link (&a, ia); 2828 ib = _dbus_list_get_next_link (&b, ib); 2829 } 2830 2831 return ia == NULL && ib == NULL; 2832 } 2833 2834 static dbus_bool_t 2835 limits_equal (const BusLimits *a, 2836 const BusLimits *b) 2837 { 2838 return 2839 (a->max_incoming_bytes == b->max_incoming_bytes 2840 || a->max_outgoing_bytes == b->max_outgoing_bytes 2841 || a->max_message_size == b->max_message_size 2842 || a->activation_timeout == b->activation_timeout 2843 || a->auth_timeout == b->auth_timeout 2844 || a->max_completed_connections == b->max_completed_connections 2845 || a->max_incomplete_connections == b->max_incomplete_connections 2846 || a->max_connections_per_user == b->max_connections_per_user 2847 || a->max_pending_activations == b->max_pending_activations 2848 || a->max_services_per_connection == b->max_services_per_connection 2849 || a->max_match_rules_per_connection == b->max_match_rules_per_connection 2850 || a->max_replies_per_connection == b->max_replies_per_connection 2851 || a->reply_timeout == b->reply_timeout); 2852 } 2853 2854 static dbus_bool_t 2855 config_parsers_equal (const BusConfigParser *a, 2856 const BusConfigParser *b) 2857 { 2858 if (!_dbus_string_equal (&a->basedir, &b->basedir)) 2859 return FALSE; 2860 2861 if (!lists_of_elements_equal (a->stack, b->stack)) 2862 return FALSE; 2863 2864 if (!strings_equal_or_both_null (a->user, b->user)) 2865 return FALSE; 2866 2867 if (!lists_of_c_strings_equal (a->listen_on, b->listen_on)) 2868 return FALSE; 2869 2870 if (!lists_of_c_strings_equal (a->mechanisms, b->mechanisms)) 2871 return FALSE; 2872 2873 if (!lists_of_c_strings_equal (a->service_dirs, b->service_dirs)) 2874 return FALSE; 2875 2876 /* FIXME: compare policy */ 2877 2878 /* FIXME: compare service selinux ID table */ 2879 2880 if (! limits_equal (&a->limits, &b->limits)) 2881 return FALSE; 2882 2883 if (!strings_equal_or_both_null (a->pidfile, b->pidfile)) 2884 return FALSE; 2885 2886 if (! bools_equal (a->fork, b->fork)) 2887 return FALSE; 2888 2889 if (! bools_equal (a->is_toplevel, b->is_toplevel)) 2890 return FALSE; 2891 2892 return TRUE; 2893 } 2894 2895 static dbus_bool_t 2896 all_are_equiv (const DBusString *target_directory) 2897 { 2898 DBusString filename; 2899 DBusDirIter *dir; 2900 BusConfigParser *first_parser; 2901 BusConfigParser *parser; 2902 DBusError error; 2903 dbus_bool_t equal; 2904 dbus_bool_t retval; 2905 2906 dir = NULL; 2907 first_parser = NULL; 2908 parser = NULL; 2909 retval = FALSE; 2910 2911 if (!_dbus_string_init (&filename)) 2912 _dbus_assert_not_reached ("didn't allocate filename string"); 2913 2914 dbus_error_init (&error); 2915 dir = _dbus_directory_open (target_directory, &error); 2916 if (dir == NULL) 2917 { 2918 _dbus_warn ("Could not open %s: %s\n", 2919 _dbus_string_get_const_data (target_directory), 2920 error.message); 2921 dbus_error_free (&error); 2922 goto finished; 2923 } 2924 2925 printf ("Comparing equivalent files:\n"); 2926 2927 next: 2928 while (_dbus_directory_get_next_file (dir, &filename, &error)) 2929 { 2930 DBusString full_path; 2931 2932 if (!_dbus_string_init (&full_path)) 2933 _dbus_assert_not_reached ("couldn't init string"); 2934 2935 if (!_dbus_string_copy (target_directory, 0, &full_path, 0)) 2936 _dbus_assert_not_reached ("couldn't copy dir to full_path"); 2937 2938 if (!_dbus_concat_dir_and_file (&full_path, &filename)) 2939 _dbus_assert_not_reached ("couldn't concat file to dir"); 2940 2941 if (!_dbus_string_ends_with_c_str (&full_path, ".conf")) 2942 { 2943 _dbus_verbose ("Skipping non-.conf file %s\n", 2944 _dbus_string_get_const_data (&filename)); 2945 _dbus_string_free (&full_path); 2946 goto next; 2947 } 2948 2949 printf (" %s\n", _dbus_string_get_const_data (&filename)); 2950 2951 parser = bus_config_load (&full_path, TRUE, NULL, &error); 2952 2953 if (parser == NULL) 2954 { 2955 _dbus_warn ("Could not load file %s: %s\n", 2956 _dbus_string_get_const_data (&full_path), 2957 error.message); 2958 _dbus_string_free (&full_path); 2959 dbus_error_free (&error); 2960 goto finished; 2961 } 2962 else if (first_parser == NULL) 2963 { 2964 _dbus_string_free (&full_path); 2965 first_parser = parser; 2966 } 2967 else 2968 { 2969 _dbus_string_free (&full_path); 2970 equal = config_parsers_equal (first_parser, parser); 2971 bus_config_parser_unref (parser); 2972 if (! equal) 2973 goto finished; 2974 } 2975 } 2976 2977 retval = TRUE; 2978 2979 finished: 2980 _dbus_string_free (&filename); 2981 if (first_parser) 2982 bus_config_parser_unref (first_parser); 2983 if (dir) 2984 _dbus_directory_close (dir); 2985 2986 return retval; 2987 2988 } 2989 2990 static dbus_bool_t 2991 process_test_equiv_subdir (const DBusString *test_base_dir, 2992 const char *subdir) 2993 { 2994 DBusString test_directory; 2995 DBusString filename; 2996 DBusDirIter *dir; 2997 DBusError error; 2998 dbus_bool_t equal; 2999 dbus_bool_t retval; 3000 3001 dir = NULL; 3002 retval = FALSE; 3003 3004 if (!_dbus_string_init (&test_directory)) 3005 _dbus_assert_not_reached ("didn't allocate test_directory"); 3006 3007 _dbus_string_init_const (&filename, subdir); 3008 3009 if (!_dbus_string_copy (test_base_dir, 0, 3010 &test_directory, 0)) 3011 _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory"); 3012 3013 if (!_dbus_concat_dir_and_file (&test_directory, &filename)) 3014 _dbus_assert_not_reached ("couldn't allocate full path"); 3015 3016 _dbus_string_free (&filename); 3017 if (!_dbus_string_init (&filename)) 3018 _dbus_assert_not_reached ("didn't allocate filename string"); 3019 3020 dbus_error_init (&error); 3021 dir = _dbus_directory_open (&test_directory, &error); 3022 if (dir == NULL) 3023 { 3024 _dbus_warn ("Could not open %s: %s\n", 3025 _dbus_string_get_const_data (&test_directory), 3026 error.message); 3027 dbus_error_free (&error); 3028 goto finished; 3029 } 3030 3031 while (_dbus_directory_get_next_file (dir, &filename, &error)) 3032 { 3033 DBusString full_path; 3034 3035 /* Skip CVS's magic directories! */ 3036 if (_dbus_string_equal_c_str (&filename, "CVS")) 3037 continue; 3038 3039 if (!_dbus_string_init (&full_path)) 3040 _dbus_assert_not_reached ("couldn't init string"); 3041 3042 if (!_dbus_string_copy (&test_directory, 0, &full_path, 0)) 3043 _dbus_assert_not_reached ("couldn't copy dir to full_path"); 3044 3045 if (!_dbus_concat_dir_and_file (&full_path, &filename)) 3046 _dbus_assert_not_reached ("couldn't concat file to dir"); 3047 3048 equal = all_are_equiv (&full_path); 3049 _dbus_string_free (&full_path); 3050 3051 if (!equal) 3052 goto finished; 3053 } 3054 3055 retval = TRUE; 3056 3057 finished: 3058 _dbus_string_free (&test_directory); 3059 _dbus_string_free (&filename); 3060 if (dir) 3061 _dbus_directory_close (dir); 3062 3063 return retval; 3064 3065 } 3066 3067 static const char *test_service_dir_matches[] = 3068 { 3069 "/testusr/testlocal/testshare/dbus-1/services", 3070 "/testusr/testshare/dbus-1/services", 3071 DBUS_DATADIR"/dbus-1/services", 3072 "/testhome/foo/.testlocal/testshare/dbus-1/services", 3073 NULL 3074 }; 3075 3076 static dbus_bool_t 3077 test_default_session_servicedirs (void) 3078 { 3079 DBusList *dirs; 3080 DBusList *link; 3081 int i; 3082 3083 dirs = NULL; 3084 3085 printf ("Testing retriving the default session service directories\n"); 3086 if (!_dbus_get_standard_session_servicedirs (&dirs)) 3087 _dbus_assert_not_reached ("couldn't get stardard dirs"); 3088 3089 /* make sure our defaults end with share/dbus-1/service */ 3090 while ((link = _dbus_list_pop_first_link (&dirs))) 3091 { 3092 DBusString path; 3093 3094 printf (" default service dir: %s\n", (char *)link->data); 3095 _dbus_string_init_const (&path, (char *)link->data); 3096 if (!_dbus_string_ends_with_c_str (&path, "share/dbus-1/services")) 3097 { 3098 printf ("error with default session service directories\n"); 3099 return FALSE; 3100 } 3101 3102 dbus_free (link->data); 3103 _dbus_list_free_link (link); 3104 } 3105 3106 if (!_dbus_setenv ("XDG_DATA_HOME", "/testhome/foo/.testlocal/testshare")) 3107 _dbus_assert_not_reached ("couldn't setenv XDG_DATA_HOME"); 3108 3109 if (!_dbus_setenv ("XDG_DATA_DIRS", ":/testusr/testlocal/testshare: :/testusr/testshare:")) 3110 _dbus_assert_not_reached ("couldn't setenv XDG_DATA_DIRS"); 3111 3112 if (!_dbus_get_standard_session_servicedirs (&dirs)) 3113 _dbus_assert_not_reached ("couldn't get stardard dirs"); 3114 3115 /* make sure we read and parse the env variable correctly */ 3116 i = 0; 3117 while ((link = _dbus_list_pop_first_link (&dirs))) 3118 { 3119 printf (" test service dir: %s\n", (char *)link->data); 3120 if (test_service_dir_matches[i] == NULL) 3121 { 3122 printf ("more directories parsed than in match set\n"); 3123 return FALSE; 3124 } 3125 3126 if (strcmp (test_service_dir_matches[i], 3127 (char *)link->data) != 0) 3128 { 3129 printf ("%s directory does not match %s in the match set\n", 3130 (char *)link->data, 3131 test_service_dir_matches[i]); 3132 return FALSE; 3133 } 3134 3135 ++i; 3136 3137 dbus_free (link->data); 3138 _dbus_list_free_link (link); 3139 } 3140 3141 if (test_service_dir_matches[i] != NULL) 3142 { 3143 printf ("extra data %s in the match set was not matched\n", 3144 test_service_dir_matches[i]); 3145 3146 return FALSE; 3147 } 3148 3149 return TRUE; 3150 } 3151 3152 dbus_bool_t 3153 bus_config_parser_test (const DBusString *test_data_dir) 3154 { 3155 if (test_data_dir == NULL || 3156 _dbus_string_get_length (test_data_dir) == 0) 3157 { 3158 printf ("No test data\n"); 3159 return TRUE; 3160 } 3161 3162 if (!test_default_session_servicedirs()) 3163 return FALSE; 3164 3165 if (!process_test_valid_subdir (test_data_dir, "valid-config-files", VALID)) 3166 return FALSE; 3167 3168 if (!process_test_valid_subdir (test_data_dir, "invalid-config-files", INVALID)) 3169 return FALSE; 3170 3171 if (!process_test_equiv_subdir (test_data_dir, "equiv-config-files")) 3172 return FALSE; 3173 3174 return TRUE; 3175 } 3176 3177 #endif /* DBUS_BUILD_TESTS */ 3178 3179