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