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