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