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