Merge branch 'dbus-1.10'
[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           /* drop the rule on the floor */
1745           break;
1746           
1747         case POLICY_DEFAULT:
1748           if (!bus_policy_append_default_rule (parser->policy, rule))
1749             goto nomem;
1750           break;
1751         case POLICY_MANDATORY:
1752           if (!bus_policy_append_mandatory_rule (parser->policy, rule))
1753             goto nomem;
1754           break;
1755         case POLICY_USER:
1756           if (!BUS_POLICY_RULE_IS_PER_CLIENT (rule))
1757             {
1758               dbus_set_error (error, DBUS_ERROR_FAILED,
1759                               "<%s> rule cannot be per-user because it has bus-global semantics",
1760                               element_name);
1761               goto failed;
1762             }
1763           
1764           if (!bus_policy_append_user_rule (parser->policy, pe->d.policy.gid_uid_or_at_console,
1765                                             rule))
1766             goto nomem;
1767           break;
1768         case POLICY_GROUP:
1769           if (!BUS_POLICY_RULE_IS_PER_CLIENT (rule))
1770             {
1771               dbus_set_error (error, DBUS_ERROR_FAILED,
1772                               "<%s> rule cannot be per-group because it has bus-global semantics",
1773                               element_name);
1774               goto failed;
1775             }
1776           
1777           if (!bus_policy_append_group_rule (parser->policy, pe->d.policy.gid_uid_or_at_console,
1778                                              rule))
1779             goto nomem;
1780           break;
1781         
1782
1783         case POLICY_CONSOLE:
1784           if (!bus_policy_append_console_rule (parser->policy, pe->d.policy.gid_uid_or_at_console,
1785                                                rule))
1786             goto nomem;
1787           break;
1788         }
1789  
1790       bus_policy_rule_unref (rule);
1791       rule = NULL;
1792     }
1793   
1794   return TRUE;
1795
1796  nomem:
1797   BUS_SET_OOM (error);
1798  failed:
1799   if (rule)
1800     bus_policy_rule_unref (rule);
1801   return FALSE;
1802 }
1803
1804 static dbus_bool_t
1805 start_policy_child (BusConfigParser   *parser,
1806                     const char        *element_name,
1807                     const char       **attribute_names,
1808                     const char       **attribute_values,
1809                     DBusError         *error)
1810 {
1811   if (strcmp (element_name, "allow") == 0)
1812     {
1813       if (!append_rule_from_element (parser, element_name,
1814                                      attribute_names, attribute_values,
1815                                      TRUE, error))
1816         return FALSE;
1817       
1818       if (push_element (parser, ELEMENT_ALLOW) == NULL)
1819         {
1820           BUS_SET_OOM (error);
1821           return FALSE;
1822         }
1823       
1824       return TRUE;
1825     }
1826   else if (strcmp (element_name, "deny") == 0)
1827     {
1828       if (!append_rule_from_element (parser, element_name,
1829                                      attribute_names, attribute_values,
1830                                      FALSE, error))
1831         return FALSE;
1832       
1833       if (push_element (parser, ELEMENT_DENY) == NULL)
1834         {
1835           BUS_SET_OOM (error);
1836           return FALSE;
1837         }
1838       
1839       return TRUE;
1840     }
1841   else
1842     {
1843       dbus_set_error (error, DBUS_ERROR_FAILED,
1844                       "Element <%s> not allowed inside <%s> in configuration file",
1845                       element_name, "policy");
1846       return FALSE;
1847     }
1848 }
1849
1850 static dbus_bool_t
1851 start_selinux_child (BusConfigParser   *parser,
1852                      const char        *element_name,
1853                      const char       **attribute_names,
1854                      const char       **attribute_values,
1855                      DBusError         *error)
1856 {
1857   char *own_copy;
1858   char *context_copy;
1859
1860   own_copy = NULL;
1861   context_copy = NULL;
1862
1863   if (strcmp (element_name, "associate") == 0)
1864     {
1865       const char *own;
1866       const char *context;
1867       
1868       if (!locate_attributes (parser, "associate",
1869                               attribute_names,
1870                               attribute_values,
1871                               error,
1872                               "own", &own,
1873                               "context", &context,
1874                               NULL))
1875         return FALSE;
1876       
1877       if (push_element (parser, ELEMENT_ASSOCIATE) == NULL)
1878         {
1879           BUS_SET_OOM (error);
1880           return FALSE;
1881         }
1882
1883       if (own == NULL || context == NULL)
1884         {
1885           dbus_set_error (error, DBUS_ERROR_FAILED,
1886                           "Element <associate> must have attributes own=\"<servicename>\" and context=\"<selinux context>\"");
1887           return FALSE;
1888         }
1889
1890       own_copy = _dbus_strdup (own);
1891       if (own_copy == NULL)
1892         goto oom;
1893       context_copy = _dbus_strdup (context);
1894       if (context_copy == NULL)
1895         goto oom;
1896
1897       if (!_dbus_hash_table_insert_string (parser->service_context_table,
1898                                            own_copy, context_copy))
1899         goto oom;
1900
1901       return TRUE;
1902     }
1903   else
1904     {
1905       dbus_set_error (error, DBUS_ERROR_FAILED,
1906                       "Element <%s> not allowed inside <%s> in configuration file",
1907                       element_name, "selinux");
1908       return FALSE;
1909     }
1910
1911  oom:
1912   if (own_copy)
1913     dbus_free (own_copy);
1914
1915   if (context_copy)  
1916     dbus_free (context_copy);
1917
1918   BUS_SET_OOM (error);
1919   return FALSE;
1920 }
1921
1922 dbus_bool_t
1923 bus_config_parser_start_element (BusConfigParser   *parser,
1924                                  const char        *element_name,
1925                                  const char       **attribute_names,
1926                                  const char       **attribute_values,
1927                                  DBusError         *error)
1928 {
1929   ElementType t;
1930
1931   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1932
1933   /* printf ("START: %s\n", element_name); */
1934   
1935   t = top_element_type (parser);
1936
1937   if (t == ELEMENT_NONE)
1938     {
1939       if (strcmp (element_name, "busconfig") == 0)
1940         {
1941           if (!check_no_attributes (parser, "busconfig", attribute_names, attribute_values, error))
1942             return FALSE;
1943           
1944           if (push_element (parser, ELEMENT_BUSCONFIG) == NULL)
1945             {
1946               BUS_SET_OOM (error);
1947               return FALSE;
1948             }
1949
1950           return TRUE;
1951         }
1952       else
1953         {
1954           dbus_set_error (error, DBUS_ERROR_FAILED,
1955                           "Unknown element <%s> at root of configuration file",
1956                           element_name);
1957           return FALSE;
1958         }
1959     }
1960   else if (t == ELEMENT_BUSCONFIG)
1961     {
1962       return start_busconfig_child (parser, element_name,
1963                                     attribute_names, attribute_values,
1964                                     error);
1965     }
1966   else if (t == ELEMENT_POLICY)
1967     {
1968       return start_policy_child (parser, element_name,
1969                                  attribute_names, attribute_values,
1970                                  error);
1971     }
1972   else if (t == ELEMENT_SELINUX)
1973     {
1974       return start_selinux_child (parser, element_name,
1975                                   attribute_names, attribute_values,
1976                                   error);
1977     }
1978   else
1979     {
1980       dbus_set_error (error, DBUS_ERROR_FAILED,
1981                       "Element <%s> is not allowed in this context",
1982                       element_name);
1983       return FALSE;
1984     }  
1985 }
1986
1987 static dbus_bool_t
1988 set_limit (BusConfigParser *parser,
1989            const char      *name,
1990            long             value,
1991            DBusError       *error)
1992 {
1993   dbus_bool_t must_be_positive;
1994   dbus_bool_t must_be_int;
1995
1996   must_be_int = FALSE;
1997   must_be_positive = FALSE;
1998   
1999   if (strcmp (name, "max_incoming_bytes") == 0)
2000     {
2001       must_be_positive = TRUE;
2002       parser->limits.max_incoming_bytes = value;
2003     }
2004   else if (strcmp (name, "max_incoming_unix_fds") == 0)
2005     {
2006       must_be_positive = TRUE;
2007       parser->limits.max_incoming_unix_fds = value;
2008     }
2009   else if (strcmp (name, "max_outgoing_bytes") == 0)
2010     {
2011       must_be_positive = TRUE;
2012       parser->limits.max_outgoing_bytes = value;
2013     }
2014   else if (strcmp (name, "max_outgoing_unix_fds") == 0)
2015     {
2016       must_be_positive = TRUE;
2017       parser->limits.max_outgoing_unix_fds = value;
2018     }
2019   else if (strcmp (name, "max_message_size") == 0)
2020     {
2021       must_be_positive = TRUE;
2022       parser->limits.max_message_size = value;
2023     }
2024   else if (strcmp (name, "max_message_unix_fds") == 0)
2025     {
2026       must_be_positive = TRUE;
2027       parser->limits.max_message_unix_fds = value;
2028     }
2029   else if (strcmp (name, "service_start_timeout") == 0)
2030     {
2031       must_be_positive = TRUE;
2032       must_be_int = TRUE;
2033       parser->limits.activation_timeout = value;
2034     }
2035   else if (strcmp (name, "auth_timeout") == 0)
2036     {
2037       must_be_positive = TRUE;
2038       must_be_int = TRUE;
2039       parser->limits.auth_timeout = value;
2040     }
2041   else if (strcmp (name, "pending_fd_timeout") == 0)
2042     {
2043       must_be_positive = TRUE;
2044       must_be_int = TRUE;
2045       parser->limits.pending_fd_timeout = value;
2046     }
2047   else if (strcmp (name, "reply_timeout") == 0)
2048     {
2049       must_be_positive = TRUE;
2050       must_be_int = TRUE;
2051       parser->limits.reply_timeout = value;
2052     }
2053   else if (strcmp (name, "max_completed_connections") == 0)
2054     {
2055       must_be_positive = TRUE;
2056       must_be_int = TRUE;
2057       parser->limits.max_completed_connections = value;
2058     }
2059   else if (strcmp (name, "max_incomplete_connections") == 0)
2060     {
2061       must_be_positive = TRUE;
2062       must_be_int = TRUE;
2063       parser->limits.max_incomplete_connections = value;
2064     }
2065   else if (strcmp (name, "max_connections_per_user") == 0)
2066     {
2067       must_be_positive = TRUE;
2068       must_be_int = TRUE;
2069       parser->limits.max_connections_per_user = value;
2070     }
2071   else if (strcmp (name, "max_pending_service_starts") == 0)
2072     {
2073       must_be_positive = TRUE;
2074       must_be_int = TRUE;
2075       parser->limits.max_pending_activations = value;
2076     }
2077   else if (strcmp (name, "max_names_per_connection") == 0)
2078     {
2079       must_be_positive = TRUE;
2080       must_be_int = TRUE;
2081       parser->limits.max_services_per_connection = value;
2082     }
2083   else if (strcmp (name, "max_match_rules_per_connection") == 0)
2084     {
2085       must_be_positive = TRUE;
2086       must_be_int = TRUE;
2087       parser->limits.max_match_rules_per_connection = value;
2088     }
2089   else if (strcmp (name, "max_replies_per_connection") == 0)
2090     {
2091       must_be_positive = TRUE;
2092       must_be_int = TRUE;
2093       parser->limits.max_replies_per_connection = value;
2094     }
2095   else
2096     {
2097       dbus_set_error (error, DBUS_ERROR_FAILED,
2098                       "There is no limit called \"%s\"\n",
2099                       name);
2100       return FALSE;
2101     }
2102   
2103   if (must_be_positive && value < 0)
2104     {
2105       dbus_set_error (error, DBUS_ERROR_FAILED,
2106                       "<limit name=\"%s\"> must be a positive number\n",
2107                       name);
2108       return FALSE;
2109     }
2110
2111   if (must_be_int &&
2112       (value < _DBUS_INT_MIN || value > _DBUS_INT_MAX))
2113     {
2114       dbus_set_error (error, DBUS_ERROR_FAILED,
2115                       "<limit name=\"%s\"> value is too large\n",
2116                       name);
2117       return FALSE;
2118     }
2119
2120   return TRUE;  
2121 }
2122
2123 dbus_bool_t
2124 bus_config_parser_end_element (BusConfigParser   *parser,
2125                                const char        *element_name,
2126                                DBusError         *error)
2127 {
2128   ElementType t;
2129   const char *n;
2130   Element *e;
2131
2132   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2133
2134   /* printf ("END: %s\n", element_name); */
2135   
2136   t = top_element_type (parser);
2137
2138   if (t == ELEMENT_NONE)
2139     {
2140       /* should probably be an assertion failure but
2141        * being paranoid about XML parsers
2142        */
2143       dbus_set_error (error, DBUS_ERROR_FAILED,
2144                       "XML parser ended element with no element on the stack");
2145       return FALSE;
2146     }
2147
2148   n = bus_config_parser_element_type_to_name (t);
2149   _dbus_assert (n != NULL);
2150   if (strcmp (n, element_name) != 0)
2151     {
2152       /* should probably be an assertion failure but
2153        * being paranoid about XML parsers
2154        */
2155       dbus_set_error (error, DBUS_ERROR_FAILED,
2156                       "XML element <%s> ended but topmost element on the stack was <%s>",
2157                       element_name, n);
2158       return FALSE;
2159     }
2160
2161   e = peek_element (parser);
2162   _dbus_assert (e != NULL);
2163
2164   switch (e->type)
2165     {
2166     case ELEMENT_NONE:
2167       _dbus_assert_not_reached ("element in stack has no type");
2168       break;
2169
2170     case ELEMENT_INCLUDE:
2171     case ELEMENT_USER:
2172     case ELEMENT_CONFIGTYPE:
2173     case ELEMENT_LISTEN:
2174     case ELEMENT_PIDFILE:
2175     case ELEMENT_AUTH:
2176     case ELEMENT_SERVICEDIR:
2177     case ELEMENT_SERVICEHELPER:
2178     case ELEMENT_INCLUDEDIR:
2179     case ELEMENT_LIMIT:
2180       if (!e->had_content)
2181         {
2182           dbus_set_error (error, DBUS_ERROR_FAILED,
2183                           "XML element <%s> was expected to have content inside it",
2184                           bus_config_parser_element_type_to_name (e->type));
2185           return FALSE;
2186         }
2187
2188       if (e->type == ELEMENT_LIMIT)
2189         {
2190           if (!set_limit (parser, e->d.limit.name, e->d.limit.value,
2191                           error))
2192             return FALSE;
2193         }
2194       break;
2195
2196     case ELEMENT_BUSCONFIG:
2197     case ELEMENT_POLICY:
2198     case ELEMENT_ALLOW:
2199     case ELEMENT_DENY:
2200     case ELEMENT_FORK:
2201     case ELEMENT_SYSLOG:
2202     case ELEMENT_KEEP_UMASK:
2203     case ELEMENT_SELINUX:
2204     case ELEMENT_ASSOCIATE:
2205     case ELEMENT_STANDARD_SESSION_SERVICEDIRS:
2206     case ELEMENT_STANDARD_SYSTEM_SERVICEDIRS:
2207     case ELEMENT_ALLOW_ANONYMOUS:
2208     case ELEMENT_APPARMOR:
2209       break;
2210     }
2211
2212   pop_element (parser);
2213
2214   return TRUE;
2215 }
2216
2217 static dbus_bool_t
2218 all_whitespace (const DBusString *str)
2219 {
2220   int i;
2221
2222   _dbus_string_skip_white (str, 0, &i);
2223
2224   return i == _dbus_string_get_length (str);
2225 }
2226
2227 static dbus_bool_t
2228 make_full_path (const DBusString *basedir,
2229                 const DBusString *filename,
2230                 DBusString       *full_path)
2231 {
2232   if (_dbus_path_is_absolute (filename))
2233     {
2234       if (!_dbus_string_copy (filename, 0, full_path, 0))
2235         return FALSE;
2236     }
2237   else
2238     {
2239       if (!_dbus_string_copy (basedir, 0, full_path, 0))
2240         return FALSE;
2241       
2242       if (!_dbus_concat_dir_and_file (full_path, filename))
2243         return FALSE;
2244     }
2245
2246   if (!_dbus_replace_install_prefix (full_path))
2247     return FALSE;
2248
2249   return TRUE;
2250 }
2251
2252 static dbus_bool_t
2253 include_file (BusConfigParser   *parser,
2254               const DBusString  *filename,
2255               dbus_bool_t        ignore_missing,
2256               DBusError         *error)
2257 {
2258   /* FIXME good test case for this would load each config file in the
2259    * test suite both alone, and as an include, and check
2260    * that the result is the same
2261    */
2262   BusConfigParser *included;
2263   const char *filename_str;
2264   DBusError tmp_error;
2265         
2266   dbus_error_init (&tmp_error);
2267
2268   filename_str = _dbus_string_get_const_data (filename);
2269
2270   /* Check to make sure this file hasn't already been included. */
2271   if (seen_include (parser, filename))
2272     {
2273       dbus_set_error (error, DBUS_ERROR_FAILED,
2274                       "Circular inclusion of file '%s'",
2275                       filename_str);
2276       return FALSE;
2277     }
2278   
2279   if (! _dbus_list_append (&parser->included_files, (void *) filename_str))
2280     {
2281       BUS_SET_OOM (error);
2282       return FALSE;
2283     }
2284
2285   /* Since parser is passed in as the parent, included
2286      inherits parser's limits. */
2287   included = bus_config_load (filename, FALSE, parser, &tmp_error);
2288
2289   _dbus_list_pop_last (&parser->included_files);
2290
2291   if (included == NULL)
2292     {
2293       _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
2294
2295       if (dbus_error_has_name (&tmp_error, DBUS_ERROR_FILE_NOT_FOUND) &&
2296           ignore_missing)
2297         {
2298           dbus_error_free (&tmp_error);
2299           return TRUE;
2300         }
2301       else
2302         {
2303           dbus_move_error (&tmp_error, error);
2304           return FALSE;
2305         }
2306     }
2307   else
2308     {
2309       _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
2310
2311       if (!merge_included (parser, included, error))
2312         {
2313           bus_config_parser_unref (included);
2314           return FALSE;
2315         }
2316
2317       /* Copy included's limits back to parser. */
2318       parser->limits = included->limits;
2319
2320       bus_config_parser_unref (included);
2321       return TRUE;
2322     }
2323 }
2324
2325 static dbus_bool_t
2326 servicehelper_path (BusConfigParser   *parser,
2327                     const DBusString  *filename,
2328                     DBusError         *error)
2329 {
2330   const char *filename_str;
2331   char *servicehelper;
2332
2333   filename_str = _dbus_string_get_const_data (filename);
2334
2335   /* copy to avoid overwriting with NULL on OOM */
2336   servicehelper = _dbus_strdup (filename_str);
2337
2338   /* check for OOM */
2339   if (servicehelper == NULL)
2340     {
2341       BUS_SET_OOM (error);
2342       return FALSE;
2343     }
2344
2345   /* save the latest servicehelper only if not OOM */
2346   dbus_free (parser->servicehelper);
2347   parser->servicehelper = servicehelper;
2348
2349   /* We don't check whether the helper exists; instead we
2350    * would just fail to ever activate anything if it doesn't.
2351    * This allows an admin to fix the problem if it doesn't exist.
2352    * It also allows the parser test suite to successfully parse
2353    * test cases without installing the helper. ;-)
2354    */
2355   
2356   return TRUE;
2357 }
2358
2359 static dbus_bool_t
2360 include_dir (BusConfigParser   *parser,
2361              const DBusString  *dirname,
2362              DBusError         *error)
2363 {
2364   DBusString filename;
2365   dbus_bool_t retval;
2366   DBusError tmp_error;
2367   DBusDirIter *dir;
2368   char *s;
2369   
2370   if (!_dbus_string_init (&filename))
2371     {
2372       BUS_SET_OOM (error);
2373       return FALSE;
2374     }
2375
2376   retval = FALSE;
2377   
2378   dir = _dbus_directory_open (dirname, error);
2379
2380   if (dir == NULL)
2381     {
2382       if (dbus_error_has_name (error, DBUS_ERROR_FILE_NOT_FOUND))
2383         {
2384           dbus_error_free (error);
2385           goto success;
2386         }
2387       else
2388         goto failed;
2389     }
2390
2391   dbus_error_init (&tmp_error);
2392   while (_dbus_directory_get_next_file (dir, &filename, &tmp_error))
2393     {
2394       DBusString full_path;
2395
2396       if (!_dbus_string_init (&full_path))
2397         {
2398           BUS_SET_OOM (error);
2399           goto failed;
2400         }
2401
2402       if (!_dbus_string_copy (dirname, 0, &full_path, 0))
2403         {
2404           BUS_SET_OOM (error);
2405           _dbus_string_free (&full_path);
2406           goto failed;
2407         }      
2408
2409       if (!_dbus_concat_dir_and_file (&full_path, &filename))
2410         {
2411           BUS_SET_OOM (error);
2412           _dbus_string_free (&full_path);
2413           goto failed;
2414         }
2415       
2416       if (_dbus_string_ends_with_c_str (&full_path, ".conf"))
2417         {
2418           if (!include_file (parser, &full_path, TRUE, error))
2419             {
2420               if (dbus_error_is_set (error))
2421                 {
2422                   /* We use both syslog and stderr here, because this is
2423                    * the configuration parser, so we don't yet know whether
2424                    * this bus is going to want to write to syslog! Err on
2425                    * the side of making sure the message gets to the sysadmin
2426                    * somehow. */
2427                   _dbus_init_system_log ("dbus-daemon",
2428                       DBUS_LOG_FLAGS_STDERR | DBUS_LOG_FLAGS_SYSTEM_LOG);
2429                   _dbus_log (DBUS_SYSTEM_LOG_INFO,
2430                              "Encountered error '%s' while parsing '%s'",
2431                              error->message,
2432                              _dbus_string_get_const_data (&full_path));
2433                   dbus_error_free (error);
2434                 }
2435             }
2436         }
2437
2438       _dbus_string_free (&full_path);
2439     }
2440
2441   if (dbus_error_is_set (&tmp_error))
2442     {
2443       dbus_move_error (&tmp_error, error);
2444       goto failed;
2445     }
2446
2447
2448   if (!_dbus_string_copy_data (dirname, &s))
2449     {
2450       BUS_SET_OOM (error);
2451       goto failed;
2452     }
2453
2454   if (!_dbus_list_append (&parser->conf_dirs, s))
2455     {
2456       dbus_free (s);
2457       BUS_SET_OOM (error);
2458       goto failed;
2459     }
2460
2461  success:
2462   retval = TRUE;
2463   
2464  failed:
2465   _dbus_string_free (&filename);
2466   
2467   if (dir)
2468     _dbus_directory_close (dir);
2469
2470   return retval;
2471 }
2472
2473 dbus_bool_t
2474 bus_config_parser_content (BusConfigParser   *parser,
2475                            const DBusString  *content,
2476                            DBusError         *error)
2477 {
2478   Element *e;
2479
2480   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2481
2482 #if 0
2483   {
2484     const char *c_str;
2485     
2486     _dbus_string_get_const_data (content, &c_str);
2487
2488     printf ("CONTENT %d bytes: %s\n", _dbus_string_get_length (content), c_str);
2489   }
2490 #endif
2491   
2492   e = peek_element (parser);
2493   if (e == NULL)
2494     {
2495       dbus_set_error (error, DBUS_ERROR_FAILED,
2496                       "Text content outside of any XML element in configuration file");
2497       return FALSE;
2498     }
2499   else if (e->had_content)
2500     {
2501       _dbus_assert_not_reached ("Element had multiple content blocks");
2502       return FALSE;
2503     }
2504
2505   switch (top_element_type (parser))
2506     {
2507     case ELEMENT_NONE:
2508       _dbus_assert_not_reached ("element at top of stack has no type");
2509       return FALSE;
2510
2511     case ELEMENT_BUSCONFIG:
2512     case ELEMENT_POLICY:
2513     case ELEMENT_ALLOW:
2514     case ELEMENT_DENY:
2515     case ELEMENT_FORK:
2516     case ELEMENT_SYSLOG:
2517     case ELEMENT_KEEP_UMASK:
2518     case ELEMENT_STANDARD_SESSION_SERVICEDIRS:    
2519     case ELEMENT_STANDARD_SYSTEM_SERVICEDIRS:    
2520     case ELEMENT_ALLOW_ANONYMOUS:
2521     case ELEMENT_SELINUX:
2522     case ELEMENT_ASSOCIATE:
2523     case ELEMENT_APPARMOR:
2524       if (all_whitespace (content))
2525         return TRUE;
2526       else
2527         {
2528           dbus_set_error (error, DBUS_ERROR_FAILED,
2529                           "No text content expected inside XML element %s in configuration file",
2530                           bus_config_parser_element_type_to_name (top_element_type (parser)));
2531           return FALSE;
2532         }
2533
2534     case ELEMENT_PIDFILE:
2535       {
2536         char *s;
2537
2538         e->had_content = TRUE;
2539         
2540         if (!_dbus_string_copy_data (content, &s))
2541           goto nomem;
2542           
2543         dbus_free (parser->pidfile);
2544         parser->pidfile = s;
2545       }
2546       break;
2547
2548     case ELEMENT_INCLUDE:
2549       {
2550         DBusString full_path, selinux_policy_root;
2551
2552         e->had_content = TRUE;
2553
2554         if (e->d.include.if_selinux_enabled
2555             && !bus_selinux_enabled ())
2556           break;
2557
2558         if (!_dbus_string_init (&full_path))
2559           goto nomem;
2560
2561         if (e->d.include.selinux_root_relative)
2562           {
2563             if (!bus_selinux_get_policy_root ())
2564               {
2565                 dbus_set_error (error, DBUS_ERROR_FAILED,
2566                                 "Could not determine SELinux policy root for relative inclusion");
2567                 _dbus_string_free (&full_path);
2568                 return FALSE;
2569               }
2570             _dbus_string_init_const (&selinux_policy_root,
2571                                      bus_selinux_get_policy_root ());
2572             if (!make_full_path (&selinux_policy_root, content, &full_path))
2573               {
2574                 _dbus_string_free (&full_path);
2575                 goto nomem;
2576               }
2577           }
2578         else if (!make_full_path (&parser->basedir, content, &full_path))
2579           {
2580             _dbus_string_free (&full_path);
2581             goto nomem;
2582           }
2583
2584         if (!include_file (parser, &full_path,
2585                            e->d.include.ignore_missing, error))
2586           {
2587             _dbus_string_free (&full_path);
2588             return FALSE;
2589           }
2590
2591         _dbus_string_free (&full_path);
2592       }
2593       break;
2594
2595     case ELEMENT_SERVICEHELPER:
2596       {
2597         DBusString full_path;
2598         
2599         e->had_content = TRUE;
2600
2601         if (!_dbus_string_init (&full_path))
2602           goto nomem;
2603         
2604         if (!make_full_path (&parser->basedir, content, &full_path))
2605           {
2606             _dbus_string_free (&full_path);
2607             goto nomem;
2608           }
2609
2610         if (!servicehelper_path (parser, &full_path, error))
2611           {
2612             _dbus_string_free (&full_path);
2613             return FALSE;
2614           }
2615
2616         _dbus_string_free (&full_path);
2617       }
2618       break;
2619       
2620     case ELEMENT_INCLUDEDIR:
2621       {
2622         DBusString full_path;
2623         
2624         e->had_content = TRUE;
2625
2626         if (!_dbus_string_init (&full_path))
2627           goto nomem;
2628         
2629         if (!make_full_path (&parser->basedir, content, &full_path))
2630           {
2631             _dbus_string_free (&full_path);
2632             goto nomem;
2633           }
2634         
2635         if (!include_dir (parser, &full_path, error))
2636           {
2637             _dbus_string_free (&full_path);
2638             return FALSE;
2639           }
2640
2641         _dbus_string_free (&full_path);
2642       }
2643       break;
2644       
2645     case ELEMENT_USER:
2646       {
2647         char *s;
2648
2649         e->had_content = TRUE;
2650         
2651         if (!_dbus_string_copy_data (content, &s))
2652           goto nomem;
2653           
2654         dbus_free (parser->user);
2655         parser->user = s;
2656       }
2657       break;
2658
2659     case ELEMENT_CONFIGTYPE:
2660       {
2661         char *s;
2662
2663         e->had_content = TRUE;
2664
2665         if (!_dbus_string_copy_data (content, &s))
2666           goto nomem;
2667         
2668         dbus_free (parser->bus_type);
2669         parser->bus_type = s;
2670       }
2671       break;
2672       
2673     case ELEMENT_LISTEN:
2674       {
2675         char *s;
2676
2677         e->had_content = TRUE;
2678         
2679         if (!_dbus_string_copy_data (content, &s))
2680           goto nomem;
2681
2682         if (!_dbus_list_append (&parser->listen_on,
2683                                 s))
2684           {
2685             dbus_free (s);
2686             goto nomem;
2687           }
2688       }
2689       break;
2690
2691     case ELEMENT_AUTH:
2692       {
2693         char *s;
2694         
2695         e->had_content = TRUE;
2696
2697         if (!_dbus_string_copy_data (content, &s))
2698           goto nomem;
2699
2700         if (!_dbus_list_append (&parser->mechanisms,
2701                                 s))
2702           {
2703             dbus_free (s);
2704             goto nomem;
2705           }
2706       }
2707       break;
2708
2709     case ELEMENT_SERVICEDIR:
2710       {
2711         char *s;
2712         BusConfigServiceDir *dir;
2713         DBusString full_path;
2714         DBusList *link;
2715
2716         e->had_content = TRUE;
2717
2718         if (!_dbus_string_init (&full_path))
2719           goto nomem;
2720         
2721         if (!make_full_path (&parser->basedir, content, &full_path))
2722           {
2723             _dbus_string_free (&full_path);
2724             goto nomem;
2725           }
2726         
2727         if (!_dbus_string_copy_data (&full_path, &s))
2728           {
2729             _dbus_string_free (&full_path);
2730             goto nomem;
2731           }
2732
2733         /* <servicedir/> has traditionally implied that we watch the
2734          * directory with inotify, and allow service files whose names do not
2735          * match the bus name */
2736         dir = bus_config_service_dir_new_take (s, BUS_SERVICE_DIR_FLAGS_NONE);
2737
2738         if (dir == NULL)
2739           {
2740             _dbus_string_free (&full_path);
2741             dbus_free (s);
2742             goto nomem;
2743           }
2744
2745         link = _dbus_list_alloc_link (dir);
2746
2747         if (link == NULL)
2748           {
2749             _dbus_string_free (&full_path);
2750             bus_config_service_dir_free (dir);
2751             goto nomem;
2752           }
2753
2754         /* cannot fail */
2755         service_dirs_append_link_unique_or_free (&parser->service_dirs, link);
2756         _dbus_string_free (&full_path);
2757       }
2758       break;
2759
2760     case ELEMENT_LIMIT:
2761       {
2762         long val;
2763
2764         e->had_content = TRUE;
2765
2766         val = 0;
2767         if (!_dbus_string_parse_int (content, 0, &val, NULL))
2768           {
2769             dbus_set_error (error, DBUS_ERROR_FAILED,
2770                             "<limit name=\"%s\"> element has invalid value (could not parse as integer)",
2771                             e->d.limit.name);
2772             return FALSE;
2773           }
2774
2775         e->d.limit.value = val;
2776
2777         _dbus_verbose ("Loaded value %ld for limit %s\n",
2778                        e->d.limit.value,
2779                        e->d.limit.name);
2780       }
2781       break;
2782     }
2783
2784   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2785   return TRUE;
2786
2787  nomem:
2788   BUS_SET_OOM (error);
2789   return FALSE;
2790 }
2791
2792 dbus_bool_t
2793 bus_config_parser_finished (BusConfigParser   *parser,
2794                             DBusError         *error)
2795 {
2796   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2797
2798   if (parser->stack != NULL)
2799     {
2800       dbus_set_error (error, DBUS_ERROR_FAILED,
2801                       "Element <%s> was not closed in configuration file",
2802                       bus_config_parser_element_type_to_name (top_element_type (parser)));
2803
2804       return FALSE;
2805     }
2806
2807   if (parser->is_toplevel && parser->listen_on == NULL)
2808     {
2809       dbus_set_error (error, DBUS_ERROR_FAILED,
2810                       "Configuration file needs one or more <listen> elements giving addresses"); 
2811       return FALSE;
2812     }
2813   
2814   return TRUE;
2815 }
2816
2817 const char*
2818 bus_config_parser_get_user (BusConfigParser *parser)
2819 {
2820   return parser->user;
2821 }
2822
2823 const char*
2824 bus_config_parser_get_type (BusConfigParser *parser)
2825 {
2826   return parser->bus_type;
2827 }
2828
2829 DBusList**
2830 bus_config_parser_get_addresses (BusConfigParser *parser)
2831 {
2832   return &parser->listen_on;
2833 }
2834
2835 DBusList**
2836 bus_config_parser_get_mechanisms (BusConfigParser *parser)
2837 {
2838   return &parser->mechanisms;
2839 }
2840
2841 DBusList**
2842 bus_config_parser_get_service_dirs (BusConfigParser *parser)
2843 {
2844   return &parser->service_dirs;
2845 }
2846
2847 DBusList**
2848 bus_config_parser_get_conf_dirs (BusConfigParser *parser)
2849 {
2850   return &parser->conf_dirs;
2851 }
2852
2853 dbus_bool_t
2854 bus_config_parser_get_fork (BusConfigParser   *parser)
2855 {
2856   return parser->fork;
2857 }
2858
2859 dbus_bool_t
2860 bus_config_parser_get_syslog (BusConfigParser   *parser)
2861 {
2862   return parser->syslog;
2863 }
2864
2865 dbus_bool_t
2866 bus_config_parser_get_keep_umask (BusConfigParser   *parser)
2867 {
2868   return parser->keep_umask;
2869 }
2870
2871 dbus_bool_t
2872 bus_config_parser_get_allow_anonymous (BusConfigParser   *parser)
2873 {
2874   return parser->allow_anonymous;
2875 }
2876
2877 const char *
2878 bus_config_parser_get_pidfile (BusConfigParser   *parser)
2879 {
2880   return parser->pidfile;
2881 }
2882
2883 const char *
2884 bus_config_parser_get_servicehelper (BusConfigParser   *parser)
2885 {
2886   return parser->servicehelper;
2887 }
2888
2889 BusPolicy*
2890 bus_config_parser_steal_policy (BusConfigParser *parser)
2891 {
2892   BusPolicy *policy;
2893
2894   _dbus_assert (parser->policy != NULL); /* can only steal the policy 1 time */
2895   
2896   policy = parser->policy;
2897
2898   parser->policy = NULL;
2899
2900   return policy;
2901 }
2902
2903 /* Overwrite any limits that were set in the configuration file */
2904 void
2905 bus_config_parser_get_limits (BusConfigParser *parser,
2906                               BusLimits       *limits)
2907 {
2908   *limits = parser->limits;
2909 }
2910
2911 DBusHashTable*
2912 bus_config_parser_steal_service_context_table (BusConfigParser *parser)
2913 {
2914   DBusHashTable *table;
2915
2916   _dbus_assert (parser->service_context_table != NULL); /* can only steal once */
2917
2918   table = parser->service_context_table;
2919
2920   parser->service_context_table = NULL;
2921
2922   return table;
2923 }
2924
2925 /*
2926  * Return a list of the directories that should be watched with inotify,
2927  * as strings. The list might be empty and is in arbitrary order.
2928  *
2929  * The list must be empty on entry. On success, the links are owned by the
2930  * caller and must be freed, but the data in each link remains owned by
2931  * the BusConfigParser and must not be freed: in GObject-Introspection
2932  * notation, it is (transfer container).
2933  */
2934 dbus_bool_t
2935 bus_config_parser_get_watched_dirs (BusConfigParser *parser,
2936                                     DBusList **watched_dirs)
2937 {
2938   DBusList *link;
2939
2940   _dbus_assert (*watched_dirs == NULL);
2941
2942   for (link = _dbus_list_get_first_link (&parser->conf_dirs);
2943        link != NULL;
2944        link = _dbus_list_get_next_link (&parser->conf_dirs, link))
2945     {
2946       if (!_dbus_list_append (watched_dirs, link->data))
2947         goto oom;
2948     }
2949
2950   for (link = _dbus_list_get_first_link (&parser->service_dirs);
2951        link != NULL;
2952        link = _dbus_list_get_next_link (&parser->service_dirs, link))
2953     {
2954       BusConfigServiceDir *dir = link->data;
2955
2956       if (dir->flags & BUS_SERVICE_DIR_FLAGS_NO_WATCH)
2957         continue;
2958
2959       if (!_dbus_list_append (watched_dirs, dir->path))
2960         goto oom;
2961     }
2962
2963   return TRUE;
2964
2965 oom:
2966   _dbus_list_clear (watched_dirs);
2967   return FALSE;
2968 }
2969
2970 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
2971 #include <stdio.h>
2972
2973 typedef enum
2974 {
2975   VALID,
2976   INVALID,
2977   UNKNOWN
2978 } Validity;
2979
2980 static dbus_bool_t
2981 do_check_own_rules (BusPolicy  *policy)
2982 {
2983   const struct {
2984     const char *name;
2985     dbus_bool_t allowed;
2986   } checks[] = {
2987     {"org.freedesktop", FALSE},
2988     {"org.freedesktop.ManySystem", FALSE},
2989     {"org.freedesktop.ManySystems", TRUE},
2990     {"org.freedesktop.ManySystems.foo", TRUE},
2991     {"org.freedesktop.ManySystems.foo.bar", TRUE},
2992     {"org.freedesktop.ManySystems2", FALSE},
2993     {"org.freedesktop.ManySystems2.foo", FALSE},
2994     {"org.freedesktop.ManySystems2.foo.bar", FALSE},
2995     {NULL, FALSE}
2996   };
2997   int i = 0;
2998
2999   while (checks[i].name)
3000     {
3001       DBusString service_name;
3002       dbus_bool_t ret;
3003
3004       if (!_dbus_string_init (&service_name))
3005         _dbus_assert_not_reached ("couldn't init string");
3006       if (!_dbus_string_append (&service_name, checks[i].name))
3007         _dbus_assert_not_reached ("couldn't append string");
3008
3009       ret = bus_policy_check_can_own (policy, &service_name);
3010       printf ("        Check name %s: %s\n", checks[i].name,
3011               ret ? "allowed" : "not allowed");
3012       if (checks[i].allowed && !ret)
3013         {
3014           _dbus_warn ("Cannot own %s", checks[i].name);
3015           return FALSE;
3016         }
3017       if (!checks[i].allowed && ret)
3018         {
3019           _dbus_warn ("Can own %s", checks[i].name);
3020           return FALSE;
3021         }
3022       _dbus_string_free (&service_name);
3023
3024       i++;
3025     }
3026
3027   return TRUE;
3028 }
3029
3030 static dbus_bool_t
3031 do_load (const DBusString *full_path,
3032          Validity          validity,
3033          dbus_bool_t       oom_possible,
3034          dbus_bool_t       check_own_rules)
3035 {
3036   BusConfigParser *parser;
3037   DBusError error;
3038
3039   dbus_error_init (&error);
3040
3041   parser = bus_config_load (full_path, TRUE, NULL, &error);
3042   if (parser == NULL)
3043     {
3044       _DBUS_ASSERT_ERROR_IS_SET (&error);
3045
3046       if (oom_possible &&
3047           dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
3048         {
3049           _dbus_verbose ("Failed to load valid file due to OOM\n");
3050           dbus_error_free (&error);
3051           return TRUE;
3052         }
3053       else if (validity == VALID)
3054         {
3055           _dbus_warn ("Failed to load valid file but still had memory: %s",
3056                       error.message);
3057
3058           dbus_error_free (&error);
3059           return FALSE;
3060         }
3061       else
3062         {
3063           dbus_error_free (&error);
3064           return TRUE;
3065         }
3066     }
3067   else
3068     {
3069       _DBUS_ASSERT_ERROR_IS_CLEAR (&error);
3070
3071       if (check_own_rules && do_check_own_rules (parser->policy) == FALSE)
3072         {
3073           return FALSE;
3074         }
3075
3076       bus_config_parser_unref (parser);
3077
3078       if (validity == INVALID)
3079         {
3080           _dbus_warn ("Accepted invalid file");
3081           return FALSE;
3082         }
3083
3084       return TRUE;
3085     }
3086 }
3087
3088 typedef struct
3089 {
3090   const DBusString *full_path;
3091   Validity          validity;
3092   dbus_bool_t       check_own_rules;
3093 } LoaderOomData;
3094
3095 static dbus_bool_t
3096 check_loader_oom_func (void *data)
3097 {
3098   LoaderOomData *d = data;
3099
3100   return do_load (d->full_path, d->validity, TRUE, d->check_own_rules);
3101 }
3102
3103 static dbus_bool_t
3104 process_test_valid_subdir (const DBusString *test_base_dir,
3105                            const char       *subdir,
3106                            Validity          validity)
3107 {
3108   DBusString test_directory;
3109   DBusString filename;
3110   DBusDirIter *dir;
3111   dbus_bool_t retval;
3112   DBusError error;
3113
3114   retval = FALSE;
3115   dir = NULL;
3116
3117   if (!_dbus_string_init (&test_directory))
3118     _dbus_assert_not_reached ("didn't allocate test_directory");
3119
3120   _dbus_string_init_const (&filename, subdir);
3121
3122   if (!_dbus_string_copy (test_base_dir, 0,
3123                           &test_directory, 0))
3124     _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
3125
3126   if (!_dbus_concat_dir_and_file (&test_directory, &filename))
3127     _dbus_assert_not_reached ("couldn't allocate full path");
3128
3129   _dbus_string_free (&filename);
3130   if (!_dbus_string_init (&filename))
3131     _dbus_assert_not_reached ("didn't allocate filename string");
3132
3133   dbus_error_init (&error);
3134   dir = _dbus_directory_open (&test_directory, &error);
3135   if (dir == NULL)
3136     {
3137       _dbus_warn ("Could not open %s: %s",
3138                   _dbus_string_get_const_data (&test_directory),
3139                   error.message);
3140       dbus_error_free (&error);
3141       goto failed;
3142     }
3143
3144   if (validity == VALID)
3145     printf ("Testing valid files:\n");
3146   else if (validity == INVALID)
3147     printf ("Testing invalid files:\n");
3148   else
3149     printf ("Testing unknown files:\n");
3150
3151  next:
3152   while (_dbus_directory_get_next_file (dir, &filename, &error))
3153     {
3154       DBusString full_path;
3155       LoaderOomData d;
3156
3157       if (!_dbus_string_init (&full_path))
3158         _dbus_assert_not_reached ("couldn't init string");
3159
3160       if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
3161         _dbus_assert_not_reached ("couldn't copy dir to full_path");
3162
3163       if (!_dbus_concat_dir_and_file (&full_path, &filename))
3164         _dbus_assert_not_reached ("couldn't concat file to dir");
3165
3166       if (!_dbus_string_ends_with_c_str (&full_path, ".conf"))
3167         {
3168           _dbus_verbose ("Skipping non-.conf file %s\n",
3169                          _dbus_string_get_const_data (&filename));
3170           _dbus_string_free (&full_path);
3171           goto next;
3172         }
3173
3174       printf ("    %s\n", _dbus_string_get_const_data (&filename));
3175
3176       _dbus_verbose (" expecting %s\n",
3177                      validity == VALID ? "valid" :
3178                      (validity == INVALID ? "invalid" :
3179                       (validity == UNKNOWN ? "unknown" : "???")));
3180
3181       d.full_path = &full_path;
3182       d.validity = validity;
3183       d.check_own_rules = _dbus_string_ends_with_c_str (&full_path,
3184           "check-own-rules.conf");
3185
3186       /* FIXME hackaround for an expat problem, see
3187        * https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=124747
3188        * http://freedesktop.org/pipermail/dbus/2004-May/001153.html
3189        */
3190       /* if (!_dbus_test_oom_handling ("config-loader", check_loader_oom_func, &d)) */
3191       if (!check_loader_oom_func (&d))
3192         _dbus_assert_not_reached ("test failed");
3193       
3194       _dbus_string_free (&full_path);
3195     }
3196
3197   if (dbus_error_is_set (&error))
3198     {
3199       _dbus_warn ("Could not get next file in %s: %s",
3200                   _dbus_string_get_const_data (&test_directory),
3201                   error.message);
3202       dbus_error_free (&error);
3203       goto failed;
3204     }
3205
3206   retval = TRUE;
3207
3208  failed:
3209
3210   if (dir)
3211     _dbus_directory_close (dir);
3212   _dbus_string_free (&test_directory);
3213   _dbus_string_free (&filename);
3214
3215   return retval;
3216 }
3217
3218 static dbus_bool_t
3219 bools_equal (dbus_bool_t a,
3220              dbus_bool_t b)
3221 {
3222   return a ? b : !b;
3223 }
3224
3225 static dbus_bool_t
3226 strings_equal_or_both_null (const char *a,
3227                             const char *b)
3228 {
3229   if (a == NULL || b == NULL)
3230     return a == b;
3231   else
3232     return !strcmp (a, b);
3233 }
3234
3235 static dbus_bool_t
3236 elements_equal (const Element *a,
3237                 const Element *b)
3238 {
3239   if (a->type != b->type)
3240     return FALSE;
3241
3242   if (!bools_equal (a->had_content, b->had_content))
3243     return FALSE;
3244
3245   switch (a->type)
3246     {
3247
3248     case ELEMENT_INCLUDE:
3249       if (!bools_equal (a->d.include.ignore_missing,
3250                         b->d.include.ignore_missing))
3251         return FALSE;
3252       break;
3253
3254     case ELEMENT_POLICY:
3255       if (a->d.policy.type != b->d.policy.type)
3256         return FALSE;
3257       if (a->d.policy.gid_uid_or_at_console != b->d.policy.gid_uid_or_at_console)
3258         return FALSE;
3259       break;
3260
3261     case ELEMENT_LIMIT:
3262       if (strcmp (a->d.limit.name, b->d.limit.name))
3263         return FALSE;
3264       if (a->d.limit.value != b->d.limit.value)
3265         return FALSE;
3266       break;
3267
3268     default:
3269       /* do nothing */
3270       break;
3271     }
3272
3273   return TRUE;
3274
3275 }
3276
3277 static dbus_bool_t
3278 lists_of_elements_equal (DBusList *a,
3279                          DBusList *b)
3280 {
3281   DBusList *ia;
3282   DBusList *ib;
3283
3284   ia = a;
3285   ib = b;
3286   
3287   while (ia != NULL && ib != NULL)
3288     {
3289       if (elements_equal (ia->data, ib->data))
3290         return FALSE;
3291       ia = _dbus_list_get_next_link (&a, ia);
3292       ib = _dbus_list_get_next_link (&b, ib);
3293     }
3294
3295   return ia == NULL && ib == NULL;
3296 }
3297
3298 static dbus_bool_t
3299 lists_of_c_strings_equal (DBusList *a,
3300                           DBusList *b)
3301 {
3302   DBusList *ia;
3303   DBusList *ib;
3304
3305   ia = a;
3306   ib = b;
3307   
3308   while (ia != NULL && ib != NULL)
3309     {
3310       if (strcmp (ia->data, ib->data))
3311         return FALSE;
3312       ia = _dbus_list_get_next_link (&a, ia);
3313       ib = _dbus_list_get_next_link (&b, ib);
3314     }
3315
3316   return ia == NULL && ib == NULL;
3317 }
3318
3319 static dbus_bool_t
3320 lists_of_service_dirs_equal (DBusList *a,
3321                              DBusList *b)
3322 {
3323   DBusList *ia;
3324   DBusList *ib;
3325
3326   ia = a;
3327   ib = b;
3328
3329   while (ia != NULL && ib != NULL)
3330     {
3331       BusConfigServiceDir *da = ia->data;
3332       BusConfigServiceDir *db = ib->data;
3333
3334       if (strcmp (da->path, db->path))
3335         return FALSE;
3336
3337       if (da->flags != db->flags)
3338         return FALSE;
3339
3340       ia = _dbus_list_get_next_link (&a, ia);
3341       ib = _dbus_list_get_next_link (&b, ib);
3342     }
3343
3344   return ia == NULL && ib == NULL;
3345 }
3346
3347 static dbus_bool_t
3348 limits_equal (const BusLimits *a,
3349               const BusLimits *b)
3350 {
3351   return
3352     (a->max_incoming_bytes == b->max_incoming_bytes
3353      || a->max_incoming_unix_fds == b->max_incoming_unix_fds
3354      || a->max_outgoing_bytes == b->max_outgoing_bytes
3355      || a->max_outgoing_unix_fds == b->max_outgoing_unix_fds
3356      || a->max_message_size == b->max_message_size
3357      || a->max_message_unix_fds == b->max_message_unix_fds
3358      || a->activation_timeout == b->activation_timeout
3359      || a->auth_timeout == b->auth_timeout
3360      || a->pending_fd_timeout == b->pending_fd_timeout
3361      || a->max_completed_connections == b->max_completed_connections
3362      || a->max_incomplete_connections == b->max_incomplete_connections
3363      || a->max_connections_per_user == b->max_connections_per_user
3364      || a->max_pending_activations == b->max_pending_activations
3365      || a->max_services_per_connection == b->max_services_per_connection
3366      || a->max_match_rules_per_connection == b->max_match_rules_per_connection
3367      || a->max_replies_per_connection == b->max_replies_per_connection
3368      || a->reply_timeout == b->reply_timeout);
3369 }
3370
3371 static dbus_bool_t
3372 config_parsers_equal (const BusConfigParser *a,
3373                       const BusConfigParser *b)
3374 {
3375   if (!_dbus_string_equal (&a->basedir, &b->basedir))
3376     return FALSE;
3377
3378   if (!lists_of_elements_equal (a->stack, b->stack))
3379     return FALSE;
3380
3381   if (!strings_equal_or_both_null (a->user, b->user))
3382     return FALSE;
3383
3384   if (!lists_of_c_strings_equal (a->listen_on, b->listen_on))
3385     return FALSE;
3386
3387   if (!lists_of_c_strings_equal (a->mechanisms, b->mechanisms))
3388     return FALSE;
3389
3390   if (!lists_of_service_dirs_equal (a->service_dirs, b->service_dirs))
3391     return FALSE;
3392   
3393   /* FIXME: compare policy */
3394
3395   /* FIXME: compare service selinux ID table */
3396
3397   if (! limits_equal (&a->limits, &b->limits))
3398     return FALSE;
3399
3400   if (!strings_equal_or_both_null (a->pidfile, b->pidfile))
3401     return FALSE;
3402
3403   if (! bools_equal (a->fork, b->fork))
3404     return FALSE;
3405
3406   if (! bools_equal (a->keep_umask, b->keep_umask))
3407     return FALSE;
3408
3409   if (! bools_equal (a->is_toplevel, b->is_toplevel))
3410     return FALSE;
3411
3412   return TRUE;
3413 }
3414
3415 static dbus_bool_t
3416 all_are_equiv (const DBusString *target_directory)
3417 {
3418   DBusString filename;
3419   DBusDirIter *dir;
3420   BusConfigParser *first_parser;
3421   BusConfigParser *parser;
3422   DBusError error;
3423   dbus_bool_t equal;
3424   dbus_bool_t retval;
3425
3426   dir = NULL;
3427   first_parser = NULL;
3428   parser = NULL;
3429   retval = FALSE;
3430
3431   if (!_dbus_string_init (&filename))
3432     _dbus_assert_not_reached ("didn't allocate filename string");
3433
3434   dbus_error_init (&error);
3435   dir = _dbus_directory_open (target_directory, &error);
3436   if (dir == NULL)
3437     {
3438       _dbus_warn ("Could not open %s: %s",
3439                   _dbus_string_get_const_data (target_directory),
3440                   error.message);
3441       dbus_error_free (&error);
3442       goto finished;
3443     }
3444
3445   printf ("Comparing equivalent files:\n");
3446
3447  next:
3448   while (_dbus_directory_get_next_file (dir, &filename, &error))
3449     {
3450       DBusString full_path;
3451
3452       if (!_dbus_string_init (&full_path))
3453         _dbus_assert_not_reached ("couldn't init string");
3454
3455       if (!_dbus_string_copy (target_directory, 0, &full_path, 0))
3456         _dbus_assert_not_reached ("couldn't copy dir to full_path");
3457
3458       if (!_dbus_concat_dir_and_file (&full_path, &filename))
3459         _dbus_assert_not_reached ("couldn't concat file to dir");
3460
3461       if (!_dbus_string_ends_with_c_str (&full_path, ".conf"))
3462         {
3463           _dbus_verbose ("Skipping non-.conf file %s\n",
3464                          _dbus_string_get_const_data (&filename));
3465           _dbus_string_free (&full_path);
3466           goto next;
3467         }
3468
3469       printf ("    %s\n", _dbus_string_get_const_data (&filename));
3470
3471       parser = bus_config_load (&full_path, TRUE, NULL, &error);
3472
3473       if (parser == NULL)
3474         {
3475           _dbus_warn ("Could not load file %s: %s",
3476                       _dbus_string_get_const_data (&full_path),
3477                       error.message);
3478           _dbus_string_free (&full_path);
3479           dbus_error_free (&error);
3480           goto finished;
3481         }
3482       else if (first_parser == NULL)
3483         {
3484           _dbus_string_free (&full_path);
3485           first_parser = parser;
3486         }
3487       else
3488         {
3489           _dbus_string_free (&full_path);
3490           equal = config_parsers_equal (first_parser, parser);
3491           bus_config_parser_unref (parser);
3492           if (! equal)
3493             goto finished;
3494         }
3495     }
3496
3497   retval = TRUE;
3498
3499  finished:
3500   _dbus_string_free (&filename);
3501   if (first_parser)
3502     bus_config_parser_unref (first_parser);
3503   if (dir)
3504     _dbus_directory_close (dir);
3505
3506   return retval;
3507   
3508 }
3509
3510 static dbus_bool_t
3511 process_test_equiv_subdir (const DBusString *test_base_dir,
3512                            const char       *subdir)
3513 {
3514   DBusString test_directory;
3515   DBusString filename;
3516   DBusDirIter *dir;
3517   DBusError error;
3518   dbus_bool_t equal;
3519   dbus_bool_t retval;
3520
3521   dir = NULL;
3522   retval = FALSE;
3523
3524   if (!_dbus_string_init (&test_directory))
3525     _dbus_assert_not_reached ("didn't allocate test_directory");
3526
3527   _dbus_string_init_const (&filename, subdir);
3528
3529   if (!_dbus_string_copy (test_base_dir, 0,
3530                           &test_directory, 0))
3531     _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
3532
3533   if (!_dbus_concat_dir_and_file (&test_directory, &filename))
3534     _dbus_assert_not_reached ("couldn't allocate full path");
3535
3536   _dbus_string_free (&filename);
3537   if (!_dbus_string_init (&filename))
3538     _dbus_assert_not_reached ("didn't allocate filename string");
3539
3540   dbus_error_init (&error);
3541   dir = _dbus_directory_open (&test_directory, &error);
3542   if (dir == NULL)
3543     {
3544       _dbus_warn ("Could not open %s: %s",
3545                   _dbus_string_get_const_data (&test_directory),
3546                   error.message);
3547       dbus_error_free (&error);
3548       goto finished;
3549     }
3550
3551   while (_dbus_directory_get_next_file (dir, &filename, &error))
3552     {
3553       DBusString full_path;
3554
3555       /* Skip CVS's magic directories! */
3556       if (_dbus_string_equal_c_str (&filename, "CVS"))
3557         continue;
3558
3559       if (!_dbus_string_init (&full_path))
3560         _dbus_assert_not_reached ("couldn't init string");
3561
3562       if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
3563         _dbus_assert_not_reached ("couldn't copy dir to full_path");
3564
3565       if (!_dbus_concat_dir_and_file (&full_path, &filename))
3566         _dbus_assert_not_reached ("couldn't concat file to dir");
3567       
3568       equal = all_are_equiv (&full_path);
3569       _dbus_string_free (&full_path);
3570
3571       if (!equal)
3572         goto finished;
3573     }
3574
3575   retval = TRUE;
3576
3577  finished:
3578   _dbus_string_free (&test_directory);
3579   _dbus_string_free (&filename);
3580   if (dir)
3581     _dbus_directory_close (dir);
3582
3583   return retval;
3584   
3585 }
3586
3587 static const char *test_session_service_dir_matches[] = 
3588         {
3589 /* will be filled in test_default_session_servicedirs() */
3590 #ifdef DBUS_WIN
3591          NULL, /* install root-based */
3592          NULL, /* CommonProgramFiles-based */
3593 #else
3594          NULL, /* XDG_RUNTIME_DIR-based */
3595          NULL, /* XDG_DATA_HOME-based */
3596          NULL, /* XDG_DATA_DIRS-based */
3597          NULL, /* XDG_DATA_DIRS-based */
3598          DBUS_DATADIR "/dbus-1/services",
3599 #endif
3600          NULL
3601         };
3602
3603 static dbus_bool_t
3604 test_default_session_servicedirs (const DBusString *test_base_dir)
3605 {
3606   BusConfigParser *parser = NULL;
3607   DBusError error = DBUS_ERROR_INIT;
3608   DBusList **dirs;
3609   DBusList *watched_dirs = NULL;
3610   DBusList *link;
3611   DBusString tmp;
3612   DBusString full_path;
3613   DBusString progs;
3614   DBusString install_root_based;
3615   DBusString runtime_dir_based;
3616   DBusString data_home_based;
3617   DBusString data_dirs_based;
3618   DBusString data_dirs_based2;
3619   int i;
3620   dbus_bool_t ret = FALSE;
3621 #ifdef DBUS_WIN
3622   const char *common_progs;
3623 #else
3624   const char *dbus_test_builddir;
3625   const char *xdg_data_home;
3626   const char *xdg_runtime_dir;
3627 #endif
3628
3629   /* On each platform we don't actually use all of these, but it's easier to
3630    * handle the deallocation if we always allocate them, whether needed or
3631    * not */
3632   if (!_dbus_string_init (&full_path) ||
3633       !_dbus_string_init (&progs) ||
3634       !_dbus_string_init (&install_root_based) ||
3635       !_dbus_string_init (&runtime_dir_based) ||
3636       !_dbus_string_init (&data_home_based) ||
3637       !_dbus_string_init (&data_dirs_based) ||
3638       !_dbus_string_init (&data_dirs_based2))
3639     _dbus_assert_not_reached ("OOM allocating strings");
3640
3641   if (!_dbus_string_copy (test_base_dir, 0,
3642                           &full_path, 0))
3643     _dbus_assert_not_reached ("couldn't copy test_base_dir to full_path");
3644
3645   _dbus_string_init_const (&tmp, "valid-config-files");
3646
3647   if (!_dbus_concat_dir_and_file (&full_path, &tmp))
3648     _dbus_assert_not_reached ("couldn't allocate full path");
3649
3650   _dbus_string_init_const (&tmp, "standard-session-dirs.conf");
3651
3652   if (!_dbus_concat_dir_and_file (&full_path, &tmp))
3653     _dbus_assert_not_reached ("couldn't allocate full path");
3654
3655 #ifdef DBUS_WIN
3656   if (!_dbus_string_append (&install_root_based, DBUS_DATADIR) ||
3657       !_dbus_string_append (&install_root_based, "/dbus-1/services") ||
3658       !_dbus_replace_install_prefix (&install_root_based))
3659     goto out;
3660
3661   _dbus_assert (_dbus_path_is_absolute (&install_root_based));
3662
3663   test_session_service_dir_matches[0] = _dbus_string_get_const_data (
3664       &install_root_based);
3665
3666   common_progs = _dbus_getenv ("CommonProgramFiles");
3667
3668   if (common_progs) 
3669     {
3670       if (!_dbus_string_append (&progs, common_progs)) 
3671         goto out;
3672
3673       if (!_dbus_string_append (&progs, "/dbus-1/services")) 
3674         goto out;
3675
3676       test_session_service_dir_matches[1] = _dbus_string_get_const_data(&progs);
3677     }
3678 #else
3679   dbus_test_builddir = _dbus_getenv ("DBUS_TEST_BUILDDIR");
3680   xdg_data_home = _dbus_getenv ("XDG_DATA_HOME");
3681   xdg_runtime_dir = _dbus_getenv ("XDG_RUNTIME_DIR");
3682
3683   if (dbus_test_builddir == NULL || xdg_data_home == NULL ||
3684       xdg_runtime_dir == NULL)
3685     {
3686       printf ("Not testing default session service directories because a "
3687               "build-time testing environment variable is not set: "
3688               "see AM_TESTS_ENVIRONMENT in tests/Makefile.am\n");
3689       ret = TRUE;
3690       goto out;
3691     }
3692
3693   if (!_dbus_string_append (&data_dirs_based, dbus_test_builddir) ||
3694       !_dbus_string_append (&data_dirs_based, "/XDG_DATA_DIRS/dbus-1/services") ||
3695       !_dbus_string_append (&data_dirs_based2, dbus_test_builddir) ||
3696       !_dbus_string_append (&data_dirs_based2, "/XDG_DATA_DIRS2/dbus-1/services") ||
3697       !_dbus_string_append (&runtime_dir_based, xdg_runtime_dir) ||
3698       !_dbus_string_append (&data_home_based, xdg_data_home) ||
3699       !_dbus_string_append (&data_home_based, "/dbus-1/services"))
3700     _dbus_assert_not_reached ("out of memory");
3701
3702   if (!_dbus_ensure_directory (&runtime_dir_based, NULL))
3703     _dbus_assert_not_reached ("Unable to create fake XDG_RUNTIME_DIR");
3704
3705   if (!_dbus_string_append (&runtime_dir_based, "/dbus-1/services"))
3706     _dbus_assert_not_reached ("out of memory");
3707
3708   /* Sanity check: the Makefile sets this up. We assume that if this is
3709    * right, the XDG_DATA_DIRS will be too. */
3710   if (!_dbus_string_starts_with_c_str (&data_home_based, dbus_test_builddir))
3711     _dbus_assert_not_reached ("$XDG_DATA_HOME should start with $DBUS_TEST_BUILDDIR");
3712
3713   if (!_dbus_string_starts_with_c_str (&runtime_dir_based, dbus_test_builddir))
3714     _dbus_assert_not_reached ("$XDG_RUNTIME_DIR should start with $DBUS_TEST_BUILDDIR");
3715
3716   test_session_service_dir_matches[0] = _dbus_string_get_const_data (
3717       &runtime_dir_based);
3718   test_session_service_dir_matches[1] = _dbus_string_get_const_data (
3719       &data_home_based);
3720   test_session_service_dir_matches[2] = _dbus_string_get_const_data (
3721       &data_dirs_based);
3722   test_session_service_dir_matches[3] = _dbus_string_get_const_data (
3723       &data_dirs_based2);
3724 #endif
3725
3726   parser = bus_config_load (&full_path, TRUE, NULL, &error);
3727
3728   if (parser == NULL)
3729     _dbus_assert_not_reached (error.message);
3730
3731   dirs = bus_config_parser_get_service_dirs (parser);
3732
3733   for (link = _dbus_list_get_first_link (dirs), i = 0;
3734        link != NULL;
3735        link = _dbus_list_get_next_link (dirs, link), i++)
3736     {
3737       BusConfigServiceDir *dir = link->data;
3738       BusServiceDirFlags expected = BUS_SERVICE_DIR_FLAGS_NONE;
3739
3740       printf ("    test service dir: '%s'\n", dir->path);
3741       printf ("    current standard service dir: '%s'\n", test_session_service_dir_matches[i]);
3742       if (test_session_service_dir_matches[i] == NULL)
3743         {
3744           printf ("more directories parsed than in match set\n");
3745           goto out;
3746         }
3747  
3748       if (strcmp (test_session_service_dir_matches[i], dir->path) != 0)
3749         {
3750           printf ("'%s' directory does not match '%s' in the match set\n",
3751                   dir->path, test_session_service_dir_matches[i]);
3752           goto out;
3753         }
3754
3755 #ifndef DBUS_WIN
3756       /* On Unix we expect the first directory in the search path to be
3757        * in the XDG_RUNTIME_DIR, and we expect it to have special flags */
3758       if (i == 0)
3759         expected = (BUS_SERVICE_DIR_FLAGS_NO_WATCH |
3760                     BUS_SERVICE_DIR_FLAGS_STRICT_NAMING);
3761 #endif
3762
3763       if (dir->flags != expected)
3764         {
3765           printf ("'%s' directory has flags 0x%x, should be 0x%x\n",
3766                   dir->path, dir->flags, expected);
3767           goto out;
3768         }
3769     }
3770   
3771   if (test_session_service_dir_matches[i] != NULL)
3772     {
3773       printf ("extra data %s in the match set was not matched\n",
3774               test_session_service_dir_matches[i]);
3775       goto out;
3776     }
3777
3778   if (!bus_config_parser_get_watched_dirs (parser, &watched_dirs))
3779     _dbus_assert_not_reached ("out of memory");
3780
3781 #ifdef DBUS_WIN
3782   /* We expect all directories to be watched (not that it matters on Windows,
3783    * because we don't know how) */
3784   i = 0;
3785 #else
3786   /* We expect all directories except the first to be watched, because
3787    * the first one is transient */
3788   i = 1;
3789 #endif
3790
3791   for (link = _dbus_list_get_first_link (&watched_dirs);
3792        link != NULL;
3793        link = _dbus_list_get_next_link (&watched_dirs, link), i++)
3794     {
3795       printf ("    watched service dir: '%s'\n", (const char *) link->data);
3796       printf ("    current standard service dir: '%s'\n",
3797               test_session_service_dir_matches[i]);
3798
3799       if (test_session_service_dir_matches[i] == NULL)
3800         {
3801           printf ("more directories parsed than in match set\n");
3802           goto out;
3803         }
3804
3805       if (strcmp (test_session_service_dir_matches[i],
3806                   (const char *) link->data) != 0)
3807         {
3808           printf ("'%s' directory does not match '%s' in the match set\n",
3809                   (const char *) link->data,
3810                   test_session_service_dir_matches[i]);
3811           goto out;
3812         }
3813     }
3814
3815   if (test_session_service_dir_matches[i] != NULL)
3816     {
3817       printf ("extra data %s in the match set was not matched\n",
3818               test_session_service_dir_matches[i]);
3819       goto out;
3820     }
3821
3822   ret = TRUE;
3823
3824 out:
3825   if (parser != NULL)
3826     bus_config_parser_unref (parser);
3827
3828   _dbus_list_clear (&watched_dirs);
3829   _dbus_string_free (&full_path);
3830   _dbus_string_free (&install_root_based);
3831   _dbus_string_free (&progs);
3832   _dbus_string_free (&runtime_dir_based);
3833   _dbus_string_free (&data_home_based);
3834   _dbus_string_free (&data_dirs_based);
3835   _dbus_string_free (&data_dirs_based2);
3836   return ret;
3837 }
3838
3839 #ifndef DBUS_WIN
3840 static const char *test_system_service_dir_matches[] = 
3841         {
3842          "/usr/local/share/dbus-1/system-services",
3843          "/usr/share/dbus-1/system-services",
3844          DBUS_DATADIR"/dbus-1/system-services",
3845          "/lib/dbus-1/system-services",
3846          NULL
3847         };
3848
3849 static dbus_bool_t
3850 test_default_system_servicedirs (void)
3851 {
3852   DBusList *dirs;
3853   DBusList *link;
3854   int i;
3855
3856   dirs = NULL;
3857
3858   if (!_dbus_get_standard_system_servicedirs (&dirs))
3859     _dbus_assert_not_reached ("couldn't get stardard dirs");
3860
3861   /* make sure we read and parse the env variable correctly */
3862   i = 0;
3863   while ((link = _dbus_list_pop_first_link (&dirs)))
3864     {
3865       printf ("    test service dir: %s\n", (char *)link->data);
3866       if (test_system_service_dir_matches[i] == NULL)
3867         {
3868           printf ("more directories parsed than in match set\n");
3869           dbus_free (link->data);
3870           _dbus_list_free_link (link);
3871           return FALSE;
3872         }
3873  
3874       if (strcmp (test_system_service_dir_matches[i], 
3875                   (char *)link->data) != 0)
3876         {
3877           printf ("%s directory does not match %s in the match set\n", 
3878                   (char *)link->data,
3879                   test_system_service_dir_matches[i]);
3880           dbus_free (link->data);
3881           _dbus_list_free_link (link);
3882           return FALSE;
3883         }
3884
3885       ++i;
3886
3887       dbus_free (link->data);
3888       _dbus_list_free_link (link);
3889     }
3890   
3891   if (test_system_service_dir_matches[i] != NULL)
3892     {
3893       printf ("extra data %s in the match set was not matched\n",
3894               test_system_service_dir_matches[i]);
3895
3896       return FALSE;
3897     }
3898     
3899   return TRUE;
3900 }
3901 #endif
3902                    
3903 dbus_bool_t
3904 bus_config_parser_test (const DBusString *test_data_dir)
3905 {
3906   if (test_data_dir == NULL ||
3907       _dbus_string_get_length (test_data_dir) == 0)
3908     {
3909       printf ("No test data\n");
3910       return TRUE;
3911     }
3912
3913   if (!test_default_session_servicedirs (test_data_dir))
3914     return FALSE;
3915
3916 #ifdef DBUS_WIN
3917   printf("default system service dir skipped\n");
3918 #else
3919   if (!test_default_system_servicedirs())
3920     return FALSE;
3921 #endif
3922
3923   if (!process_test_valid_subdir (test_data_dir, "valid-config-files", VALID))
3924     return FALSE;
3925
3926 #ifndef DBUS_WIN
3927   if (!process_test_valid_subdir (test_data_dir, "valid-config-files-system", VALID))
3928     return FALSE;
3929 #endif
3930
3931   if (!process_test_valid_subdir (test_data_dir, "invalid-config-files", INVALID))
3932     return FALSE;
3933
3934   if (!process_test_equiv_subdir (test_data_dir, "equiv-config-files"))
3935     return FALSE;
3936
3937   return TRUE;
3938 }
3939
3940 #endif /* DBUS_ENABLE_EMBEDDED_TESTS */
3941