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