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