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