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