2004-04-09 Jon Trowbridge <trow@ximian.com>
[platform/upstream/dbus.git] / bus / config-parser.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* config-parser.c  XML-library-agnostic configuration file parser
3  *
4  * Copyright (C) 2003 Red Hat, Inc.
5  *
6  * Licensed under the Academic Free License version 2.0
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23 #include "config-parser.h"
24 #include "test.h"
25 #include "utils.h"
26 #include "policy.h"
27 #include <dbus/dbus-list.h>
28 #include <dbus/dbus-internals.h>
29 #include <string.h>
30
31 typedef enum
32 {
33   ELEMENT_NONE,
34   ELEMENT_BUSCONFIG,
35   ELEMENT_INCLUDE,
36   ELEMENT_USER,
37   ELEMENT_LISTEN,
38   ELEMENT_AUTH,
39   ELEMENT_POLICY,
40   ELEMENT_LIMIT,
41   ELEMENT_ALLOW,
42   ELEMENT_DENY,
43   ELEMENT_FORK,
44   ELEMENT_PIDFILE,
45   ELEMENT_SERVICEDIR,
46   ELEMENT_INCLUDEDIR,
47   ELEMENT_TYPE
48 } ElementType;
49
50 typedef enum
51 {
52   /* we ignore policies for unknown groups/users */
53   POLICY_IGNORED,
54
55   /* non-ignored */
56   POLICY_DEFAULT,
57   POLICY_MANDATORY,
58   POLICY_USER,
59   POLICY_GROUP
60 } PolicyType;
61
62 typedef struct
63 {
64   ElementType type;
65
66   unsigned int had_content : 1;
67
68   union
69   {
70     struct
71     {
72       unsigned int ignore_missing : 1;
73     } include;
74
75     struct
76     {
77       PolicyType type;
78       unsigned long gid_or_uid;      
79     } policy;
80
81     struct
82     {
83       char *name;
84       long value;
85     } limit;
86     
87   } d;
88
89 } Element;
90
91 /**
92  * Parser for bus configuration file. 
93  */
94 struct BusConfigParser
95 {
96   int refcount;        /**< Reference count */
97
98   DBusString basedir;  /**< Directory we resolve paths relative to */
99   
100   DBusList *stack;     /**< stack of Element */
101
102   char *user;          /**< user to run as */
103
104   char *bus_type;          /**< Message bus type */
105   
106   DBusList *listen_on; /**< List of addresses to listen to */
107
108   DBusList *mechanisms; /**< Auth mechanisms */
109
110   DBusList *service_dirs; /**< Directories to look for services in */
111
112   BusPolicy *policy;     /**< Security policy */
113
114   BusLimits limits;      /**< Limits */
115
116   char *pidfile;         /**< PID file */
117
118   unsigned int fork : 1; /**< TRUE to fork into daemon mode */
119
120   unsigned int is_toplevel : 1; /**< FALSE if we are a sub-config-file inside another one */
121 };
122
123 static const char*
124 element_type_to_name (ElementType type)
125 {
126   switch (type)
127     {
128     case ELEMENT_NONE:
129       return NULL;
130     case ELEMENT_BUSCONFIG:
131       return "busconfig";
132     case ELEMENT_INCLUDE:
133       return "include";
134     case ELEMENT_USER:
135       return "user";
136     case ELEMENT_LISTEN:
137       return "listen";
138     case ELEMENT_AUTH:
139       return "auth";
140     case ELEMENT_POLICY:
141       return "policy";
142     case ELEMENT_LIMIT:
143       return "limit";
144     case ELEMENT_ALLOW:
145       return "allow";
146     case ELEMENT_DENY:
147       return "deny";
148     case ELEMENT_FORK:
149       return "fork";
150     case ELEMENT_PIDFILE:
151       return "pidfile";
152     case ELEMENT_SERVICEDIR:
153       return "servicedir";
154     case ELEMENT_INCLUDEDIR:
155       return "includedir";
156     case ELEMENT_TYPE:
157       return "type";
158     }
159
160   _dbus_assert_not_reached ("bad element type");
161
162   return NULL;
163 }
164
165 static Element*
166 push_element (BusConfigParser *parser,
167               ElementType      type)
168 {
169   Element *e;
170
171   _dbus_assert (type != ELEMENT_NONE);
172   
173   e = dbus_new0 (Element, 1);
174   if (e == NULL)
175     return NULL;
176
177   if (!_dbus_list_append (&parser->stack, e))
178     {
179       dbus_free (e);
180       return NULL;
181     }
182   
183   e->type = type;
184
185   return e;
186 }
187
188 static void
189 element_free (Element *e)
190 {
191   if (e->type == ELEMENT_LIMIT)
192     dbus_free (e->d.limit.name);
193   
194   dbus_free (e);
195 }
196
197 static void
198 pop_element (BusConfigParser *parser)
199 {
200   Element *e;
201
202   e = _dbus_list_pop_last (&parser->stack);
203   
204   element_free (e);
205 }
206
207 static Element*
208 peek_element (BusConfigParser *parser)
209 {
210   Element *e;
211
212   e = _dbus_list_get_last (&parser->stack);
213
214   return e;
215 }
216
217 static ElementType
218 top_element_type (BusConfigParser *parser)
219 {
220   Element *e;
221
222   e = _dbus_list_get_last (&parser->stack);
223
224   if (e)
225     return e->type;
226   else
227     return ELEMENT_NONE;
228 }
229
230 static dbus_bool_t
231 merge_included (BusConfigParser *parser,
232                 BusConfigParser *included,
233                 DBusError       *error)
234 {
235   DBusList *link;
236
237   if (!bus_policy_merge (parser->policy,
238                          included->policy))
239     {
240       BUS_SET_OOM (error);
241       return FALSE;
242     }
243   
244   if (included->user != NULL)
245     {
246       dbus_free (parser->user);
247       parser->user = included->user;
248       included->user = NULL;
249     }
250
251   if (included->bus_type != NULL)
252     {
253       dbus_free (parser->bus_type);
254       parser->bus_type = included->bus_type;
255       included->bus_type = NULL;
256     }
257   
258   if (included->fork)
259     parser->fork = TRUE;
260
261   if (included->pidfile != NULL)
262     {
263       dbus_free (parser->pidfile);
264       parser->pidfile = included->pidfile;
265       included->pidfile = NULL;
266     }
267   
268   while ((link = _dbus_list_pop_first_link (&included->listen_on)))
269     _dbus_list_append_link (&parser->listen_on, link);
270
271   while ((link = _dbus_list_pop_first_link (&included->mechanisms)))
272     _dbus_list_append_link (&parser->mechanisms, link);
273
274   while ((link = _dbus_list_pop_first_link (&included->service_dirs)))
275     _dbus_list_append_link (&parser->service_dirs, link);
276   
277   return TRUE;
278 }
279
280 BusConfigParser*
281 bus_config_parser_new (const DBusString      *basedir,
282                        dbus_bool_t            is_toplevel,
283                        const BusConfigParser *parent)
284 {
285   BusConfigParser *parser;
286
287   parser = dbus_new0 (BusConfigParser, 1);
288   if (parser == NULL)
289     return NULL;
290
291   parser->is_toplevel = !!is_toplevel;
292   
293   if (!_dbus_string_init (&parser->basedir))
294     {
295       dbus_free (parser);
296       return NULL;
297     }
298
299   if (((parser->policy = bus_policy_new ()) == NULL) ||
300       !_dbus_string_copy (basedir, 0, &parser->basedir, 0))
301     {
302       if (parser->policy)
303         bus_policy_unref (parser->policy);
304       
305       _dbus_string_free (&parser->basedir);
306       dbus_free (parser);
307       return NULL;
308     }
309
310   if (parent != NULL)
311     {
312       /* Initialize the parser's limits from the parent. */
313       parser->limits = parent->limits;
314     }
315   else
316     {
317
318       /* Make up some numbers! woot! */
319       parser->limits.max_incoming_bytes = _DBUS_ONE_MEGABYTE * 63;
320       parser->limits.max_outgoing_bytes = _DBUS_ONE_MEGABYTE * 63;
321       parser->limits.max_message_size = _DBUS_ONE_MEGABYTE * 32;
322       
323       /* Making this long means the user has to wait longer for an error
324        * message if something screws up, but making it too short means
325        * they might see a false failure.
326        */
327       parser->limits.activation_timeout = 25000; /* 25 seconds */
328
329       /* Making this long risks making a DOS attack easier, but too short
330        * and legitimate auth will fail.  If interactive auth (ask user for
331        * password) is allowed, then potentially it has to be quite long.
332        */
333       parser->limits.auth_timeout = 30000; /* 30 seconds */
334       
335       parser->limits.max_incomplete_connections = 32;
336       parser->limits.max_connections_per_user = 128;
337       
338       /* Note that max_completed_connections / max_connections_per_user
339        * is the number of users that would have to work together to
340        * DOS all the other users.
341        */
342       parser->limits.max_completed_connections = 1024;
343       
344       parser->limits.max_pending_activations = 256;
345       parser->limits.max_services_per_connection = 256;
346       
347       parser->limits.max_match_rules_per_connection = 128;
348       
349       parser->limits.reply_timeout = 5 * 60 * 1000; /* 5 minutes */
350       parser->limits.max_replies_per_connection = 32;
351     }
352       
353   parser->refcount = 1;
354       
355   return parser;
356 }
357
358 BusConfigParser *
359 bus_config_parser_ref (BusConfigParser *parser)
360 {
361   _dbus_assert (parser->refcount > 0);
362
363   parser->refcount += 1;
364
365   return parser;
366 }
367
368 void
369 bus_config_parser_unref (BusConfigParser *parser)
370 {
371   _dbus_assert (parser->refcount > 0);
372
373   parser->refcount -= 1;
374
375   if (parser->refcount == 0)
376     {
377       while (parser->stack != NULL)
378         pop_element (parser);
379
380       dbus_free (parser->user);
381       dbus_free (parser->bus_type);
382       dbus_free (parser->pidfile);
383       
384       _dbus_list_foreach (&parser->listen_on,
385                           (DBusForeachFunction) dbus_free,
386                           NULL);
387
388       _dbus_list_clear (&parser->listen_on);
389
390       _dbus_list_foreach (&parser->service_dirs,
391                           (DBusForeachFunction) dbus_free,
392                           NULL);
393
394       _dbus_list_clear (&parser->service_dirs);
395
396       _dbus_list_foreach (&parser->mechanisms,
397                           (DBusForeachFunction) dbus_free,
398                           NULL);
399
400       _dbus_list_clear (&parser->mechanisms);
401       
402       _dbus_string_free (&parser->basedir);
403
404       if (parser->policy)
405         bus_policy_unref (parser->policy);
406       
407       dbus_free (parser);
408     }
409 }
410
411 dbus_bool_t
412 bus_config_parser_check_doctype (BusConfigParser   *parser,
413                                  const char        *doctype,
414                                  DBusError         *error)
415 {
416   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
417
418   if (strcmp (doctype, "busconfig") != 0)
419     {
420       dbus_set_error (error,
421                       DBUS_ERROR_FAILED,
422                       "Configuration file has the wrong document type %s",
423                       doctype);
424       return FALSE;
425     }
426   else
427     return TRUE;
428 }
429
430 typedef struct
431 {
432   const char  *name;
433   const char **retloc;
434 } LocateAttr;
435
436 static dbus_bool_t
437 locate_attributes (BusConfigParser  *parser,
438                    const char       *element_name,
439                    const char      **attribute_names,
440                    const char      **attribute_values,
441                    DBusError        *error,
442                    const char       *first_attribute_name,
443                    const char      **first_attribute_retloc,
444                    ...)
445 {
446   va_list args;
447   const char *name;
448   const char **retloc;
449   int n_attrs;
450 #define MAX_ATTRS 24
451   LocateAttr attrs[MAX_ATTRS];
452   dbus_bool_t retval;
453   int i;
454
455   _dbus_assert (first_attribute_name != NULL);
456   _dbus_assert (first_attribute_retloc != NULL);
457
458   retval = TRUE;
459
460   n_attrs = 1;
461   attrs[0].name = first_attribute_name;
462   attrs[0].retloc = first_attribute_retloc;
463   *first_attribute_retloc = NULL;
464
465   va_start (args, first_attribute_retloc);
466
467   name = va_arg (args, const char*);
468   retloc = va_arg (args, const char**);
469
470   while (name != NULL)
471     {
472       _dbus_assert (retloc != NULL);
473       _dbus_assert (n_attrs < MAX_ATTRS);
474
475       attrs[n_attrs].name = name;
476       attrs[n_attrs].retloc = retloc;
477       n_attrs += 1;
478       *retloc = NULL;
479
480       name = va_arg (args, const char*);
481       retloc = va_arg (args, const char**);
482     }
483
484   va_end (args);
485
486   if (!retval)
487     return retval;
488
489   i = 0;
490   while (attribute_names[i])
491     {
492       int j;
493       dbus_bool_t found;
494       
495       found = FALSE;
496       j = 0;
497       while (j < n_attrs)
498         {
499           if (strcmp (attrs[j].name, attribute_names[i]) == 0)
500             {
501               retloc = attrs[j].retloc;
502
503               if (*retloc != NULL)
504                 {
505                   dbus_set_error (error, DBUS_ERROR_FAILED,
506                                   "Attribute \"%s\" repeated twice on the same <%s> element",
507                                   attrs[j].name, element_name);
508                   retval = FALSE;
509                   goto out;
510                 }
511
512               *retloc = attribute_values[i];
513               found = TRUE;
514             }
515
516           ++j;
517         }
518
519       if (!found)
520         {
521           dbus_set_error (error, DBUS_ERROR_FAILED,
522                           "Attribute \"%s\" is invalid on <%s> element in this context",
523                           attribute_names[i], element_name);
524           retval = FALSE;
525           goto out;
526         }
527
528       ++i;
529     }
530
531  out:
532   return retval;
533 }
534
535 static dbus_bool_t
536 check_no_attributes (BusConfigParser  *parser,
537                      const char       *element_name,
538                      const char      **attribute_names,
539                      const char      **attribute_values,
540                      DBusError        *error)
541 {
542   if (attribute_names[0] != NULL)
543     {
544       dbus_set_error (error, DBUS_ERROR_FAILED,
545                       "Attribute \"%s\" is invalid on <%s> element in this context",
546                       attribute_names[0], element_name);
547       return FALSE;
548     }
549
550   return TRUE;
551 }
552
553 static dbus_bool_t
554 start_busconfig_child (BusConfigParser   *parser,
555                        const char        *element_name,
556                        const char       **attribute_names,
557                        const char       **attribute_values,
558                        DBusError         *error)
559 {
560   if (strcmp (element_name, "user") == 0)
561     {
562       if (!check_no_attributes (parser, "user", attribute_names, attribute_values, error))
563         return FALSE;
564
565       if (push_element (parser, ELEMENT_USER) == NULL)
566         {
567           BUS_SET_OOM (error);
568           return FALSE;
569         }
570
571       return TRUE;
572     }
573   else if (strcmp (element_name, "type") == 0)
574     {
575       if (!check_no_attributes (parser, "type", attribute_names, attribute_values, error))
576         return FALSE;
577
578       if (push_element (parser, ELEMENT_TYPE) == NULL)
579         {
580           BUS_SET_OOM (error);
581           return FALSE;
582         }
583
584       return TRUE;
585     }
586   else if (strcmp (element_name, "fork") == 0)
587     {
588       if (!check_no_attributes (parser, "fork", attribute_names, attribute_values, error))
589         return FALSE;
590
591       if (push_element (parser, ELEMENT_FORK) == NULL)
592         {
593           BUS_SET_OOM (error);
594           return FALSE;
595         }
596
597       parser->fork = TRUE;
598       
599       return TRUE;
600     }
601   else if (strcmp (element_name, "pidfile") == 0)
602     {
603       if (!check_no_attributes (parser, "pidfile", attribute_names, attribute_values, error))
604         return FALSE;
605
606       if (push_element (parser, ELEMENT_PIDFILE) == NULL)
607         {
608           BUS_SET_OOM (error);
609           return FALSE;
610         }
611
612       return TRUE;
613     }
614   else if (strcmp (element_name, "listen") == 0)
615     {
616       if (!check_no_attributes (parser, "listen", attribute_names, attribute_values, error))
617         return FALSE;
618
619       if (push_element (parser, ELEMENT_LISTEN) == NULL)
620         {
621           BUS_SET_OOM (error);
622           return FALSE;
623         }
624
625       return TRUE;
626     }
627   else if (strcmp (element_name, "auth") == 0)
628     {
629       if (!check_no_attributes (parser, "auth", attribute_names, attribute_values, error))
630         return FALSE;
631
632       if (push_element (parser, ELEMENT_AUTH) == NULL)
633         {
634           BUS_SET_OOM (error);
635           return FALSE;
636         }
637
638       return TRUE;
639     }
640   else if (strcmp (element_name, "includedir") == 0)
641     {
642       if (!check_no_attributes (parser, "includedir", attribute_names, attribute_values, error))
643         return FALSE;
644
645       if (push_element (parser, ELEMENT_INCLUDEDIR) == NULL)
646         {
647           BUS_SET_OOM (error);
648           return FALSE;
649         }
650
651       return TRUE;
652     }
653   else if (strcmp (element_name, "servicedir") == 0)
654     {
655       if (!check_no_attributes (parser, "servicedir", attribute_names, attribute_values, error))
656         return FALSE;
657
658       if (push_element (parser, ELEMENT_SERVICEDIR) == NULL)
659         {
660           BUS_SET_OOM (error);
661           return FALSE;
662         }
663
664       return TRUE;
665     }
666   else if (strcmp (element_name, "include") == 0)
667     {
668       Element *e;
669       const char *ignore_missing;
670
671       if ((e = push_element (parser, ELEMENT_INCLUDE)) == NULL)
672         {
673           BUS_SET_OOM (error);
674           return FALSE;
675         }
676
677       e->d.include.ignore_missing = FALSE;
678
679       if (!locate_attributes (parser, "include",
680                               attribute_names,
681                               attribute_values,
682                               error,
683                               "ignore_missing", &ignore_missing,
684                               NULL))
685         return FALSE;
686
687       if (ignore_missing != NULL)
688         {
689           if (strcmp (ignore_missing, "yes") == 0)
690             e->d.include.ignore_missing = TRUE;
691           else if (strcmp (ignore_missing, "no") == 0)
692             e->d.include.ignore_missing = FALSE;
693           else
694             {
695               dbus_set_error (error, DBUS_ERROR_FAILED,
696                               "ignore_missing attribute must have value \"yes\" or \"no\"");
697               return FALSE;
698             }
699         }
700
701       return TRUE;
702     }
703   else if (strcmp (element_name, "policy") == 0)
704     {
705       Element *e;
706       const char *context;
707       const char *user;
708       const char *group;
709
710       if ((e = push_element (parser, ELEMENT_POLICY)) == NULL)
711         {
712           BUS_SET_OOM (error);
713           return FALSE;
714         }
715
716       e->d.policy.type = POLICY_IGNORED;
717       
718       if (!locate_attributes (parser, "policy",
719                               attribute_names,
720                               attribute_values,
721                               error,
722                               "context", &context,
723                               "user", &user,
724                               "group", &group,
725                               NULL))
726         return FALSE;
727
728       if (((context && user) ||
729            (context && group)) ||
730           (user && group) ||
731           !(context || user || group))
732         {
733           dbus_set_error (error, DBUS_ERROR_FAILED,
734                           "<policy> element must have exactly one of (context|user|group) attributes");
735           return FALSE;
736         }
737
738       if (context != NULL)
739         {
740           if (strcmp (context, "default") == 0)
741             {
742               e->d.policy.type = POLICY_DEFAULT;
743             }
744           else if (strcmp (context, "mandatory") == 0)
745             {
746               e->d.policy.type = POLICY_MANDATORY;
747             }
748           else
749             {
750               dbus_set_error (error, DBUS_ERROR_FAILED,
751                               "context attribute on <policy> must have the value \"default\" or \"mandatory\", not \"%s\"",
752                               context);
753               return FALSE;
754             }
755         }
756       else if (user != NULL)
757         {
758           DBusString username;
759           _dbus_string_init_const (&username, user);
760
761           if (_dbus_get_user_id (&username,
762                                  &e->d.policy.gid_or_uid))
763             e->d.policy.type = POLICY_USER;
764           else
765             _dbus_warn ("Unknown username \"%s\" in message bus configuration file\n",
766                         user);
767         }
768       else if (group != NULL)
769         {
770           DBusString group_name;
771           _dbus_string_init_const (&group_name, group);
772
773           if (_dbus_get_group_id (&group_name,
774                                   &e->d.policy.gid_or_uid))
775             e->d.policy.type = POLICY_GROUP;
776           else
777             _dbus_warn ("Unknown group \"%s\" in message bus configuration file\n",
778                         group);          
779         }
780       else
781         {
782           _dbus_assert_not_reached ("all <policy> attributes null and we didn't set error");
783         }
784       
785       return TRUE;
786     }
787   else if (strcmp (element_name, "limit") == 0)
788     {
789       Element *e;
790       const char *name;
791
792       if ((e = push_element (parser, ELEMENT_LIMIT)) == NULL)
793         {
794           BUS_SET_OOM (error);
795           return FALSE;
796         }
797       
798       if (!locate_attributes (parser, "limit",
799                               attribute_names,
800                               attribute_values,
801                               error,
802                               "name", &name,
803                               NULL))
804         return FALSE;
805
806       if (name == NULL)
807         {
808           dbus_set_error (error, DBUS_ERROR_FAILED,
809                           "<limit> element must have a \"name\" attribute");
810           return FALSE;
811         }
812
813       e->d.limit.name = _dbus_strdup (name);
814       if (e->d.limit.name == NULL)
815         {
816           BUS_SET_OOM (error);
817           return FALSE;
818         }
819
820       return TRUE;
821     }
822   else
823     {
824       dbus_set_error (error, DBUS_ERROR_FAILED,
825                       "Element <%s> not allowed inside <%s> in configuration file",
826                       element_name, "busconfig");
827       return FALSE;
828     }
829 }
830
831 static dbus_bool_t
832 append_rule_from_element (BusConfigParser   *parser,
833                           const char        *element_name,
834                           const char       **attribute_names,
835                           const char       **attribute_values,
836                           dbus_bool_t        allow,
837                           DBusError         *error)
838 {
839   const char *send_interface;
840   const char *send_member;
841   const char *send_error;
842   const char *send_destination;
843   const char *send_path;
844   const char *send_type;
845   const char *receive_interface;
846   const char *receive_member;
847   const char *receive_error;
848   const char *receive_sender;
849   const char *receive_path;
850   const char *receive_type;
851   const char *eavesdrop;
852   const char *requested_reply;
853   const char *own;
854   const char *user;
855   const char *group;
856   BusPolicyRule *rule;
857   
858   if (!locate_attributes (parser, element_name,
859                           attribute_names,
860                           attribute_values,
861                           error,
862                           "send_interface", &send_interface,
863                           "send_member", &send_member,
864                           "send_error", &send_error,
865                           "send_destination", &send_destination,
866                           "send_path", &send_path,
867                           "send_type", &send_type,
868                           "receive_interface", &receive_interface,
869                           "receive_member", &receive_member,
870                           "receive_error", &receive_error,
871                           "receive_sender", &receive_sender,
872                           "receive_path", &receive_path,
873                           "receive_type", &receive_type,
874                           "eavesdrop", &eavesdrop,
875                           "requested_reply", &requested_reply,
876                           "own", &own,
877                           "user", &user,
878                           "group", &group,
879                           NULL))
880     return FALSE;
881
882   if (!(send_interface || send_member || send_error || send_destination ||
883         send_type || send_path ||
884         receive_interface || receive_member || receive_error || receive_sender ||
885         receive_type || receive_path || eavesdrop || requested_reply ||
886         own || user || group))
887     {
888       dbus_set_error (error, DBUS_ERROR_FAILED,
889                       "Element <%s> must have one or more attributes",
890                       element_name);
891       return FALSE;
892     }
893
894   if ((send_member && (send_interface == NULL && send_path == NULL)) ||
895       (receive_member && (receive_interface == NULL && receive_path == NULL)))
896     {
897       dbus_set_error (error, DBUS_ERROR_FAILED,
898                       "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.",
899                       element_name);
900       return FALSE;
901     }
902   
903   /* Allowed combinations of elements are:
904    *
905    *   base, must be all send or all receive:
906    *     nothing
907    *     interface
908    *     interface + member
909    *     error
910    * 
911    *   base send_ can combine with send_destination, send_path, send_type
912    *   base receive_ with receive_sender, receive_path, receive_type, eavesdrop, requested_reply
913    *
914    *   user, group, own must occur alone
915    *
916    * Pretty sure the below stuff is broken, FIXME think about it more.
917    */
918
919   if (((send_interface && send_error) ||
920        (send_interface && receive_interface) ||
921        (send_interface && receive_member) ||
922        (send_interface && receive_error) ||
923        (send_interface && receive_sender) ||
924        (send_interface && eavesdrop) ||
925        (send_interface && requested_reply) ||
926        (send_interface && own) ||
927        (send_interface && user) ||
928        (send_interface && group)) ||
929
930       ((send_member && send_error) ||
931        (send_member && receive_interface) ||
932        (send_member && receive_member) ||
933        (send_member && receive_error) ||
934        (send_member && receive_sender) ||
935        (send_member && eavesdrop) ||
936        (send_member && requested_reply) ||
937        (send_member && own) ||
938        (send_member && user) ||
939        (send_member && group)) ||
940       
941       ((send_error && receive_interface) ||
942        (send_error && receive_member) ||
943        (send_error && receive_error) ||
944        (send_error && receive_sender) ||
945        (send_error && eavesdrop) ||
946        (send_error && requested_reply) ||
947        (send_error && own) ||
948        (send_error && user) ||
949        (send_error && group)) ||
950
951       ((send_destination && receive_interface) ||
952        (send_destination && receive_member) ||
953        (send_destination && receive_error) ||
954        (send_destination && receive_sender) ||
955        (send_destination && eavesdrop) ||
956        (send_destination && requested_reply) ||
957        (send_destination && own) ||
958        (send_destination && user) ||
959        (send_destination && group)) ||
960
961       ((send_type && receive_interface) ||
962        (send_type && receive_member) ||
963        (send_type && receive_error) ||
964        (send_type && receive_sender) ||
965        (send_type && eavesdrop) ||
966        (send_type && requested_reply) ||
967        (send_type && own) ||
968        (send_type && user) ||
969        (send_type && group)) ||
970
971       ((send_path && receive_interface) ||
972        (send_path && receive_member) ||
973        (send_path && receive_error) ||
974        (send_path && receive_sender) ||
975        (send_path && eavesdrop) ||
976        (send_path && requested_reply) ||
977        (send_path && own) ||
978        (send_path && user) ||
979        (send_path && group)) ||
980       
981       ((receive_interface && receive_error) ||
982        (receive_interface && own) ||
983        (receive_interface && user) ||
984        (receive_interface && group)) ||
985
986       ((receive_member && receive_error) ||
987        (receive_member && own) ||
988        (receive_member && user) ||
989        (receive_member && group)) ||
990       
991       ((receive_error && own) ||
992        (receive_error && user) ||
993        (receive_error && group)) ||
994
995       ((eavesdrop && own) ||
996        (eavesdrop && user) ||
997        (eavesdrop && group)) ||
998
999       ((requested_reply && own) ||
1000        (requested_reply && user) ||
1001        (requested_reply && group)) ||
1002       
1003       ((own && user) ||
1004        (own && group)) ||
1005
1006       ((user && group)))
1007     {
1008       dbus_set_error (error, DBUS_ERROR_FAILED,
1009                       "Invalid combination of attributes on element <%s>",
1010                       element_name);
1011       return FALSE;
1012     }
1013   
1014   rule = NULL;
1015
1016   /* In BusPolicyRule, NULL represents wildcard.
1017    * In the config file, '*' represents it.
1018    */
1019 #define IS_WILDCARD(str) ((str) && ((str)[0]) == '*' && ((str)[1]) == '\0')
1020
1021   if (send_interface || send_member || send_error || send_destination ||
1022       send_path || send_type)
1023     {
1024       int message_type;
1025       
1026       if (IS_WILDCARD (send_interface))
1027         send_interface = NULL;
1028       if (IS_WILDCARD (send_member))
1029         send_member = NULL;
1030       if (IS_WILDCARD (send_error))
1031         send_error = NULL;
1032       if (IS_WILDCARD (send_destination))
1033         send_destination = NULL;
1034       if (IS_WILDCARD (send_path))
1035         send_path = NULL;
1036       if (IS_WILDCARD (send_type))
1037         send_type = NULL;
1038
1039       message_type = DBUS_MESSAGE_TYPE_INVALID;
1040       if (send_type != NULL)
1041         {
1042           message_type = dbus_message_type_from_string (send_type);
1043           if (message_type == DBUS_MESSAGE_TYPE_INVALID)
1044             {
1045               dbus_set_error (error, DBUS_ERROR_FAILED,
1046                               "Bad message type \"%s\"",
1047                               send_type);
1048               return FALSE;
1049             }
1050         }
1051       
1052       rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow); 
1053       if (rule == NULL)
1054         goto nomem;
1055       
1056       rule->d.send.message_type = message_type;
1057       rule->d.send.path = _dbus_strdup (send_path);
1058       rule->d.send.interface = _dbus_strdup (send_interface);
1059       rule->d.send.member = _dbus_strdup (send_member);
1060       rule->d.send.error = _dbus_strdup (send_error);
1061       rule->d.send.destination = _dbus_strdup (send_destination);
1062       if (send_path && rule->d.send.path == NULL)
1063         goto nomem;
1064       if (send_interface && rule->d.send.interface == NULL)
1065         goto nomem;
1066       if (send_member && rule->d.send.member == NULL)
1067         goto nomem;
1068       if (send_error && rule->d.send.error == NULL)
1069         goto nomem;
1070       if (send_destination && rule->d.send.destination == NULL)
1071         goto nomem;
1072     }
1073   else if (receive_interface || receive_member || receive_error || receive_sender ||
1074            receive_path || receive_type || eavesdrop || requested_reply)
1075     {
1076       int message_type;
1077       
1078       if (IS_WILDCARD (receive_interface))
1079         receive_interface = NULL;
1080       if (IS_WILDCARD (receive_member))
1081         receive_member = NULL;
1082       if (IS_WILDCARD (receive_error))
1083         receive_error = NULL;
1084       if (IS_WILDCARD (receive_sender))
1085         receive_sender = NULL;
1086       if (IS_WILDCARD (receive_path))
1087         receive_path = NULL;
1088       if (IS_WILDCARD (receive_type))
1089         receive_type = NULL;
1090
1091       message_type = DBUS_MESSAGE_TYPE_INVALID;
1092       if (receive_type != NULL)
1093         {
1094           message_type = dbus_message_type_from_string (receive_type);
1095           if (message_type == DBUS_MESSAGE_TYPE_INVALID)
1096             {
1097               dbus_set_error (error, DBUS_ERROR_FAILED,
1098                               "Bad message type \"%s\"",
1099                               receive_type);
1100               return FALSE;
1101             }
1102         }
1103
1104
1105       if (eavesdrop &&
1106           !(strcmp (eavesdrop, "true") == 0 ||
1107             strcmp (eavesdrop, "false") == 0))
1108         {
1109           dbus_set_error (error, DBUS_ERROR_FAILED,
1110                           "Bad value \"%s\" for %s attribute, must be true or false",
1111                           "eavesdrop", eavesdrop);
1112           return FALSE;
1113         }
1114
1115       if (requested_reply &&
1116           !(strcmp (requested_reply, "true") == 0 ||
1117             strcmp (requested_reply, "false") == 0))
1118         {
1119           dbus_set_error (error, DBUS_ERROR_FAILED,
1120                           "Bad value \"%s\" for %s attribute, must be true or false",
1121                           "requested_reply", requested_reply);
1122           return FALSE;
1123         }
1124       
1125       rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow); 
1126       if (rule == NULL)
1127         goto nomem;
1128
1129       if (eavesdrop)
1130         rule->d.receive.eavesdrop = (strcmp (eavesdrop, "true") == 0);
1131
1132       if (requested_reply)
1133         rule->d.receive.requested_reply = (strcmp (requested_reply, "true") == 0);
1134       
1135       rule->d.receive.message_type = message_type;
1136       rule->d.receive.path = _dbus_strdup (receive_path);
1137       rule->d.receive.interface = _dbus_strdup (receive_interface);
1138       rule->d.receive.member = _dbus_strdup (receive_member);
1139       rule->d.receive.error = _dbus_strdup (receive_error);
1140       rule->d.receive.origin = _dbus_strdup (receive_sender);
1141
1142       if (receive_path && rule->d.receive.path == NULL)
1143         goto nomem;
1144       if (receive_interface && rule->d.receive.interface == NULL)
1145         goto nomem;
1146       if (receive_member && rule->d.receive.member == NULL)
1147         goto nomem;
1148       if (receive_error && rule->d.receive.error == NULL)
1149         goto nomem;
1150       if (receive_sender && rule->d.receive.origin == NULL)
1151         goto nomem;
1152     }
1153   else if (own)
1154     {
1155       rule = bus_policy_rule_new (BUS_POLICY_RULE_OWN, allow); 
1156       if (rule == NULL)
1157         goto nomem;
1158
1159       if (IS_WILDCARD (own))
1160         own = NULL;
1161       
1162       rule->d.own.service_name = _dbus_strdup (own);
1163       if (own && rule->d.own.service_name == NULL)
1164         goto nomem;
1165     }
1166   else if (user)
1167     {      
1168       if (IS_WILDCARD (user))
1169         {
1170           rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow); 
1171           if (rule == NULL)
1172             goto nomem;
1173
1174           rule->d.user.uid = DBUS_UID_UNSET;
1175         }
1176       else
1177         {
1178           DBusString username;
1179           dbus_uid_t uid;
1180           
1181           _dbus_string_init_const (&username, user);
1182       
1183           if (_dbus_get_user_id (&username, &uid))
1184             {
1185               rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow); 
1186               if (rule == NULL)
1187                 goto nomem;
1188
1189               rule->d.user.uid = uid;
1190             }
1191           else
1192             {
1193               _dbus_warn ("Unknown username \"%s\" on element <%s>\n",
1194                           user, element_name);
1195             }
1196         }
1197     }
1198   else if (group)
1199     {
1200       if (IS_WILDCARD (group))
1201         {
1202           rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow); 
1203           if (rule == NULL)
1204             goto nomem;
1205
1206           rule->d.group.gid = DBUS_GID_UNSET;
1207         }
1208       else
1209         {
1210           DBusString groupname;
1211           dbus_gid_t gid;
1212           
1213           _dbus_string_init_const (&groupname, group);
1214           
1215           if (_dbus_get_user_id (&groupname, &gid))
1216             {
1217               rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow); 
1218               if (rule == NULL)
1219                 goto nomem;
1220
1221               rule->d.group.gid = gid;
1222             }
1223           else
1224             {
1225               _dbus_warn ("Unknown group \"%s\" on element <%s>\n",
1226                           group, element_name);
1227             }
1228         }
1229     }
1230   else
1231     _dbus_assert_not_reached ("Did not handle some combination of attributes on <allow> or <deny>");
1232
1233   if (rule != NULL)
1234     {
1235       Element *pe;
1236       
1237       pe = peek_element (parser);      
1238       _dbus_assert (pe != NULL);
1239       _dbus_assert (pe->type == ELEMENT_POLICY);
1240
1241       switch (pe->d.policy.type)
1242         {
1243         case POLICY_IGNORED:
1244           /* drop the rule on the floor */
1245           break;
1246           
1247         case POLICY_DEFAULT:
1248           if (!bus_policy_append_default_rule (parser->policy, rule))
1249             goto nomem;
1250           break;
1251         case POLICY_MANDATORY:
1252           if (!bus_policy_append_mandatory_rule (parser->policy, rule))
1253             goto nomem;
1254           break;
1255         case POLICY_USER:
1256           if (!BUS_POLICY_RULE_IS_PER_CLIENT (rule))
1257             {
1258               dbus_set_error (error, DBUS_ERROR_FAILED,
1259                               "<%s> rule cannot be per-user because it has bus-global semantics",
1260                               element_name);
1261               goto failed;
1262             }
1263           
1264           if (!bus_policy_append_user_rule (parser->policy, pe->d.policy.gid_or_uid,
1265                                             rule))
1266             goto nomem;
1267           break;
1268         case POLICY_GROUP:
1269           if (!BUS_POLICY_RULE_IS_PER_CLIENT (rule))
1270             {
1271               dbus_set_error (error, DBUS_ERROR_FAILED,
1272                               "<%s> rule cannot be per-group because it has bus-global semantics",
1273                               element_name);
1274               goto failed;
1275             }
1276           
1277           if (!bus_policy_append_group_rule (parser->policy, pe->d.policy.gid_or_uid,
1278                                              rule))
1279             goto nomem;
1280           break;
1281         }
1282       
1283       bus_policy_rule_unref (rule);
1284       rule = NULL;
1285     }
1286   
1287   return TRUE;
1288
1289  nomem:
1290   BUS_SET_OOM (error);
1291  failed:
1292   if (rule)
1293     bus_policy_rule_unref (rule);
1294   return FALSE;
1295 }
1296
1297 static dbus_bool_t
1298 start_policy_child (BusConfigParser   *parser,
1299                     const char        *element_name,
1300                     const char       **attribute_names,
1301                     const char       **attribute_values,
1302                     DBusError         *error)
1303 {
1304   if (strcmp (element_name, "allow") == 0)
1305     {
1306       if (!append_rule_from_element (parser, element_name,
1307                                      attribute_names, attribute_values,
1308                                      TRUE, error))
1309         return FALSE;
1310       
1311       if (push_element (parser, ELEMENT_ALLOW) == NULL)
1312         {
1313           BUS_SET_OOM (error);
1314           return FALSE;
1315         }
1316       
1317       return TRUE;
1318     }
1319   else if (strcmp (element_name, "deny") == 0)
1320     {
1321       if (!append_rule_from_element (parser, element_name,
1322                                      attribute_names, attribute_values,
1323                                      FALSE, error))
1324         return FALSE;
1325       
1326       if (push_element (parser, ELEMENT_DENY) == NULL)
1327         {
1328           BUS_SET_OOM (error);
1329           return FALSE;
1330         }
1331       
1332       return TRUE;
1333     }
1334   else
1335     {
1336       dbus_set_error (error, DBUS_ERROR_FAILED,
1337                       "Element <%s> not allowed inside <%s> in configuration file",
1338                       element_name, "policy");
1339       return FALSE;
1340     }
1341 }
1342
1343 dbus_bool_t
1344 bus_config_parser_start_element (BusConfigParser   *parser,
1345                                  const char        *element_name,
1346                                  const char       **attribute_names,
1347                                  const char       **attribute_values,
1348                                  DBusError         *error)
1349 {
1350   ElementType t;
1351
1352   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1353
1354   /* printf ("START: %s\n", element_name); */
1355   
1356   t = top_element_type (parser);
1357
1358   if (t == ELEMENT_NONE)
1359     {
1360       if (strcmp (element_name, "busconfig") == 0)
1361         {
1362           if (!check_no_attributes (parser, "busconfig", attribute_names, attribute_values, error))
1363             return FALSE;
1364           
1365           if (push_element (parser, ELEMENT_BUSCONFIG) == NULL)
1366             {
1367               BUS_SET_OOM (error);
1368               return FALSE;
1369             }
1370
1371           return TRUE;
1372         }
1373       else
1374         {
1375           dbus_set_error (error, DBUS_ERROR_FAILED,
1376                           "Unknown element <%s> at root of configuration file",
1377                           element_name);
1378           return FALSE;
1379         }
1380     }
1381   else if (t == ELEMENT_BUSCONFIG)
1382     {
1383       return start_busconfig_child (parser, element_name,
1384                                     attribute_names, attribute_values,
1385                                     error);
1386     }
1387   else if (t == ELEMENT_POLICY)
1388     {
1389       return start_policy_child (parser, element_name,
1390                                  attribute_names, attribute_values,
1391                                  error);
1392     }
1393   else
1394     {
1395       dbus_set_error (error, DBUS_ERROR_FAILED,
1396                       "Element <%s> is not allowed in this context",
1397                       element_name);
1398       return FALSE;
1399     }  
1400 }
1401
1402 static dbus_bool_t
1403 set_limit (BusConfigParser *parser,
1404            const char      *name,
1405            long             value,
1406            DBusError       *error)
1407 {
1408   dbus_bool_t must_be_positive;
1409   dbus_bool_t must_be_int;
1410
1411   must_be_int = FALSE;
1412   must_be_positive = FALSE;
1413   
1414   if (strcmp (name, "max_incoming_bytes") == 0)
1415     {
1416       must_be_positive = TRUE;
1417       parser->limits.max_incoming_bytes = value;
1418     }
1419   else if (strcmp (name, "max_outgoing_bytes") == 0)
1420     {
1421       must_be_positive = TRUE;
1422       parser->limits.max_outgoing_bytes = value;
1423     }
1424   else if (strcmp (name, "max_message_size") == 0)
1425     {
1426       must_be_positive = TRUE;
1427       parser->limits.max_message_size = value;
1428     }
1429   else if (strcmp (name, "activation_timeout") == 0)
1430     {
1431       must_be_positive = TRUE;
1432       must_be_int = TRUE;
1433       parser->limits.activation_timeout = value;
1434     }
1435   else if (strcmp (name, "auth_timeout") == 0)
1436     {
1437       must_be_positive = TRUE;
1438       must_be_int = TRUE;
1439       parser->limits.auth_timeout = value;
1440     }
1441   else if (strcmp (name, "reply_timeout") == 0)
1442     {
1443       must_be_positive = TRUE;
1444       must_be_int = TRUE;
1445       parser->limits.reply_timeout = value;
1446     }
1447   else if (strcmp (name, "max_completed_connections") == 0)
1448     {
1449       must_be_positive = TRUE;
1450       must_be_int = TRUE;
1451       parser->limits.max_completed_connections = value;
1452     }
1453   else if (strcmp (name, "max_incomplete_connections") == 0)
1454     {
1455       must_be_positive = TRUE;
1456       must_be_int = TRUE;
1457       parser->limits.max_incomplete_connections = value;
1458     }
1459   else if (strcmp (name, "max_connections_per_user") == 0)
1460     {
1461       must_be_positive = TRUE;
1462       must_be_int = TRUE;
1463       parser->limits.max_connections_per_user = value;
1464     }
1465   else if (strcmp (name, "max_pending_activations") == 0)
1466     {
1467       must_be_positive = TRUE;
1468       must_be_int = TRUE;
1469       parser->limits.max_pending_activations = value;
1470     }
1471   else if (strcmp (name, "max_services_per_connection") == 0)
1472     {
1473       must_be_positive = TRUE;
1474       must_be_int = TRUE;
1475       parser->limits.max_services_per_connection = value;
1476     }
1477   else if (strcmp (name, "max_replies_per_connection") == 0)
1478     {
1479       must_be_positive = TRUE;
1480       must_be_int = TRUE;
1481       parser->limits.max_replies_per_connection = value;
1482     }
1483   else
1484     {
1485       dbus_set_error (error, DBUS_ERROR_FAILED,
1486                       "There is no limit called \"%s\"\n",
1487                       name);
1488       return FALSE;
1489     }
1490   
1491   if (must_be_positive && value < 0)
1492     {
1493       dbus_set_error (error, DBUS_ERROR_FAILED,
1494                       "<limit name=\"%s\"> must be a positive number\n",
1495                       name);
1496       return FALSE;
1497     }
1498
1499   if (must_be_int &&
1500       (value < _DBUS_INT_MIN || value > _DBUS_INT_MAX))
1501     {
1502       dbus_set_error (error, DBUS_ERROR_FAILED,
1503                       "<limit name=\"%s\"> value is too large\n",
1504                       name);
1505       return FALSE;
1506     }
1507
1508   return TRUE;  
1509 }
1510
1511 dbus_bool_t
1512 bus_config_parser_end_element (BusConfigParser   *parser,
1513                                const char        *element_name,
1514                                DBusError         *error)
1515 {
1516   ElementType t;
1517   const char *n;
1518   Element *e;
1519
1520   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1521
1522   /* printf ("END: %s\n", element_name); */
1523   
1524   t = top_element_type (parser);
1525
1526   if (t == ELEMENT_NONE)
1527     {
1528       /* should probably be an assertion failure but
1529        * being paranoid about XML parsers
1530        */
1531       dbus_set_error (error, DBUS_ERROR_FAILED,
1532                       "XML parser ended element with no element on the stack");
1533       return FALSE;
1534     }
1535
1536   n = element_type_to_name (t);
1537   _dbus_assert (n != NULL);
1538   if (strcmp (n, element_name) != 0)
1539     {
1540       /* should probably be an assertion failure but
1541        * being paranoid about XML parsers
1542        */
1543       dbus_set_error (error, DBUS_ERROR_FAILED,
1544                       "XML element <%s> ended but topmost element on the stack was <%s>",
1545                       element_name, n);
1546       return FALSE;
1547     }
1548
1549   e = peek_element (parser);
1550   _dbus_assert (e != NULL);
1551
1552   switch (e->type)
1553     {
1554     case ELEMENT_NONE:
1555       _dbus_assert_not_reached ("element in stack has no type");
1556       break;
1557
1558     case ELEMENT_INCLUDE:
1559     case ELEMENT_USER:
1560     case ELEMENT_TYPE:
1561     case ELEMENT_LISTEN:
1562     case ELEMENT_PIDFILE:
1563     case ELEMENT_AUTH:
1564     case ELEMENT_SERVICEDIR:
1565     case ELEMENT_INCLUDEDIR:
1566     case ELEMENT_LIMIT:
1567       if (!e->had_content)
1568         {
1569           dbus_set_error (error, DBUS_ERROR_FAILED,
1570                           "XML element <%s> was expected to have content inside it",
1571                           element_type_to_name (e->type));
1572           return FALSE;
1573         }
1574
1575       if (e->type == ELEMENT_LIMIT)
1576         {
1577           if (!set_limit (parser, e->d.limit.name, e->d.limit.value,
1578                           error))
1579             return FALSE;
1580         }
1581       break;
1582
1583     case ELEMENT_BUSCONFIG:
1584     case ELEMENT_POLICY:
1585     case ELEMENT_ALLOW:
1586     case ELEMENT_DENY:
1587     case ELEMENT_FORK:
1588       break;
1589     }
1590
1591   pop_element (parser);
1592
1593   return TRUE;
1594 }
1595
1596 static dbus_bool_t
1597 all_whitespace (const DBusString *str)
1598 {
1599   int i;
1600
1601   _dbus_string_skip_white (str, 0, &i);
1602
1603   return i == _dbus_string_get_length (str);
1604 }
1605
1606 static dbus_bool_t
1607 make_full_path (const DBusString *basedir,
1608                 const DBusString *filename,
1609                 DBusString       *full_path)
1610 {
1611   if (_dbus_path_is_absolute (filename))
1612     {
1613       return _dbus_string_copy (filename, 0, full_path, 0);
1614     }
1615   else
1616     {
1617       if (!_dbus_string_copy (basedir, 0, full_path, 0))
1618         return FALSE;
1619       
1620       if (!_dbus_concat_dir_and_file (full_path, filename))
1621         return FALSE;
1622
1623       return TRUE;
1624     }
1625 }
1626
1627 static dbus_bool_t
1628 include_file (BusConfigParser   *parser,
1629               const DBusString  *filename,
1630               dbus_bool_t        ignore_missing,
1631               DBusError         *error)
1632 {
1633   /* FIXME good test case for this would load each config file in the
1634    * test suite both alone, and as an include, and check
1635    * that the result is the same
1636    */
1637   BusConfigParser *included;
1638   DBusError tmp_error;
1639         
1640   dbus_error_init (&tmp_error);
1641
1642   /* Since parser is passed in as the parent, included
1643      inherits parser's limits. */
1644   included = bus_config_load (filename, FALSE, parser, &tmp_error);
1645
1646   if (included == NULL)
1647     {
1648       _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
1649
1650       if (dbus_error_has_name (&tmp_error, DBUS_ERROR_FILE_NOT_FOUND) &&
1651           ignore_missing)
1652         {
1653           dbus_error_free (&tmp_error);
1654           return TRUE;
1655         }
1656       else
1657         {
1658           dbus_move_error (&tmp_error, error);
1659           return FALSE;
1660         }
1661     }
1662   else
1663     {
1664       _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
1665
1666       if (!merge_included (parser, included, error))
1667         {
1668           bus_config_parser_unref (included);
1669           return FALSE;
1670         }
1671
1672       /* Copy included's limits back to parser. */
1673       parser->limits = included->limits;
1674
1675       bus_config_parser_unref (included);
1676       return TRUE;
1677     }
1678 }
1679
1680 static dbus_bool_t
1681 include_dir (BusConfigParser   *parser,
1682              const DBusString  *dirname,
1683              DBusError         *error)
1684 {
1685   DBusString filename;
1686   dbus_bool_t retval;
1687   DBusError tmp_error;
1688   DBusDirIter *dir;
1689   
1690   if (!_dbus_string_init (&filename))
1691     {
1692       BUS_SET_OOM (error);
1693       return FALSE;
1694     }
1695
1696   retval = FALSE;
1697   
1698   dir = _dbus_directory_open (dirname, error);
1699
1700   if (dir == NULL)
1701     goto failed;
1702
1703   dbus_error_init (&tmp_error);
1704   while (_dbus_directory_get_next_file (dir, &filename, &tmp_error))
1705     {
1706       DBusString full_path;
1707
1708       if (!_dbus_string_init (&full_path))
1709         {
1710           BUS_SET_OOM (error);
1711           goto failed;
1712         }
1713
1714       if (!_dbus_string_copy (dirname, 0, &full_path, 0))
1715         {
1716           BUS_SET_OOM (error);
1717           _dbus_string_free (&full_path);
1718           goto failed;
1719         }      
1720
1721       if (!_dbus_concat_dir_and_file (&full_path, &filename))
1722         {
1723           BUS_SET_OOM (error);
1724           _dbus_string_free (&full_path);
1725           goto failed;
1726         }
1727       
1728       if (_dbus_string_ends_with_c_str (&full_path, ".conf"))
1729         {
1730           if (!include_file (parser, &full_path, TRUE, error))
1731             {
1732               _dbus_string_free (&full_path);
1733               goto failed;
1734             }
1735         }
1736
1737       _dbus_string_free (&full_path);
1738     }
1739
1740   if (dbus_error_is_set (&tmp_error))
1741     {
1742       dbus_move_error (&tmp_error, error);
1743       goto failed;
1744     }
1745   
1746   retval = TRUE;
1747   
1748  failed:
1749   _dbus_string_free (&filename);
1750   
1751   if (dir)
1752     _dbus_directory_close (dir);
1753
1754   return retval;
1755 }
1756
1757 dbus_bool_t
1758 bus_config_parser_content (BusConfigParser   *parser,
1759                            const DBusString  *content,
1760                            DBusError         *error)
1761 {
1762   Element *e;
1763
1764   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1765
1766 #if 0
1767   {
1768     const char *c_str;
1769     
1770     _dbus_string_get_const_data (content, &c_str);
1771
1772     printf ("CONTENT %d bytes: %s\n", _dbus_string_get_length (content), c_str);
1773   }
1774 #endif
1775   
1776   e = peek_element (parser);
1777   if (e == NULL)
1778     {
1779       dbus_set_error (error, DBUS_ERROR_FAILED,
1780                       "Text content outside of any XML element in configuration file");
1781       return FALSE;
1782     }
1783   else if (e->had_content)
1784     {
1785       _dbus_assert_not_reached ("Element had multiple content blocks");
1786       return FALSE;
1787     }
1788
1789   switch (top_element_type (parser))
1790     {
1791     case ELEMENT_NONE:
1792       _dbus_assert_not_reached ("element at top of stack has no type");
1793       return FALSE;
1794
1795     case ELEMENT_BUSCONFIG:
1796     case ELEMENT_POLICY:
1797     case ELEMENT_ALLOW:
1798     case ELEMENT_DENY:
1799     case ELEMENT_FORK:
1800       if (all_whitespace (content))
1801         return TRUE;
1802       else
1803         {
1804           dbus_set_error (error, DBUS_ERROR_FAILED,
1805                           "No text content expected inside XML element %s in configuration file",
1806                           element_type_to_name (top_element_type (parser)));
1807           return FALSE;
1808         }
1809
1810     case ELEMENT_PIDFILE:
1811       {
1812         char *s;
1813
1814         e->had_content = TRUE;
1815         
1816         if (!_dbus_string_copy_data (content, &s))
1817           goto nomem;
1818           
1819         dbus_free (parser->pidfile);
1820         parser->pidfile = s;
1821       }
1822       break;
1823
1824     case ELEMENT_INCLUDE:
1825       {
1826         DBusString full_path;
1827         
1828         e->had_content = TRUE;
1829
1830         if (!_dbus_string_init (&full_path))
1831           goto nomem;
1832         
1833         if (!make_full_path (&parser->basedir, content, &full_path))
1834           {
1835             _dbus_string_free (&full_path);
1836             goto nomem;
1837           }
1838         
1839         if (!include_file (parser, &full_path,
1840                            e->d.include.ignore_missing, error))
1841           {
1842             _dbus_string_free (&full_path);
1843             return FALSE;
1844           }
1845
1846         _dbus_string_free (&full_path);
1847       }
1848       break;
1849
1850     case ELEMENT_INCLUDEDIR:
1851       {
1852         DBusString full_path;
1853         
1854         e->had_content = TRUE;
1855
1856         if (!_dbus_string_init (&full_path))
1857           goto nomem;
1858         
1859         if (!make_full_path (&parser->basedir, content, &full_path))
1860           {
1861             _dbus_string_free (&full_path);
1862             goto nomem;
1863           }
1864         
1865         if (!include_dir (parser, &full_path, error))
1866           {
1867             _dbus_string_free (&full_path);
1868             return FALSE;
1869           }
1870
1871         _dbus_string_free (&full_path);
1872       }
1873       break;
1874       
1875     case ELEMENT_USER:
1876       {
1877         char *s;
1878
1879         e->had_content = TRUE;
1880         
1881         if (!_dbus_string_copy_data (content, &s))
1882           goto nomem;
1883           
1884         dbus_free (parser->user);
1885         parser->user = s;
1886       }
1887       break;
1888
1889     case ELEMENT_TYPE:
1890       {
1891         char *s;
1892
1893         e->had_content = TRUE;
1894
1895         if (!_dbus_string_copy_data (content, &s))
1896           goto nomem;
1897         
1898         dbus_free (parser->bus_type);
1899         parser->bus_type = s;
1900       }
1901       break;
1902       
1903     case ELEMENT_LISTEN:
1904       {
1905         char *s;
1906
1907         e->had_content = TRUE;
1908         
1909         if (!_dbus_string_copy_data (content, &s))
1910           goto nomem;
1911
1912         if (!_dbus_list_append (&parser->listen_on,
1913                                 s))
1914           {
1915             dbus_free (s);
1916             goto nomem;
1917           }
1918       }
1919       break;
1920
1921     case ELEMENT_AUTH:
1922       {
1923         char *s;
1924         
1925         e->had_content = TRUE;
1926
1927         if (!_dbus_string_copy_data (content, &s))
1928           goto nomem;
1929
1930         if (!_dbus_list_append (&parser->mechanisms,
1931                                 s))
1932           {
1933             dbus_free (s);
1934             goto nomem;
1935           }
1936       }
1937       break;
1938
1939     case ELEMENT_SERVICEDIR:
1940       {
1941         char *s;
1942         DBusString full_path;
1943         
1944         e->had_content = TRUE;
1945
1946         if (!_dbus_string_init (&full_path))
1947           goto nomem;
1948         
1949         if (!make_full_path (&parser->basedir, content, &full_path))
1950           {
1951             _dbus_string_free (&full_path);
1952             goto nomem;
1953           }
1954         
1955         if (!_dbus_string_copy_data (&full_path, &s))
1956           {
1957             _dbus_string_free (&full_path);
1958             goto nomem;
1959           }
1960
1961         if (!_dbus_list_append (&parser->service_dirs, s))
1962           {
1963             _dbus_string_free (&full_path);
1964             dbus_free (s);
1965             goto nomem;
1966           }
1967
1968         _dbus_string_free (&full_path);
1969       }
1970       break;
1971
1972     case ELEMENT_LIMIT:
1973       {
1974         long val;
1975
1976         e->had_content = TRUE;
1977
1978         val = 0;
1979         if (!_dbus_string_parse_int (content, 0, &val, NULL))
1980           {
1981             dbus_set_error (error, DBUS_ERROR_FAILED,
1982                             "<limit name=\"%s\"> element has invalid value (could not parse as integer)",
1983                             e->d.limit.name);
1984             return FALSE;
1985           }
1986
1987         e->d.limit.value = val;
1988
1989         _dbus_verbose ("Loaded value %ld for limit %s\n",
1990                        e->d.limit.value,
1991                        e->d.limit.name);
1992       }
1993       break;
1994     }
1995
1996   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1997   return TRUE;
1998
1999  nomem:
2000   BUS_SET_OOM (error);
2001   return FALSE;
2002 }
2003
2004 dbus_bool_t
2005 bus_config_parser_finished (BusConfigParser   *parser,
2006                             DBusError         *error)
2007 {
2008   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2009
2010   if (parser->stack != NULL)
2011     {
2012       dbus_set_error (error, DBUS_ERROR_FAILED,
2013                       "Element <%s> was not closed in configuration file",
2014                       element_type_to_name (top_element_type (parser)));
2015
2016       return FALSE;
2017     }
2018
2019   if (parser->is_toplevel && parser->listen_on == NULL)
2020     {
2021       dbus_set_error (error, DBUS_ERROR_FAILED,
2022                       "Configuration file needs one or more <listen> elements giving addresses"); 
2023       return FALSE;
2024     }
2025   
2026   return TRUE;
2027 }
2028
2029 const char*
2030 bus_config_parser_get_user (BusConfigParser *parser)
2031 {
2032   return parser->user;
2033 }
2034
2035 const char*
2036 bus_config_parser_get_type (BusConfigParser *parser)
2037 {
2038   return parser->bus_type;
2039 }
2040
2041 DBusList**
2042 bus_config_parser_get_addresses (BusConfigParser *parser)
2043 {
2044   return &parser->listen_on;
2045 }
2046
2047 DBusList**
2048 bus_config_parser_get_mechanisms (BusConfigParser *parser)
2049 {
2050   return &parser->mechanisms;
2051 }
2052
2053 DBusList**
2054 bus_config_parser_get_service_dirs (BusConfigParser *parser)
2055 {
2056   return &parser->service_dirs;
2057 }
2058
2059 dbus_bool_t
2060 bus_config_parser_get_fork (BusConfigParser   *parser)
2061 {
2062   return parser->fork;
2063 }
2064
2065 const char *
2066 bus_config_parser_get_pidfile (BusConfigParser   *parser)
2067 {
2068   return parser->pidfile;
2069 }
2070
2071 BusPolicy*
2072 bus_config_parser_steal_policy (BusConfigParser *parser)
2073 {
2074   BusPolicy *policy;
2075
2076   _dbus_assert (parser->policy != NULL); /* can only steal the policy 1 time */
2077   
2078   policy = parser->policy;
2079
2080   parser->policy = NULL;
2081
2082   return policy;
2083 }
2084
2085 /* Overwrite any limits that were set in the configuration file */
2086 void
2087 bus_config_parser_get_limits (BusConfigParser *parser,
2088                               BusLimits       *limits)
2089 {
2090   *limits = parser->limits;
2091 }
2092
2093 #ifdef DBUS_BUILD_TESTS
2094 #include <stdio.h>
2095
2096 typedef enum
2097 {
2098   VALID,
2099   INVALID,
2100   UNKNOWN
2101 } Validity;
2102
2103 static dbus_bool_t
2104 do_load (const DBusString *full_path,
2105          Validity          validity,
2106          dbus_bool_t       oom_possible)
2107 {
2108   BusConfigParser *parser;
2109   DBusError error;
2110
2111   dbus_error_init (&error);
2112
2113   parser = bus_config_load (full_path, TRUE, NULL, &error);
2114   if (parser == NULL)
2115     {
2116       _DBUS_ASSERT_ERROR_IS_SET (&error);
2117
2118       if (oom_possible &&
2119           dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
2120         {
2121           _dbus_verbose ("Failed to load valid file due to OOM\n");
2122           dbus_error_free (&error);
2123           return TRUE;
2124         }
2125       else if (validity == VALID)
2126         {
2127           _dbus_warn ("Failed to load valid file but still had memory: %s\n",
2128                       error.message);
2129
2130           dbus_error_free (&error);
2131           return FALSE;
2132         }
2133       else
2134         {
2135           dbus_error_free (&error);
2136           return TRUE;
2137         }
2138     }
2139   else
2140     {
2141       _DBUS_ASSERT_ERROR_IS_CLEAR (&error);
2142
2143       bus_config_parser_unref (parser);
2144
2145       if (validity == INVALID)
2146         {
2147           _dbus_warn ("Accepted invalid file\n");
2148           return FALSE;
2149         }
2150
2151       return TRUE;
2152     }
2153 }
2154
2155 typedef struct
2156 {
2157   const DBusString *full_path;
2158   Validity          validity;
2159 } LoaderOomData;
2160
2161 static dbus_bool_t
2162 check_loader_oom_func (void *data)
2163 {
2164   LoaderOomData *d = data;
2165
2166   return do_load (d->full_path, d->validity, TRUE);
2167 }
2168
2169 static dbus_bool_t
2170 process_test_valid_subdir (const DBusString *test_base_dir,
2171                            const char       *subdir,
2172                            Validity          validity)
2173 {
2174   DBusString test_directory;
2175   DBusString filename;
2176   DBusDirIter *dir;
2177   dbus_bool_t retval;
2178   DBusError error;
2179
2180   retval = FALSE;
2181   dir = NULL;
2182
2183   if (!_dbus_string_init (&test_directory))
2184     _dbus_assert_not_reached ("didn't allocate test_directory\n");
2185
2186   _dbus_string_init_const (&filename, subdir);
2187
2188   if (!_dbus_string_copy (test_base_dir, 0,
2189                           &test_directory, 0))
2190     _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
2191
2192   if (!_dbus_concat_dir_and_file (&test_directory, &filename))
2193     _dbus_assert_not_reached ("couldn't allocate full path");
2194
2195   _dbus_string_free (&filename);
2196   if (!_dbus_string_init (&filename))
2197     _dbus_assert_not_reached ("didn't allocate filename string\n");
2198
2199   dbus_error_init (&error);
2200   dir = _dbus_directory_open (&test_directory, &error);
2201   if (dir == NULL)
2202     {
2203       _dbus_warn ("Could not open %s: %s\n",
2204                   _dbus_string_get_const_data (&test_directory),
2205                   error.message);
2206       dbus_error_free (&error);
2207       goto failed;
2208     }
2209
2210   printf ("Testing:\n");
2211
2212  next:
2213   while (_dbus_directory_get_next_file (dir, &filename, &error))
2214     {
2215       DBusString full_path;
2216       LoaderOomData d;
2217
2218       if (!_dbus_string_init (&full_path))
2219         _dbus_assert_not_reached ("couldn't init string");
2220
2221       if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
2222         _dbus_assert_not_reached ("couldn't copy dir to full_path");
2223
2224       if (!_dbus_concat_dir_and_file (&full_path, &filename))
2225         _dbus_assert_not_reached ("couldn't concat file to dir");
2226
2227       if (!_dbus_string_ends_with_c_str (&full_path, ".conf"))
2228         {
2229           _dbus_verbose ("Skipping non-.conf file %s\n",
2230                          _dbus_string_get_const_data (&filename));
2231           _dbus_string_free (&full_path);
2232           goto next;
2233         }
2234
2235       printf ("    %s\n", _dbus_string_get_const_data (&filename));
2236
2237       _dbus_verbose (" expecting %s\n",
2238                      validity == VALID ? "valid" :
2239                      (validity == INVALID ? "invalid" :
2240                       (validity == UNKNOWN ? "unknown" : "???")));
2241
2242       d.full_path = &full_path;
2243       d.validity = validity;
2244       if (!_dbus_test_oom_handling ("config-loader", check_loader_oom_func, &d))
2245         _dbus_assert_not_reached ("test failed");
2246
2247       _dbus_string_free (&full_path);
2248     }
2249
2250   if (dbus_error_is_set (&error))
2251     {
2252       _dbus_warn ("Could not get next file in %s: %s\n",
2253                   _dbus_string_get_const_data (&test_directory),
2254                   error.message);
2255       dbus_error_free (&error);
2256       goto failed;
2257     }
2258
2259   retval = TRUE;
2260
2261  failed:
2262
2263   if (dir)
2264     _dbus_directory_close (dir);
2265   _dbus_string_free (&test_directory);
2266   _dbus_string_free (&filename);
2267
2268   return retval;
2269 }
2270
2271 static dbus_bool_t
2272 bools_equal (dbus_bool_t a,
2273              dbus_bool_t b)
2274 {
2275   return a ? b : !b;
2276 }
2277
2278 static dbus_bool_t
2279 strings_equal_or_both_null (const char *a,
2280                             const char *b)
2281 {
2282   if (a == NULL || b == NULL)
2283     return a == b;
2284   else
2285     return !strcmp (a, b);
2286 }
2287
2288 static dbus_bool_t
2289 elements_equal (const Element *a,
2290                 const Element *b)
2291 {
2292   if (a->type != b->type)
2293     return FALSE;
2294
2295   if (!bools_equal (a->had_content, b->had_content))
2296     return FALSE;
2297
2298   switch (a->type)
2299     {
2300
2301     case ELEMENT_INCLUDE:
2302       if (!bools_equal (a->d.include.ignore_missing,
2303                         b->d.include.ignore_missing))
2304         return FALSE;
2305       break;
2306
2307     case ELEMENT_POLICY:
2308       if (a->d.policy.type != b->d.policy.type)
2309         return FALSE;
2310       if (a->d.policy.gid_or_uid != b->d.policy.gid_or_uid)
2311         return FALSE;
2312       break;
2313
2314     case ELEMENT_LIMIT:
2315       if (strcmp (a->d.limit.name, b->d.limit.name))
2316         return FALSE;
2317       if (a->d.limit.value != b->d.limit.value)
2318         return FALSE;
2319       break;
2320
2321     default:
2322       /* do nothing */
2323       break;
2324     }
2325
2326   return TRUE;
2327
2328 }
2329
2330 static dbus_bool_t
2331 lists_of_elements_equal (DBusList *a,
2332                          DBusList *b)
2333 {
2334   DBusList *ia;
2335   DBusList *ib;
2336
2337   ia = a;
2338   ib = b;
2339   
2340   while (ia != NULL && ib != NULL)
2341     {
2342       if (elements_equal (ia->data, ib->data))
2343         return FALSE;
2344       ia = _dbus_list_get_next_link (&a, ia);
2345       ib = _dbus_list_get_next_link (&b, ib);
2346     }
2347
2348   return ia == NULL && ib == NULL;
2349 }
2350
2351 static dbus_bool_t
2352 lists_of_c_strings_equal (DBusList *a,
2353                           DBusList *b)
2354 {
2355   DBusList *ia;
2356   DBusList *ib;
2357
2358   ia = a;
2359   ib = b;
2360   
2361   while (ia != NULL && ib != NULL)
2362     {
2363       if (strcmp (ia->data, ib->data))
2364         return FALSE;
2365       ia = _dbus_list_get_next_link (&a, ia);
2366       ib = _dbus_list_get_next_link (&b, ib);
2367     }
2368
2369   return ia == NULL && ib == NULL;
2370 }
2371
2372 static dbus_bool_t
2373 limits_equal (const BusLimits *a,
2374               const BusLimits *b)
2375 {
2376   return
2377     (a->max_incoming_bytes == b->max_incoming_bytes
2378      || a->max_outgoing_bytes == b->max_outgoing_bytes
2379      || a->max_message_size == b->max_message_size
2380      || a->activation_timeout == b->activation_timeout
2381      || a->auth_timeout == b->auth_timeout
2382      || a->max_completed_connections == b->max_completed_connections
2383      || a->max_incomplete_connections == b->max_incomplete_connections
2384      || a->max_connections_per_user == b->max_connections_per_user
2385      || a->max_pending_activations == b->max_pending_activations
2386      || a->max_services_per_connection == b->max_services_per_connection
2387      || a->max_match_rules_per_connection == b->max_match_rules_per_connection
2388      || a->max_replies_per_connection == b->max_replies_per_connection
2389      || a->reply_timeout == b->reply_timeout);
2390 }
2391
2392 static dbus_bool_t
2393 config_parsers_equal (const BusConfigParser *a,
2394                       const BusConfigParser *b)
2395 {
2396   if (!_dbus_string_equal (&a->basedir, &b->basedir))
2397     return FALSE;
2398
2399   if (!lists_of_elements_equal (a->stack, b->stack))
2400     return FALSE;
2401
2402   if (!strings_equal_or_both_null (a->user, b->user))
2403     return FALSE;
2404
2405   if (!lists_of_c_strings_equal (a->listen_on, b->listen_on))
2406     return FALSE;
2407
2408   if (!lists_of_c_strings_equal (a->mechanisms, b->mechanisms))
2409     return FALSE;
2410
2411   if (!lists_of_c_strings_equal (a->service_dirs, b->service_dirs))
2412     return FALSE;
2413   
2414   /* FIXME: compare policy */
2415
2416   if (! limits_equal (&a->limits, &b->limits))
2417     return FALSE;
2418
2419   if (!strings_equal_or_both_null (a->pidfile, b->pidfile))
2420     return FALSE;
2421
2422   if (! bools_equal (a->fork, b->fork))
2423     return FALSE;
2424
2425   if (! bools_equal (a->is_toplevel, b->is_toplevel))
2426     return FALSE;
2427
2428   return TRUE;
2429 }
2430
2431 static dbus_bool_t
2432 all_are_equiv (const DBusString *target_directory)
2433 {
2434   DBusString filename;
2435   DBusDirIter *dir;
2436   BusConfigParser *first_parser;
2437   BusConfigParser *parser;
2438   DBusError error;
2439   dbus_bool_t equal;
2440   dbus_bool_t retval;
2441
2442   dir = NULL;
2443   first_parser = NULL;
2444   parser = NULL;
2445   retval = FALSE;
2446
2447   if (!_dbus_string_init (&filename))
2448     _dbus_assert_not_reached ("didn't allocate filename string");
2449
2450   dbus_error_init (&error);
2451   dir = _dbus_directory_open (target_directory, &error);
2452   if (dir == NULL)
2453     {
2454       _dbus_warn ("Could not open %s: %s\n",
2455                   _dbus_string_get_const_data (target_directory),
2456                   error.message);
2457       dbus_error_free (&error);
2458       goto finished;
2459     }
2460
2461   printf ("Comparing:\n");
2462
2463  next:
2464   while (_dbus_directory_get_next_file (dir, &filename, &error))
2465     {
2466       DBusString full_path;
2467
2468       if (!_dbus_string_init (&full_path))
2469         _dbus_assert_not_reached ("couldn't init string");
2470
2471       if (!_dbus_string_copy (target_directory, 0, &full_path, 0))
2472         _dbus_assert_not_reached ("couldn't copy dir to full_path");
2473
2474       if (!_dbus_concat_dir_and_file (&full_path, &filename))
2475         _dbus_assert_not_reached ("couldn't concat file to dir");
2476
2477       if (!_dbus_string_ends_with_c_str (&full_path, ".conf"))
2478         {
2479           _dbus_verbose ("Skipping non-.conf file %s\n",
2480                          _dbus_string_get_const_data (&filename));
2481           _dbus_string_free (&full_path);
2482           goto next;
2483         }
2484
2485       printf ("    %s\n", _dbus_string_get_const_data (&filename));
2486
2487       parser = bus_config_load (&full_path, TRUE, NULL, &error);
2488       _dbus_string_free (&full_path);
2489
2490       if (parser == NULL)
2491         {
2492           _dbus_warn ("Could not load file %s: %s\n",
2493                       _dbus_string_get_const_data (&full_path),
2494                       error.message);
2495           dbus_error_free (&error);
2496           goto finished;
2497         }
2498       else if (first_parser == NULL)
2499         {
2500           first_parser = parser;
2501         }
2502       else
2503         {
2504           equal = config_parsers_equal (first_parser, parser);
2505           bus_config_parser_unref (parser);
2506           if (! equal)
2507             goto finished;
2508         }
2509
2510     }
2511
2512   retval = TRUE;
2513
2514  finished:
2515   _dbus_string_free (&filename);
2516   if (first_parser)
2517     bus_config_parser_unref (first_parser);
2518   if (dir)
2519     _dbus_directory_close (dir);
2520
2521   return retval;
2522   
2523 }
2524
2525 static dbus_bool_t
2526 process_test_equiv_subdir (const DBusString *test_base_dir,
2527                            const char       *subdir)
2528 {
2529   DBusString test_directory;
2530   DBusString filename;
2531   DBusDirIter *dir;
2532   DBusError error;
2533   dbus_bool_t equal;
2534   dbus_bool_t retval;
2535
2536   dir = NULL;
2537   retval = FALSE;
2538
2539   if (!_dbus_string_init (&test_directory))
2540     _dbus_assert_not_reached ("didn't allocate test_directory");
2541
2542   _dbus_string_init_const (&filename, subdir);
2543
2544   if (!_dbus_string_copy (test_base_dir, 0,
2545                           &test_directory, 0))
2546     _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
2547
2548   if (!_dbus_concat_dir_and_file (&test_directory, &filename))
2549     _dbus_assert_not_reached ("couldn't allocate full path");
2550
2551   _dbus_string_free (&filename);
2552   if (!_dbus_string_init (&filename))
2553     _dbus_assert_not_reached ("didn't allocate filename string");
2554
2555   dbus_error_init (&error);
2556   dir = _dbus_directory_open (&test_directory, &error);
2557   if (dir == NULL)
2558     {
2559       _dbus_warn ("Could not open %s: %s\n",
2560                   _dbus_string_get_const_data (&test_directory),
2561                   error.message);
2562       dbus_error_free (&error);
2563       goto finished;
2564     }
2565
2566   while (_dbus_directory_get_next_file (dir, &filename, &error))
2567     {
2568       DBusString full_path;
2569
2570       /* Skip CVS's magic directories! */
2571       if (_dbus_string_equal_c_str (&filename, "CVS"))
2572         continue;
2573
2574       if (!_dbus_string_init (&full_path))
2575         _dbus_assert_not_reached ("couldn't init string");
2576
2577       if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
2578         _dbus_assert_not_reached ("couldn't copy dir to full_path");
2579
2580       if (!_dbus_concat_dir_and_file (&full_path, &filename))
2581         _dbus_assert_not_reached ("couldn't concat file to dir");
2582       
2583       equal = all_are_equiv (&full_path);
2584       _dbus_string_free (&full_path);
2585
2586       if (!equal)
2587         goto finished;
2588     }
2589
2590   retval = TRUE;
2591
2592  finished:
2593   _dbus_string_free (&test_directory);
2594   _dbus_string_free (&filename);
2595   if (dir)
2596     _dbus_directory_close (dir);
2597
2598   return retval;
2599   
2600 }
2601                            
2602 dbus_bool_t
2603 bus_config_parser_test (const DBusString *test_data_dir)
2604 {
2605   if (test_data_dir == NULL ||
2606       _dbus_string_get_length (test_data_dir) == 0)
2607     {
2608       printf ("No test data\n");
2609       return TRUE;
2610     }
2611
2612   if (!process_test_valid_subdir (test_data_dir, "valid-config-files", VALID))
2613     return FALSE;
2614
2615   if (!process_test_equiv_subdir (test_data_dir, "equiv-config-files"))
2616     return FALSE;
2617
2618   return TRUE;
2619 }
2620
2621 #endif /* DBUS_BUILD_TESTS */
2622