85c367b3cde925ffdc16e1fd5de36de1ba557b5b
[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 1.2
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   } d;
82
83 } Element;
84
85 struct BusConfigParser
86 {
87   int refcount;
88
89   DBusString basedir;  /**< Directory we resolve paths relative to */
90   
91   DBusList *stack;     /**< stack of Element */
92
93   char *user;          /**< user to run as */
94
95   char *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 services in */
102
103   BusPolicy *policy;     /**< Security policy */
104   
105   unsigned int fork : 1; /**< TRUE to fork into daemon mode */
106
107   char *pidfile;
108 };
109
110 static const char*
111 element_type_to_name (ElementType type)
112 {
113   switch (type)
114     {
115     case ELEMENT_NONE:
116       return NULL;
117     case ELEMENT_BUSCONFIG:
118       return "busconfig";
119     case ELEMENT_INCLUDE:
120       return "include";
121     case ELEMENT_USER:
122       return "user";
123     case ELEMENT_LISTEN:
124       return "listen";
125     case ELEMENT_AUTH:
126       return "auth";
127     case ELEMENT_POLICY:
128       return "policy";
129     case ELEMENT_LIMIT:
130       return "limit";
131     case ELEMENT_ALLOW:
132       return "allow";
133     case ELEMENT_DENY:
134       return "deny";
135     case ELEMENT_FORK:
136       return "fork";
137     case ELEMENT_PIDFILE:
138       return "pidfile";
139     case ELEMENT_SERVICEDIR:
140       return "servicedir";
141     case ELEMENT_INCLUDEDIR:
142       return "includedir";
143     case ELEMENT_TYPE:
144       return "type";
145     }
146
147   _dbus_assert_not_reached ("bad element type");
148
149   return NULL;
150 }
151
152 static Element*
153 push_element (BusConfigParser *parser,
154               ElementType      type)
155 {
156   Element *e;
157
158   _dbus_assert (type != ELEMENT_NONE);
159   
160   e = dbus_new0 (Element, 1);
161   if (e == NULL)
162     return NULL;
163
164   if (!_dbus_list_append (&parser->stack, e))
165     {
166       dbus_free (e);
167       return NULL;
168     }
169   
170   e->type = type;
171
172   return e;
173 }
174
175 static void
176 element_free (Element *e)
177 {
178
179   dbus_free (e);
180 }
181
182 static void
183 pop_element (BusConfigParser *parser)
184 {
185   Element *e;
186
187   e = _dbus_list_pop_last (&parser->stack);
188   
189   element_free (e);
190 }
191
192 static Element*
193 peek_element (BusConfigParser *parser)
194 {
195   Element *e;
196
197   e = _dbus_list_get_last (&parser->stack);
198
199   return e;
200 }
201
202 static ElementType
203 top_element_type (BusConfigParser *parser)
204 {
205   Element *e;
206
207   e = _dbus_list_get_last (&parser->stack);
208
209   if (e)
210     return e->type;
211   else
212     return ELEMENT_NONE;
213 }
214
215 static dbus_bool_t
216 merge_included (BusConfigParser *parser,
217                 BusConfigParser *included,
218                 DBusError       *error)
219 {
220   DBusList *link;
221
222   if (included->user != NULL)
223     {
224       dbus_free (parser->user);
225       parser->user = included->user;
226       included->user = NULL;
227     }
228
229   if (included->bus_type != NULL)
230     {
231       dbus_free (parser->bus_type);
232       parser->bus_type = included->bus_type;
233       included->bus_type = NULL;
234     }
235   
236   if (included->fork)
237     parser->fork = TRUE;
238
239   if (included->pidfile != NULL)
240     {
241       dbus_free (parser->pidfile);
242       parser->pidfile = included->pidfile;
243       included->pidfile = NULL;
244     }
245   
246   while ((link = _dbus_list_pop_first_link (&included->listen_on)))
247     _dbus_list_append_link (&parser->listen_on, link);
248
249   while ((link = _dbus_list_pop_first_link (&included->mechanisms)))
250     _dbus_list_append_link (&parser->mechanisms, link);
251
252   while ((link = _dbus_list_pop_first_link (&included->service_dirs)))
253     _dbus_list_append_link (&parser->service_dirs, link);
254   
255   return TRUE;
256 }
257
258 BusConfigParser*
259 bus_config_parser_new (const DBusString *basedir)
260 {
261   BusConfigParser *parser;
262
263   parser = dbus_new0 (BusConfigParser, 1);
264   if (parser == NULL)
265     return NULL;
266
267   if (!_dbus_string_init (&parser->basedir))
268     {
269       dbus_free (parser);
270       return NULL;
271     }
272
273   if (((parser->policy = bus_policy_new ()) == NULL) ||
274       !_dbus_string_copy (basedir, 0, &parser->basedir, 0))
275     {
276       if (parser->policy)
277         bus_policy_unref (parser->policy);
278       
279       _dbus_string_free (&parser->basedir);
280       dbus_free (parser);
281       return NULL;
282     }
283   
284   parser->refcount = 1;
285
286   return parser;
287 }
288
289 void
290 bus_config_parser_ref (BusConfigParser *parser)
291 {
292   _dbus_assert (parser->refcount > 0);
293
294   parser->refcount += 1;
295 }
296
297 void
298 bus_config_parser_unref (BusConfigParser *parser)
299 {
300   _dbus_assert (parser->refcount > 0);
301
302   parser->refcount -= 1;
303
304   if (parser->refcount == 0)
305     {
306       while (parser->stack != NULL)
307         pop_element (parser);
308
309       dbus_free (parser->user);
310       dbus_free (parser->bus_type);
311       dbus_free (parser->pidfile);
312       
313       _dbus_list_foreach (&parser->listen_on,
314                           (DBusForeachFunction) dbus_free,
315                           NULL);
316
317       _dbus_list_clear (&parser->listen_on);
318
319       _dbus_list_foreach (&parser->service_dirs,
320                           (DBusForeachFunction) dbus_free,
321                           NULL);
322
323       _dbus_list_clear (&parser->service_dirs);
324
325       _dbus_list_foreach (&parser->mechanisms,
326                           (DBusForeachFunction) dbus_free,
327                           NULL);
328
329       _dbus_list_clear (&parser->mechanisms);
330       
331       _dbus_string_free (&parser->basedir);
332
333       if (parser->policy)
334         bus_policy_unref (parser->policy);
335       
336       dbus_free (parser);
337     }
338 }
339
340 dbus_bool_t
341 bus_config_parser_check_doctype (BusConfigParser   *parser,
342                                  const char        *doctype,
343                                  DBusError         *error)
344 {
345   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
346
347   if (strcmp (doctype, "busconfig") != 0)
348     {
349       dbus_set_error (error,
350                       DBUS_ERROR_FAILED,
351                       "Configuration file has the wrong document type %s",
352                       doctype);
353       return FALSE;
354     }
355   else
356     return TRUE;
357 }
358
359 typedef struct
360 {
361   const char  *name;
362   const char **retloc;
363 } LocateAttr;
364
365 static dbus_bool_t
366 locate_attributes (BusConfigParser  *parser,
367                    const char       *element_name,
368                    const char      **attribute_names,
369                    const char      **attribute_values,
370                    DBusError        *error,
371                    const char       *first_attribute_name,
372                    const char      **first_attribute_retloc,
373                    ...)
374 {
375   va_list args;
376   const char *name;
377   const char **retloc;
378   int n_attrs;
379 #define MAX_ATTRS 24
380   LocateAttr attrs[MAX_ATTRS];
381   dbus_bool_t retval;
382   int i;
383
384   _dbus_assert (first_attribute_name != NULL);
385   _dbus_assert (first_attribute_retloc != NULL);
386
387   retval = TRUE;
388
389   n_attrs = 1;
390   attrs[0].name = first_attribute_name;
391   attrs[0].retloc = first_attribute_retloc;
392   *first_attribute_retloc = NULL;
393
394   va_start (args, first_attribute_retloc);
395
396   name = va_arg (args, const char*);
397   retloc = va_arg (args, const char**);
398
399   while (name != NULL)
400     {
401       _dbus_assert (retloc != NULL);
402       _dbus_assert (n_attrs < MAX_ATTRS);
403
404       attrs[n_attrs].name = name;
405       attrs[n_attrs].retloc = retloc;
406       n_attrs += 1;
407       *retloc = NULL;
408
409       name = va_arg (args, const char*);
410       retloc = va_arg (args, const char**);
411     }
412
413   va_end (args);
414
415   if (!retval)
416     return retval;
417
418   i = 0;
419   while (attribute_names[i])
420     {
421       int j;
422       dbus_bool_t found;
423       
424       found = FALSE;
425       j = 0;
426       while (j < n_attrs)
427         {
428           if (strcmp (attrs[j].name, attribute_names[i]) == 0)
429             {
430               retloc = attrs[j].retloc;
431
432               if (*retloc != NULL)
433                 {
434                   dbus_set_error (error, DBUS_ERROR_FAILED,
435                                   "Attribute \"%s\" repeated twice on the same <%s> element",
436                                   attrs[j].name, element_name);
437                   retval = FALSE;
438                   goto out;
439                 }
440
441               *retloc = attribute_values[i];
442               found = TRUE;
443             }
444
445           ++j;
446         }
447
448       if (!found)
449         {
450           dbus_set_error (error, DBUS_ERROR_FAILED,
451                           "Attribute \"%s\" is invalid on <%s> element in this context",
452                           attribute_names[i], element_name);
453           retval = FALSE;
454           goto out;
455         }
456
457       ++i;
458     }
459
460  out:
461   return retval;
462 }
463
464 static dbus_bool_t
465 check_no_attributes (BusConfigParser  *parser,
466                      const char       *element_name,
467                      const char      **attribute_names,
468                      const char      **attribute_values,
469                      DBusError        *error)
470 {
471   if (attribute_names[0] != NULL)
472     {
473       dbus_set_error (error, DBUS_ERROR_FAILED,
474                       "Attribute \"%s\" is invalid on <%s> element in this context",
475                       attribute_names[0], element_name);
476       return FALSE;
477     }
478
479   return TRUE;
480 }
481
482 static dbus_bool_t
483 start_busconfig_child (BusConfigParser   *parser,
484                        const char        *element_name,
485                        const char       **attribute_names,
486                        const char       **attribute_values,
487                        DBusError         *error)
488 {
489   if (strcmp (element_name, "user") == 0)
490     {
491       if (!check_no_attributes (parser, "user", attribute_names, attribute_values, error))
492         return FALSE;
493
494       if (push_element (parser, ELEMENT_USER) == NULL)
495         {
496           BUS_SET_OOM (error);
497           return FALSE;
498         }
499
500       return TRUE;
501     }
502   else if (strcmp (element_name, "type") == 0)
503     {
504       if (!check_no_attributes (parser, "type", attribute_names, attribute_values, error))
505         return FALSE;
506
507       if (push_element (parser, ELEMENT_TYPE) == NULL)
508         {
509           BUS_SET_OOM (error);
510           return FALSE;
511         }
512
513       return TRUE;
514     }
515   else if (strcmp (element_name, "fork") == 0)
516     {
517       if (!check_no_attributes (parser, "fork", attribute_names, attribute_values, error))
518         return FALSE;
519
520       if (push_element (parser, ELEMENT_FORK) == NULL)
521         {
522           BUS_SET_OOM (error);
523           return FALSE;
524         }
525
526       parser->fork = TRUE;
527       
528       return TRUE;
529     }
530   else if (strcmp (element_name, "pidfile") == 0)
531     {
532       if (!check_no_attributes (parser, "pidfile", attribute_names, attribute_values, error))
533         return FALSE;
534
535       if (push_element (parser, ELEMENT_PIDFILE) == NULL)
536         {
537           BUS_SET_OOM (error);
538           return FALSE;
539         }
540
541       return TRUE;
542     }
543   else if (strcmp (element_name, "listen") == 0)
544     {
545       if (!check_no_attributes (parser, "listen", attribute_names, attribute_values, error))
546         return FALSE;
547
548       if (push_element (parser, ELEMENT_LISTEN) == NULL)
549         {
550           BUS_SET_OOM (error);
551           return FALSE;
552         }
553
554       return TRUE;
555     }
556   else if (strcmp (element_name, "auth") == 0)
557     {
558       if (!check_no_attributes (parser, "auth", attribute_names, attribute_values, error))
559         return FALSE;
560
561       if (push_element (parser, ELEMENT_AUTH) == NULL)
562         {
563           BUS_SET_OOM (error);
564           return FALSE;
565         }
566
567       return TRUE;
568     }
569   else if (strcmp (element_name, "includedir") == 0)
570     {
571       if (!check_no_attributes (parser, "includedir", attribute_names, attribute_values, error))
572         return FALSE;
573
574       if (push_element (parser, ELEMENT_INCLUDEDIR) == NULL)
575         {
576           BUS_SET_OOM (error);
577           return FALSE;
578         }
579
580       return TRUE;
581     }
582   else if (strcmp (element_name, "servicedir") == 0)
583     {
584       if (!check_no_attributes (parser, "servicedir", attribute_names, attribute_values, error))
585         return FALSE;
586
587       if (push_element (parser, ELEMENT_SERVICEDIR) == NULL)
588         {
589           BUS_SET_OOM (error);
590           return FALSE;
591         }
592
593       return TRUE;
594     }
595   else if (strcmp (element_name, "include") == 0)
596     {
597       Element *e;
598       const char *ignore_missing;
599
600       if ((e = push_element (parser, ELEMENT_INCLUDE)) == NULL)
601         {
602           BUS_SET_OOM (error);
603           return FALSE;
604         }
605
606       e->d.include.ignore_missing = FALSE;
607
608       if (!locate_attributes (parser, "include",
609                               attribute_names,
610                               attribute_values,
611                               error,
612                               "ignore_missing", &ignore_missing,
613                               NULL))
614         return FALSE;
615
616       if (ignore_missing != NULL)
617         {
618           if (strcmp (ignore_missing, "yes") == 0)
619             e->d.include.ignore_missing = TRUE;
620           else if (strcmp (ignore_missing, "no") == 0)
621             e->d.include.ignore_missing = FALSE;
622           else
623             {
624               dbus_set_error (error, DBUS_ERROR_FAILED,
625                               "ignore_missing attribute must have value \"yes\" or \"no\"");
626               return FALSE;
627             }
628         }
629
630       return TRUE;
631     }
632   else if (strcmp (element_name, "policy") == 0)
633     {
634       Element *e;
635       const char *context;
636       const char *user;
637       const char *group;
638
639       if ((e = push_element (parser, ELEMENT_POLICY)) == NULL)
640         {
641           BUS_SET_OOM (error);
642           return FALSE;
643         }
644
645       e->d.policy.type = POLICY_IGNORED;
646       
647       if (!locate_attributes (parser, "policy",
648                               attribute_names,
649                               attribute_values,
650                               error,
651                               "context", &context,
652                               "user", &user,
653                               "group", &group,
654                               NULL))
655         return FALSE;
656
657       if (((context && user) ||
658            (context && group)) ||
659           (user && group) ||
660           !(context || user || group))
661         {
662           dbus_set_error (error, DBUS_ERROR_FAILED,
663                           "<policy> element must have exactly one of (context|user|group) attributes");
664           return FALSE;
665         }
666
667       if (context != NULL)
668         {
669           if (strcmp (context, "default") == 0)
670             {
671               e->d.policy.type = POLICY_DEFAULT;
672             }
673           else if (strcmp (context, "mandatory") == 0)
674             {
675               e->d.policy.type = POLICY_MANDATORY;
676             }
677           else
678             {
679               dbus_set_error (error, DBUS_ERROR_FAILED,
680                               "context attribute on <policy> must have the value \"default\" or \"mandatory\", not \"%s\"",
681                               context);
682               return FALSE;
683             }
684         }
685       else if (user != NULL)
686         {
687           DBusString username;
688           _dbus_string_init_const (&username, user);
689
690           if (_dbus_get_user_id (&username,
691                                  &e->d.policy.gid_or_uid))
692             e->d.policy.type = POLICY_USER;
693           else
694             _dbus_warn ("Unknown username \"%s\" in message bus configuration file\n",
695                         user);
696         }
697       else if (group != NULL)
698         {
699           DBusString group_name;
700           _dbus_string_init_const (&group_name, group);
701
702           if (_dbus_get_group_id (&group_name,
703                                   &e->d.policy.gid_or_uid))
704             e->d.policy.type = POLICY_GROUP;
705           else
706             _dbus_warn ("Unknown group \"%s\" in message bus configuration file\n",
707                         group);          
708         }
709       else
710         {
711           _dbus_assert_not_reached ("all <policy> attributes null and we didn't set error");
712         }
713       
714       return TRUE;
715     }
716   else
717     {
718       dbus_set_error (error, DBUS_ERROR_FAILED,
719                       "Element <%s> not allowed inside <%s> in configuration file",
720                       element_name, "busconfig");
721       return FALSE;
722     }
723 }
724
725 static dbus_bool_t
726 append_rule_from_element (BusConfigParser   *parser,
727                           const char        *element_name,
728                           const char       **attribute_names,
729                           const char       **attribute_values,
730                           dbus_bool_t        allow,
731                           DBusError         *error)
732 {
733   const char *send;
734   const char *receive;
735   const char *own;
736   const char *send_to;
737   const char *receive_from;
738   const char *user;
739   const char *group;
740   BusPolicyRule *rule;
741   
742   if (!locate_attributes (parser, element_name,
743                           attribute_names,
744                           attribute_values,
745                           error,
746                           "send", &send,
747                           "receive", &receive,
748                           "own", &own,
749                           "send_to", &send_to,
750                           "receive_from", &receive_from,
751                           "user", &user,
752                           "group", &group,
753                           NULL))
754     return FALSE;
755
756   if (!(send || receive || own || send_to || receive_from ||
757         user || group))
758     {
759       dbus_set_error (error, DBUS_ERROR_FAILED,
760                       "Element <%s> must have one or more attributes",
761                       element_name);
762       return FALSE;
763     }
764   
765   if (((send && own) ||
766        (send && receive) ||
767        (send && receive_from) ||
768        (send && user) ||
769        (send && group)) ||
770
771       ((receive && own) ||
772        (receive && send_to) ||
773        (receive && user) ||
774        (receive && group)) ||
775
776       ((own && send_to) ||
777        (own && receive_from) ||
778        (own && user) ||
779        (own && group)) ||
780
781       ((send_to && receive_from) ||
782        (send_to && user) ||
783        (send_to && group)) ||
784
785       ((receive_from && user) ||
786        (receive_from && group)) ||
787
788       (user && group))
789     {
790       dbus_set_error (error, DBUS_ERROR_FAILED,
791                       "Invalid combination of attributes on element <%s>, "
792                       "only send/send_to or receive/receive_from may be paired",
793                       element_name);
794       return FALSE;
795     }
796
797   rule = NULL;
798
799   /* In BusPolicyRule, NULL represents wildcard.
800    * In the config file, '*' represents it.
801    */
802 #define IS_WILDCARD(str) ((str) && ((str)[0]) == '*' && ((str)[1]) == '\0')
803
804   if (send || send_to)
805     {
806       rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow); 
807       if (rule == NULL)
808         goto nomem;
809
810       if (IS_WILDCARD (send))
811         send = NULL;
812       if (IS_WILDCARD (send_to))
813         send_to = NULL;
814       
815       rule->d.send.message_name = _dbus_strdup (send);
816       rule->d.send.destination = _dbus_strdup (send_to);
817       if (send && rule->d.send.message_name == NULL)
818         goto nomem;
819       if (send_to && rule->d.send.destination == NULL)
820         goto nomem;
821     }
822   else if (receive || receive_from)
823     {
824       rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow); 
825       if (rule == NULL)
826         goto nomem;
827
828       if (IS_WILDCARD (receive))
829         receive = NULL;
830
831       if (IS_WILDCARD (receive_from))
832         receive_from = NULL;
833       
834       rule->d.receive.message_name = _dbus_strdup (receive);
835       rule->d.receive.origin = _dbus_strdup (receive_from);
836       if (receive && rule->d.receive.message_name == NULL)
837         goto nomem;
838       if (receive_from && rule->d.receive.origin == NULL)
839         goto nomem;
840     }
841   else if (own)
842     {
843       rule = bus_policy_rule_new (BUS_POLICY_RULE_OWN, allow); 
844       if (rule == NULL)
845         goto nomem;
846
847       if (IS_WILDCARD (own))
848         own = NULL;
849       
850       rule->d.own.service_name = _dbus_strdup (own);
851       if (own && rule->d.own.service_name == NULL)
852         goto nomem;
853     }
854   else if (user)
855     {      
856       if (IS_WILDCARD (user))
857         {
858           rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow); 
859           if (rule == NULL)
860             goto nomem;
861
862           /* FIXME the wildcard needs storing in the rule somehow */
863         }
864       else
865         {
866           DBusString username;
867           dbus_uid_t uid;
868           
869           _dbus_string_init_const (&username, user);
870       
871           if (_dbus_get_user_id (&username, &uid))
872             {
873               rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow); 
874               if (rule == NULL)
875                 goto nomem;
876               
877               rule->d.user.user = _dbus_strdup (user);
878               if (rule->d.user.user == NULL)
879                 goto nomem;
880               rule->d.user.uid = uid;
881             }
882           else
883             {
884               _dbus_warn ("Unknown username \"%s\" on element <%s>\n",
885                           user, element_name);
886             }
887         }
888     }
889   else if (group)
890     {
891       if (IS_WILDCARD (group))
892         {
893           rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow); 
894           if (rule == NULL)
895             goto nomem;
896
897           /* FIXME the wildcard needs storing in the rule somehow */
898         }
899       else
900         {
901           DBusString groupname;
902           dbus_gid_t gid;
903           
904           _dbus_string_init_const (&groupname, group);
905           
906           if (_dbus_get_user_id (&groupname, &gid))
907             {
908               rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow); 
909               if (rule == NULL)
910                 goto nomem;
911               
912               rule->d.group.group = _dbus_strdup (group);
913               if (rule->d.group.group == NULL)
914                 goto nomem;
915               rule->d.group.gid = gid;
916             }
917           else
918             {
919               _dbus_warn ("Unknown group \"%s\" on element <%s>\n",
920                           group, element_name);
921             }
922         }
923     }
924   else
925     _dbus_assert_not_reached ("Did not handle some combination of attributes on <allow> or <deny>");
926
927   if (rule != NULL)
928     {
929       Element *pe;
930       
931       pe = peek_element (parser);      
932       _dbus_assert (pe != NULL);
933       _dbus_assert (pe->type == ELEMENT_POLICY);
934
935       switch (pe->d.policy.type)
936         {
937         case POLICY_IGNORED:
938           /* drop the rule on the floor */
939           break;
940           
941         case POLICY_DEFAULT:
942           if (!bus_policy_append_default_rule (parser->policy, rule))
943             goto nomem;
944           break;
945         case POLICY_MANDATORY:
946           if (!bus_policy_append_mandatory_rule (parser->policy, rule))
947             goto nomem;
948           break;
949         case POLICY_USER:
950           if (!BUS_POLICY_RULE_IS_PER_CLIENT (rule))
951             {
952               dbus_set_error (error, DBUS_ERROR_FAILED,
953                               "<%s> rule cannot be per-user because it has bus-global semantics",
954                               element_name);
955               goto failed;
956             }
957           
958           if (!bus_policy_append_user_rule (parser->policy, pe->d.policy.gid_or_uid,
959                                             rule))
960             goto nomem;
961           break;
962         case POLICY_GROUP:
963           if (!BUS_POLICY_RULE_IS_PER_CLIENT (rule))
964             {
965               dbus_set_error (error, DBUS_ERROR_FAILED,
966                               "<%s> rule cannot be per-group because it has bus-global semantics",
967                               element_name);
968               goto failed;
969             }
970           
971           if (!bus_policy_append_group_rule (parser->policy, pe->d.policy.gid_or_uid,
972                                              rule))
973             goto nomem;
974           break;
975         }
976       
977       bus_policy_rule_unref (rule);
978       rule = NULL;
979     }
980   
981   return TRUE;
982
983  nomem:
984   BUS_SET_OOM (error);
985  failed:
986   if (rule)
987     bus_policy_rule_unref (rule);
988   return FALSE;
989 }
990
991 static dbus_bool_t
992 start_policy_child (BusConfigParser   *parser,
993                     const char        *element_name,
994                     const char       **attribute_names,
995                     const char       **attribute_values,
996                     DBusError         *error)
997 {
998   if (strcmp (element_name, "allow") == 0)
999     {
1000       if (!append_rule_from_element (parser, element_name,
1001                                      attribute_names, attribute_values,
1002                                      TRUE, error))
1003         return FALSE;
1004       
1005       if (push_element (parser, ELEMENT_ALLOW) == NULL)
1006         {
1007           BUS_SET_OOM (error);
1008           return FALSE;
1009         }
1010       
1011       return TRUE;
1012     }
1013   else if (strcmp (element_name, "deny") == 0)
1014     {
1015       if (!append_rule_from_element (parser, element_name,
1016                                      attribute_names, attribute_values,
1017                                      FALSE, error))
1018         return FALSE;
1019       
1020       if (push_element (parser, ELEMENT_DENY) == NULL)
1021         {
1022           BUS_SET_OOM (error);
1023           return FALSE;
1024         }
1025       
1026       return TRUE;
1027     }
1028   else
1029     {
1030       dbus_set_error (error, DBUS_ERROR_FAILED,
1031                       "Element <%s> not allowed inside <%s> in configuration file",
1032                       element_name, "policy");
1033       return FALSE;
1034     }
1035 }
1036
1037 dbus_bool_t
1038 bus_config_parser_start_element (BusConfigParser   *parser,
1039                                  const char        *element_name,
1040                                  const char       **attribute_names,
1041                                  const char       **attribute_values,
1042                                  DBusError         *error)
1043 {
1044   ElementType t;
1045
1046   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1047
1048   /* printf ("START: %s\n", element_name); */
1049   
1050   t = top_element_type (parser);
1051
1052   if (t == ELEMENT_NONE)
1053     {
1054       if (strcmp (element_name, "busconfig") == 0)
1055         {
1056           if (!check_no_attributes (parser, "busconfig", attribute_names, attribute_values, error))
1057             return FALSE;
1058           
1059           if (push_element (parser, ELEMENT_BUSCONFIG) == NULL)
1060             {
1061               BUS_SET_OOM (error);
1062               return FALSE;
1063             }
1064
1065           return TRUE;
1066         }
1067       else
1068         {
1069           dbus_set_error (error, DBUS_ERROR_FAILED,
1070                           "Unknown element <%s> at root of configuration file",
1071                           element_name);
1072           return FALSE;
1073         }
1074     }
1075   else if (t == ELEMENT_BUSCONFIG)
1076     {
1077       return start_busconfig_child (parser, element_name,
1078                                     attribute_names, attribute_values,
1079                                     error);
1080     }
1081   else if (t == ELEMENT_POLICY)
1082     {
1083       return start_policy_child (parser, element_name,
1084                                  attribute_names, attribute_values,
1085                                  error);
1086     }
1087   else
1088     {
1089       dbus_set_error (error, DBUS_ERROR_FAILED,
1090                       "Element <%s> is not allowed in this context",
1091                       element_name);
1092       return FALSE;
1093     }  
1094 }
1095
1096 dbus_bool_t
1097 bus_config_parser_end_element (BusConfigParser   *parser,
1098                                const char        *element_name,
1099                                DBusError         *error)
1100 {
1101   ElementType t;
1102   const char *n;
1103   Element *e;
1104
1105   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1106
1107   /* printf ("END: %s\n", element_name); */
1108   
1109   t = top_element_type (parser);
1110
1111   if (t == ELEMENT_NONE)
1112     {
1113       /* should probably be an assertion failure but
1114        * being paranoid about XML parsers
1115        */
1116       dbus_set_error (error, DBUS_ERROR_FAILED,
1117                       "XML parser ended element with no element on the stack");
1118       return FALSE;
1119     }
1120
1121   n = element_type_to_name (t);
1122   _dbus_assert (n != NULL);
1123   if (strcmp (n, element_name) != 0)
1124     {
1125       /* should probably be an assertion failure but
1126        * being paranoid about XML parsers
1127        */
1128       dbus_set_error (error, DBUS_ERROR_FAILED,
1129                       "XML element <%s> ended but topmost element on the stack was <%s>",
1130                       element_name, n);
1131       return FALSE;
1132     }
1133
1134   e = peek_element (parser);
1135   _dbus_assert (e != NULL);
1136
1137   switch (e->type)
1138     {
1139     case ELEMENT_NONE:
1140       _dbus_assert_not_reached ("element in stack has no type");
1141       break;
1142
1143     case ELEMENT_INCLUDE:
1144     case ELEMENT_USER:
1145     case ELEMENT_TYPE:
1146     case ELEMENT_LISTEN:
1147     case ELEMENT_PIDFILE:
1148     case ELEMENT_AUTH:
1149     case ELEMENT_SERVICEDIR:
1150     case ELEMENT_INCLUDEDIR:
1151       if (!e->had_content)
1152         {
1153           dbus_set_error (error, DBUS_ERROR_FAILED,
1154                           "XML element <%s> was expected to have content inside it",
1155                           element_type_to_name (e->type));
1156           return FALSE;
1157         }
1158       break;
1159
1160     case ELEMENT_BUSCONFIG:
1161     case ELEMENT_POLICY:
1162     case ELEMENT_LIMIT:
1163     case ELEMENT_ALLOW:
1164     case ELEMENT_DENY:
1165     case ELEMENT_FORK:
1166       break;
1167     }
1168
1169   pop_element (parser);
1170
1171   return TRUE;
1172 }
1173
1174 static dbus_bool_t
1175 all_whitespace (const DBusString *str)
1176 {
1177   int i;
1178
1179   _dbus_string_skip_white (str, 0, &i);
1180
1181   return i == _dbus_string_get_length (str);
1182 }
1183
1184 static dbus_bool_t
1185 make_full_path (const DBusString *basedir,
1186                 const DBusString *filename,
1187                 DBusString       *full_path)
1188 {
1189   if (_dbus_path_is_absolute (filename))
1190     {
1191       return _dbus_string_copy (filename, 0, full_path, 0);
1192     }
1193   else
1194     {
1195       if (!_dbus_string_copy (basedir, 0, full_path, 0))
1196         return FALSE;
1197       
1198       if (!_dbus_concat_dir_and_file (full_path, filename))
1199         return FALSE;
1200
1201       return TRUE;
1202     }
1203 }
1204
1205 static dbus_bool_t
1206 include_file (BusConfigParser   *parser,
1207               const DBusString  *filename,
1208               dbus_bool_t        ignore_missing,
1209               DBusError         *error)
1210 {
1211   /* FIXME good test case for this would load each config file in the
1212    * test suite both alone, and as an include, and check
1213    * that the result is the same
1214    */
1215   BusConfigParser *included;
1216   DBusError tmp_error;
1217         
1218   dbus_error_init (&tmp_error);
1219   included = bus_config_load (filename, &tmp_error);
1220   if (included == NULL)
1221     {
1222       _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
1223
1224       if (dbus_error_has_name (&tmp_error, DBUS_ERROR_FILE_NOT_FOUND) &&
1225           ignore_missing)
1226         {
1227           dbus_error_free (&tmp_error);
1228           return TRUE;
1229         }
1230       else
1231         {
1232           dbus_move_error (&tmp_error, error);
1233           return FALSE;
1234         }
1235     }
1236   else
1237     {
1238       _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
1239
1240       if (!merge_included (parser, included, error))
1241         {
1242           bus_config_parser_unref (included);
1243           return FALSE;
1244         }
1245
1246       bus_config_parser_unref (included);
1247       return TRUE;
1248     }
1249 }
1250
1251 static dbus_bool_t
1252 include_dir (BusConfigParser   *parser,
1253              const DBusString  *dirname,
1254              DBusError         *error)
1255 {
1256   DBusString filename;
1257   dbus_bool_t retval;
1258   DBusError tmp_error;
1259   DBusDirIter *dir;
1260   
1261   if (!_dbus_string_init (&filename))
1262     {
1263       BUS_SET_OOM (error);
1264       return FALSE;
1265     }
1266
1267   retval = FALSE;
1268   
1269   dir = _dbus_directory_open (dirname, error);
1270
1271   if (dir == NULL)
1272     goto failed;
1273
1274   dbus_error_init (&tmp_error);
1275   while (_dbus_directory_get_next_file (dir, &filename, &tmp_error))
1276     {
1277       DBusString full_path;
1278
1279       if (!_dbus_string_init (&full_path))
1280         {
1281           BUS_SET_OOM (error);
1282           goto failed;
1283         }
1284
1285       if (!_dbus_string_copy (dirname, 0, &full_path, 0))
1286         {
1287           BUS_SET_OOM (error);
1288           _dbus_string_free (&full_path);
1289           goto failed;
1290         }      
1291
1292       if (!_dbus_concat_dir_and_file (&full_path, &filename))
1293         {
1294           BUS_SET_OOM (error);
1295           _dbus_string_free (&full_path);
1296           goto failed;
1297         }
1298       
1299       if (_dbus_string_ends_with_c_str (&full_path, ".conf"))
1300         {
1301           if (!include_file (parser, &full_path, TRUE, error))
1302             {
1303               _dbus_string_free (&full_path);
1304               goto failed;
1305             }
1306         }
1307
1308       _dbus_string_free (&full_path);
1309     }
1310
1311   if (dbus_error_is_set (&tmp_error))
1312     {
1313       dbus_move_error (&tmp_error, error);
1314       goto failed;
1315     }
1316   
1317   retval = TRUE;
1318   
1319  failed:
1320   _dbus_string_free (&filename);
1321   
1322   if (dir)
1323     _dbus_directory_close (dir);
1324
1325   return retval;
1326 }
1327
1328 dbus_bool_t
1329 bus_config_parser_content (BusConfigParser   *parser,
1330                            const DBusString  *content,
1331                            DBusError         *error)
1332 {
1333   Element *e;
1334
1335   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1336
1337 #if 0
1338   {
1339     const char *c_str;
1340     
1341     _dbus_string_get_const_data (content, &c_str);
1342
1343     printf ("CONTENT %d bytes: %s\n", _dbus_string_get_length (content), c_str);
1344   }
1345 #endif
1346   
1347   e = peek_element (parser);
1348   if (e == NULL)
1349     {
1350       dbus_set_error (error, DBUS_ERROR_FAILED,
1351                       "Text content outside of any XML element in configuration file");
1352       return FALSE;
1353     }
1354   else if (e->had_content)
1355     {
1356       _dbus_assert_not_reached ("Element had multiple content blocks");
1357       return FALSE;
1358     }
1359
1360   switch (top_element_type (parser))
1361     {
1362     case ELEMENT_NONE:
1363       _dbus_assert_not_reached ("element at top of stack has no type");
1364       return FALSE;
1365
1366     case ELEMENT_BUSCONFIG:
1367     case ELEMENT_POLICY:
1368     case ELEMENT_LIMIT:
1369     case ELEMENT_ALLOW:
1370     case ELEMENT_DENY:
1371     case ELEMENT_FORK:
1372       if (all_whitespace (content))
1373         return TRUE;
1374       else
1375         {
1376           dbus_set_error (error, DBUS_ERROR_FAILED,
1377                           "No text content expected inside XML element %s in configuration file",
1378                           element_type_to_name (top_element_type (parser)));
1379           return FALSE;
1380         }
1381
1382     case ELEMENT_PIDFILE:
1383       {
1384         char *s;
1385
1386         e->had_content = TRUE;
1387         
1388         if (!_dbus_string_copy_data (content, &s))
1389           goto nomem;
1390           
1391         dbus_free (parser->pidfile);
1392         parser->pidfile = s;
1393       }
1394       break;
1395
1396     case ELEMENT_INCLUDE:
1397       {
1398         DBusString full_path;
1399         
1400         e->had_content = TRUE;
1401
1402         if (!_dbus_string_init (&full_path))
1403           goto nomem;
1404         
1405         if (!make_full_path (&parser->basedir, content, &full_path))
1406           {
1407             _dbus_string_free (&full_path);
1408             goto nomem;
1409           }
1410         
1411         if (!include_file (parser, &full_path,
1412                            e->d.include.ignore_missing, error))
1413           {
1414             _dbus_string_free (&full_path);
1415             return FALSE;
1416           }
1417
1418         _dbus_string_free (&full_path);
1419       }
1420       break;
1421
1422     case ELEMENT_INCLUDEDIR:
1423       {
1424         DBusString full_path;
1425         
1426         e->had_content = TRUE;
1427
1428         if (!_dbus_string_init (&full_path))
1429           goto nomem;
1430         
1431         if (!make_full_path (&parser->basedir, content, &full_path))
1432           {
1433             _dbus_string_free (&full_path);
1434             goto nomem;
1435           }
1436         
1437         if (!include_dir (parser, &full_path, error))
1438           {
1439             _dbus_string_free (&full_path);
1440             return FALSE;
1441           }
1442
1443         _dbus_string_free (&full_path);
1444       }
1445       break;
1446       
1447     case ELEMENT_USER:
1448       {
1449         char *s;
1450
1451         e->had_content = TRUE;
1452         
1453         if (!_dbus_string_copy_data (content, &s))
1454           goto nomem;
1455           
1456         dbus_free (parser->user);
1457         parser->user = s;
1458       }
1459       break;
1460
1461     case ELEMENT_TYPE:
1462       {
1463         char *s;
1464
1465         e->had_content = TRUE;
1466
1467         if (!_dbus_string_copy_data (content, &s))
1468           goto nomem;
1469         
1470         dbus_free (parser->bus_type);
1471         parser->bus_type = s;
1472       }
1473       break;
1474       
1475     case ELEMENT_LISTEN:
1476       {
1477         char *s;
1478
1479         e->had_content = TRUE;
1480         
1481         if (!_dbus_string_copy_data (content, &s))
1482           goto nomem;
1483
1484         if (!_dbus_list_append (&parser->listen_on,
1485                                 s))
1486           {
1487             dbus_free (s);
1488             goto nomem;
1489           }
1490       }
1491       break;
1492
1493     case ELEMENT_AUTH:
1494       {
1495         char *s;
1496         
1497         e->had_content = TRUE;
1498
1499         if (!_dbus_string_copy_data (content, &s))
1500           goto nomem;
1501
1502         if (!_dbus_list_append (&parser->mechanisms,
1503                                 s))
1504           {
1505             dbus_free (s);
1506             goto nomem;
1507           }
1508       }
1509       break;
1510
1511     case ELEMENT_SERVICEDIR:
1512       {
1513         char *s;
1514         DBusString full_path;
1515         
1516         e->had_content = TRUE;
1517
1518         if (!_dbus_string_init (&full_path))
1519           goto nomem;
1520         
1521         if (!make_full_path (&parser->basedir, content, &full_path))
1522           {
1523             _dbus_string_free (&full_path);
1524             goto nomem;
1525           }
1526         
1527         if (!_dbus_string_copy_data (&full_path, &s))
1528           {
1529             _dbus_string_free (&full_path);
1530             goto nomem;
1531           }
1532
1533         if (!_dbus_list_append (&parser->service_dirs, s))
1534           {
1535             _dbus_string_free (&full_path);
1536             dbus_free (s);
1537             goto nomem;
1538           }
1539
1540         _dbus_string_free (&full_path);
1541       }
1542       break;
1543     }
1544
1545   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1546   return TRUE;
1547
1548  nomem:
1549   BUS_SET_OOM (error);
1550   return FALSE;
1551 }
1552
1553 dbus_bool_t
1554 bus_config_parser_finished (BusConfigParser   *parser,
1555                             DBusError         *error)
1556 {
1557   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1558
1559   if (parser->stack != NULL)
1560     {
1561       dbus_set_error (error, DBUS_ERROR_FAILED,
1562                       "Element <%s> was not closed in configuration file",
1563                       element_type_to_name (top_element_type (parser)));
1564
1565       return FALSE;
1566     }
1567
1568   if (parser->listen_on == NULL)
1569     {
1570       dbus_set_error (error, DBUS_ERROR_FAILED,
1571                       "Configuration file needs one or more <listen> elements giving addresses"); 
1572       return FALSE;
1573     }
1574   
1575   return TRUE;
1576 }
1577
1578 const char*
1579 bus_config_parser_get_user (BusConfigParser *parser)
1580 {
1581   return parser->user;
1582 }
1583
1584 const char*
1585 bus_config_parser_get_type (BusConfigParser *parser)
1586 {
1587   return parser->bus_type;
1588 }
1589
1590 DBusList**
1591 bus_config_parser_get_addresses (BusConfigParser *parser)
1592 {
1593   return &parser->listen_on;
1594 }
1595
1596 DBusList**
1597 bus_config_parser_get_mechanisms (BusConfigParser *parser)
1598 {
1599   return &parser->mechanisms;
1600 }
1601
1602 DBusList**
1603 bus_config_parser_get_service_dirs (BusConfigParser *parser)
1604 {
1605   return &parser->service_dirs;
1606 }
1607
1608 dbus_bool_t
1609 bus_config_parser_get_fork (BusConfigParser   *parser)
1610 {
1611   return parser->fork;
1612 }
1613
1614 const char *
1615 bus_config_parser_get_pidfile (BusConfigParser   *parser)
1616 {
1617   return parser->pidfile;
1618 }
1619
1620 BusPolicy*
1621 bus_config_parser_steal_policy (BusConfigParser *parser)
1622 {
1623   BusPolicy *policy;
1624
1625   _dbus_assert (parser->policy != NULL); /* can only steal the policy 1 time */
1626   
1627   policy = parser->policy;
1628
1629   parser->policy = NULL;
1630
1631   return policy;
1632 }
1633
1634 #ifdef DBUS_BUILD_TESTS
1635 #include <stdio.h>
1636
1637 typedef enum
1638 {
1639   VALID,
1640   INVALID,
1641   UNKNOWN
1642 } Validity;
1643
1644 static dbus_bool_t
1645 do_load (const DBusString *full_path,
1646          Validity          validity,
1647          dbus_bool_t       oom_possible)
1648 {
1649   BusConfigParser *parser;
1650   DBusError error;
1651
1652   dbus_error_init (&error);
1653
1654   parser = bus_config_load (full_path, &error);
1655   if (parser == NULL)
1656     {
1657       _DBUS_ASSERT_ERROR_IS_SET (&error);
1658
1659       if (oom_possible &&
1660           dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
1661         {
1662           _dbus_verbose ("Failed to load valid file due to OOM\n");
1663           dbus_error_free (&error);
1664           return TRUE;
1665         }
1666       else if (validity == VALID)
1667         {
1668           _dbus_warn ("Failed to load valid file but still had memory: %s\n",
1669                       error.message);
1670
1671           dbus_error_free (&error);
1672           return FALSE;
1673         }
1674       else
1675         {
1676           dbus_error_free (&error);
1677           return TRUE;
1678         }
1679     }
1680   else
1681     {
1682       _DBUS_ASSERT_ERROR_IS_CLEAR (&error);
1683
1684       bus_config_parser_unref (parser);
1685
1686       if (validity == INVALID)
1687         {
1688           _dbus_warn ("Accepted invalid file\n");
1689           return FALSE;
1690         }
1691
1692       return TRUE;
1693     }
1694 }
1695
1696 typedef struct
1697 {
1698   const DBusString *full_path;
1699   Validity          validity;
1700 } LoaderOomData;
1701
1702 static dbus_bool_t
1703 check_loader_oom_func (void *data)
1704 {
1705   LoaderOomData *d = data;
1706
1707   return do_load (d->full_path, d->validity, TRUE);
1708 }
1709
1710 static dbus_bool_t
1711 process_test_subdir (const DBusString *test_base_dir,
1712                      const char       *subdir,
1713                      Validity          validity)
1714 {
1715   DBusString test_directory;
1716   DBusString filename;
1717   DBusDirIter *dir;
1718   dbus_bool_t retval;
1719   DBusError error;
1720
1721   retval = FALSE;
1722   dir = NULL;
1723
1724   if (!_dbus_string_init (&test_directory))
1725     _dbus_assert_not_reached ("didn't allocate test_directory\n");
1726
1727   _dbus_string_init_const (&filename, subdir);
1728
1729   if (!_dbus_string_copy (test_base_dir, 0,
1730                           &test_directory, 0))
1731     _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
1732
1733   if (!_dbus_concat_dir_and_file (&test_directory, &filename))
1734     _dbus_assert_not_reached ("couldn't allocate full path");
1735
1736   _dbus_string_free (&filename);
1737   if (!_dbus_string_init (&filename))
1738     _dbus_assert_not_reached ("didn't allocate filename string\n");
1739
1740   dbus_error_init (&error);
1741   dir = _dbus_directory_open (&test_directory, &error);
1742   if (dir == NULL)
1743     {
1744       _dbus_warn ("Could not open %s: %s\n",
1745                   _dbus_string_get_const_data (&test_directory),
1746                   error.message);
1747       dbus_error_free (&error);
1748       goto failed;
1749     }
1750
1751   printf ("Testing:\n");
1752
1753  next:
1754   while (_dbus_directory_get_next_file (dir, &filename, &error))
1755     {
1756       DBusString full_path;
1757       LoaderOomData d;
1758
1759       if (!_dbus_string_init (&full_path))
1760         _dbus_assert_not_reached ("couldn't init string");
1761
1762       if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
1763         _dbus_assert_not_reached ("couldn't copy dir to full_path");
1764
1765       if (!_dbus_concat_dir_and_file (&full_path, &filename))
1766         _dbus_assert_not_reached ("couldn't concat file to dir");
1767
1768       if (!_dbus_string_ends_with_c_str (&full_path, ".conf"))
1769         {
1770           _dbus_verbose ("Skipping non-.conf file %s\n",
1771                          _dbus_string_get_const_data (&filename));
1772           _dbus_string_free (&full_path);
1773           goto next;
1774         }
1775
1776       printf ("    %s\n", _dbus_string_get_const_data (&filename));
1777
1778       _dbus_verbose (" expecting %s\n",
1779                      validity == VALID ? "valid" :
1780                      (validity == INVALID ? "invalid" :
1781                       (validity == UNKNOWN ? "unknown" : "???")));
1782
1783       d.full_path = &full_path;
1784       d.validity = validity;
1785       if (!_dbus_test_oom_handling ("config-loader", check_loader_oom_func, &d))
1786         _dbus_assert_not_reached ("test failed");
1787
1788       _dbus_string_free (&full_path);
1789     }
1790
1791   if (dbus_error_is_set (&error))
1792     {
1793       _dbus_warn ("Could not get next file in %s: %s\n",
1794                   _dbus_string_get_const_data (&test_directory),
1795                   error.message);
1796       dbus_error_free (&error);
1797       goto failed;
1798     }
1799
1800   retval = TRUE;
1801
1802  failed:
1803
1804   if (dir)
1805     _dbus_directory_close (dir);
1806   _dbus_string_free (&test_directory);
1807   _dbus_string_free (&filename);
1808
1809   return retval;
1810 }
1811
1812 dbus_bool_t
1813 bus_config_parser_test (const DBusString *test_data_dir)
1814 {
1815   if (test_data_dir == NULL ||
1816       _dbus_string_get_length (test_data_dir) == 0)
1817     {
1818       printf ("No test data\n");
1819       return TRUE;
1820     }
1821
1822   if (!process_test_subdir (test_data_dir, "valid-config-files", VALID))
1823     return FALSE;
1824
1825   return TRUE;
1826 }
1827
1828 #endif /* DBUS_BUILD_TESTS */
1829