Home | History | Annotate | Download | only in bus
      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 
     35 typedef 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 
     48 typedef 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  */
     82 struct 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 
    124 static Element*
    125 push_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 
    147 static void
    148 element_free (Element *e)
    149 {
    150   if (e->type == ELEMENT_LIMIT)
    151     dbus_free (e->d.limit.name);
    152 
    153   dbus_free (e);
    154 }
    155 
    156 static void
    157 pop_element (BusConfigParser *parser)
    158 {
    159   Element *e;
    160 
    161   e = _dbus_list_pop_last (&parser->stack);
    162 
    163   element_free (e);
    164 }
    165 
    166 static Element*
    167 peek_element (BusConfigParser *parser)
    168 {
    169   Element *e;
    170 
    171   e = _dbus_list_get_last (&parser->stack);
    172 
    173   return e;
    174 }
    175 
    176 static ElementType
    177 top_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 
    189 static dbus_bool_t
    190 merge_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 
    232 static dbus_bool_t
    233 service_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 
    252 static dbus_bool_t
    253 service_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 
    263 static void
    264 service_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 
    278 static dbus_bool_t
    279 merge_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 
    341 static dbus_bool_t
    342 seen_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 
    359 BusConfigParser*
    360 bus_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 
    466 BusConfigParser *
    467 bus_config_parser_ref (BusConfigParser *parser)
    468 {
    469   _dbus_assert (parser->refcount > 0);
    470 
    471   parser->refcount += 1;
    472 
    473   return parser;
    474 }
    475 
    476 void
    477 bus_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 
    529 dbus_bool_t
    530 bus_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 
    548 typedef struct
    549 {
    550   const char  *name;
    551   const char **retloc;
    552 } LocateAttr;
    553 
    554 static dbus_bool_t
    555 locate_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 
    650 static dbus_bool_t
    651 check_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 
    668 static dbus_bool_t
    669 start_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 
   1131 static dbus_bool_t
   1132 append_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 
   1642 static dbus_bool_t
   1643 start_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 
   1688 static dbus_bool_t
   1689 start_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 
   1760 dbus_bool_t
   1761 bus_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 
   1825 static dbus_bool_t
   1826 set_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 
   1955 dbus_bool_t
   1956 bus_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 
   2048 static dbus_bool_t
   2049 all_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 
   2058 static dbus_bool_t
   2059 make_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 
   2079 static dbus_bool_t
   2080 include_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 
   2152 static dbus_bool_t
   2153 servicehelper_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 
   2186 static dbus_bool_t
   2187 include_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 
   2278 dbus_bool_t
   2279 bus_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 
   2579 dbus_bool_t
   2580 bus_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 
   2604 const char*
   2605 bus_config_parser_get_user (BusConfigParser *parser)
   2606 {
   2607   return parser->user;
   2608 }
   2609 
   2610 const char*
   2611 bus_config_parser_get_type (BusConfigParser *parser)
   2612 {
   2613   return parser->bus_type;
   2614 }
   2615 
   2616 DBusList**
   2617 bus_config_parser_get_addresses (BusConfigParser *parser)
   2618 {
   2619   return &parser->listen_on;
   2620 }
   2621 
   2622 DBusList**
   2623 bus_config_parser_get_mechanisms (BusConfigParser *parser)
   2624 {
   2625   return &parser->mechanisms;
   2626 }
   2627 
   2628 DBusList**
   2629 bus_config_parser_get_service_dirs (BusConfigParser *parser)
   2630 {
   2631   return &parser->service_dirs;
   2632 }
   2633 
   2634 DBusList**
   2635 bus_config_parser_get_conf_dirs (BusConfigParser *parser)
   2636 {
   2637   return &parser->conf_dirs;
   2638 }
   2639 
   2640 dbus_bool_t
   2641 bus_config_parser_get_fork (BusConfigParser   *parser)
   2642 {
   2643   return parser->fork;
   2644 }
   2645 
   2646 dbus_bool_t
   2647 bus_config_parser_get_syslog (BusConfigParser   *parser)
   2648 {
   2649   return parser->syslog;
   2650 }
   2651 
   2652 dbus_bool_t
   2653 bus_config_parser_get_keep_umask (BusConfigParser   *parser)
   2654 {
   2655   return parser->keep_umask;
   2656 }
   2657 
   2658 dbus_bool_t
   2659 bus_config_parser_get_allow_anonymous (BusConfigParser   *parser)
   2660 {
   2661   return parser->allow_anonymous;
   2662 }
   2663 
   2664 const char *
   2665 bus_config_parser_get_pidfile (BusConfigParser   *parser)
   2666 {
   2667   return parser->pidfile;
   2668 }
   2669 
   2670 const char *
   2671 bus_config_parser_get_servicehelper (BusConfigParser   *parser)
   2672 {
   2673   return parser->servicehelper;
   2674 }
   2675 
   2676 BusPolicy*
   2677 bus_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 */
   2691 void
   2692 bus_config_parser_get_limits (BusConfigParser *parser,
   2693                               BusLimits       *limits)
   2694 {
   2695   *limits = parser->limits;
   2696 }
   2697 
   2698 DBusHashTable*
   2699 bus_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 
   2715 typedef enum
   2716 {
   2717   VALID,
   2718   INVALID,
   2719   UNKNOWN
   2720 } Validity;
   2721 
   2722 static dbus_bool_t
   2723 do_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 
   2774 typedef struct
   2775 {
   2776   const DBusString *full_path;
   2777   Validity          validity;
   2778 } LoaderOomData;
   2779 
   2780 static dbus_bool_t
   2781 check_loader_oom_func (void *data)
   2782 {
   2783   LoaderOomData *d = data;
   2784 
   2785   return do_load (d->full_path, d->validity, TRUE);
   2786 }
   2787 
   2788 static dbus_bool_t
   2789 process_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 
   2901 static dbus_bool_t
   2902 bools_equal (dbus_bool_t a,
   2903 	     dbus_bool_t b)
   2904 {
   2905   return a ? b : !b;
   2906 }
   2907 
   2908 static dbus_bool_t
   2909 strings_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 
   2918 static dbus_bool_t
   2919 elements_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 
   2960 static dbus_bool_t
   2961 lists_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 
   2981 static dbus_bool_t
   2982 lists_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 
   3002 static dbus_bool_t
   3003 limits_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 
   3025 static dbus_bool_t
   3026 config_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 
   3069 static dbus_bool_t
   3070 all_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 
   3164 static dbus_bool_t
   3165 process_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 
   3241 static 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 
   3257 static dbus_bool_t
   3258 test_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 
   3370 static 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 
   3383 static dbus_bool_t
   3384 test_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 
   3496 dbus_bool_t
   3497 bus_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