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