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