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