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