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