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