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