Add syslog of security denials and configuration file reloads
[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 *send_interface;
1130   const char *send_member;
1131   const char *send_error;
1132   const char *send_destination;
1133   const char *send_path;
1134   const char *send_type;
1135   const char *receive_interface;
1136   const char *receive_member;
1137   const char *receive_error;
1138   const char *receive_sender;
1139   const char *receive_path;
1140   const char *receive_type;
1141   const char *eavesdrop;
1142   const char *send_requested_reply;
1143   const char *receive_requested_reply;
1144   const char *own;
1145   const char *user;
1146   const char *group;
1147
1148   BusPolicyRule *rule;
1149   
1150   if (!locate_attributes (parser, element_name,
1151                           attribute_names,
1152                           attribute_values,
1153                           error,
1154                           "send_interface", &send_interface,
1155                           "send_member", &send_member,
1156                           "send_error", &send_error,
1157                           "send_destination", &send_destination,
1158                           "send_path", &send_path,
1159                           "send_type", &send_type,
1160                           "receive_interface", &receive_interface,
1161                           "receive_member", &receive_member,
1162                           "receive_error", &receive_error,
1163                           "receive_sender", &receive_sender,
1164                           "receive_path", &receive_path,
1165                           "receive_type", &receive_type,
1166                           "eavesdrop", &eavesdrop,
1167                           "send_requested_reply", &send_requested_reply,
1168                           "receive_requested_reply", &receive_requested_reply,
1169                           "own", &own,
1170                           "user", &user,
1171                           "group", &group,
1172                           NULL))
1173     return FALSE;
1174
1175   if (!(send_interface || send_member || send_error || send_destination ||
1176         send_type || send_path ||
1177         receive_interface || receive_member || receive_error || receive_sender ||
1178         receive_type || receive_path || eavesdrop ||
1179         send_requested_reply || receive_requested_reply ||
1180         own || user || group))
1181     {
1182       dbus_set_error (error, DBUS_ERROR_FAILED,
1183                       "Element <%s> must have one or more attributes",
1184                       element_name);
1185       return FALSE;
1186     }
1187
1188   if ((send_member && (send_interface == NULL && send_path == NULL)) ||
1189       (receive_member && (receive_interface == NULL && receive_path == NULL)))
1190     {
1191       dbus_set_error (error, DBUS_ERROR_FAILED,
1192                       "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.",
1193                       element_name);
1194       return FALSE;
1195     }
1196   
1197   /* Allowed combinations of elements are:
1198    *
1199    *   base, must be all send or all receive:
1200    *     nothing
1201    *     interface
1202    *     interface + member
1203    *     error
1204    * 
1205    *   base send_ can combine with send_destination, send_path, send_type, send_requested_reply
1206    *   base receive_ with receive_sender, receive_path, receive_type, receive_requested_reply, eavesdrop
1207    *
1208    *   user, group, own must occur alone
1209    *
1210    * Pretty sure the below stuff is broken, FIXME think about it more.
1211    */
1212
1213   if (((send_interface && send_error) ||
1214        (send_interface && receive_interface) ||
1215        (send_interface && receive_member) ||
1216        (send_interface && receive_error) ||
1217        (send_interface && receive_sender) ||
1218        (send_interface && receive_requested_reply) ||
1219        (send_interface && own) ||
1220        (send_interface && user) ||
1221        (send_interface && group)) ||
1222
1223       ((send_member && send_error) ||
1224        (send_member && receive_interface) ||
1225        (send_member && receive_member) ||
1226        (send_member && receive_error) ||
1227        (send_member && receive_sender) ||
1228        (send_member && receive_requested_reply) ||
1229        (send_member && own) ||
1230        (send_member && user) ||
1231        (send_member && group)) ||
1232       
1233       ((send_error && receive_interface) ||
1234        (send_error && receive_member) ||
1235        (send_error && receive_error) ||
1236        (send_error && receive_sender) ||
1237        (send_error && receive_requested_reply) ||
1238        (send_error && own) ||
1239        (send_error && user) ||
1240        (send_error && group)) ||
1241
1242       ((send_destination && receive_interface) ||
1243        (send_destination && receive_member) ||
1244        (send_destination && receive_error) ||
1245        (send_destination && receive_sender) ||
1246        (send_destination && receive_requested_reply) ||
1247        (send_destination && own) ||
1248        (send_destination && user) ||
1249        (send_destination && group)) ||
1250
1251       ((send_type && receive_interface) ||
1252        (send_type && receive_member) ||
1253        (send_type && receive_error) ||
1254        (send_type && receive_sender) ||
1255        (send_type && receive_requested_reply) ||
1256        (send_type && own) ||
1257        (send_type && user) ||
1258        (send_type && group)) ||
1259
1260       ((send_path && receive_interface) ||
1261        (send_path && receive_member) ||
1262        (send_path && receive_error) ||
1263        (send_path && receive_sender) ||
1264        (send_path && receive_requested_reply) ||
1265        (send_path && own) ||
1266        (send_path && user) ||
1267        (send_path && group)) ||
1268
1269       ((send_requested_reply && receive_interface) ||
1270        (send_requested_reply && receive_member) ||
1271        (send_requested_reply && receive_error) ||
1272        (send_requested_reply && receive_sender) ||
1273        (send_requested_reply && receive_requested_reply) ||
1274        (send_requested_reply && own) ||
1275        (send_requested_reply && user) ||
1276        (send_requested_reply && group)) ||
1277       
1278       ((receive_interface && receive_error) ||
1279        (receive_interface && own) ||
1280        (receive_interface && user) ||
1281        (receive_interface && group)) ||
1282
1283       ((receive_member && receive_error) ||
1284        (receive_member && own) ||
1285        (receive_member && user) ||
1286        (receive_member && group)) ||
1287       
1288       ((receive_error && own) ||
1289        (receive_error && user) ||
1290        (receive_error && group)) ||
1291
1292       ((eavesdrop && own) ||
1293        (eavesdrop && user) ||
1294        (eavesdrop && group)) ||
1295
1296       ((receive_requested_reply && own) ||
1297        (receive_requested_reply && user) ||
1298        (receive_requested_reply && group)) ||
1299       
1300       ((own && user) ||
1301        (own && group)) ||
1302
1303       ((user && group)))
1304     {
1305       dbus_set_error (error, DBUS_ERROR_FAILED,
1306                       "Invalid combination of attributes on element <%s>",
1307                       element_name);
1308       return FALSE;
1309     }
1310   
1311   rule = NULL;
1312
1313   /* In BusPolicyRule, NULL represents wildcard.
1314    * In the config file, '*' represents it.
1315    */
1316 #define IS_WILDCARD(str) ((str) && ((str)[0]) == '*' && ((str)[1]) == '\0')
1317
1318   if (send_interface || send_member || send_error || send_destination ||
1319       send_path || send_type || send_requested_reply)
1320     {
1321       int message_type;
1322       
1323       if (IS_WILDCARD (send_interface))
1324         send_interface = NULL;
1325       if (IS_WILDCARD (send_member))
1326         send_member = NULL;
1327       if (IS_WILDCARD (send_error))
1328         send_error = NULL;
1329       if (IS_WILDCARD (send_destination))
1330         send_destination = NULL;
1331       if (IS_WILDCARD (send_path))
1332         send_path = NULL;
1333       if (IS_WILDCARD (send_type))
1334         send_type = NULL;
1335
1336       message_type = DBUS_MESSAGE_TYPE_INVALID;
1337       if (send_type != NULL)
1338         {
1339           message_type = dbus_message_type_from_string (send_type);
1340           if (message_type == DBUS_MESSAGE_TYPE_INVALID)
1341             {
1342               dbus_set_error (error, DBUS_ERROR_FAILED,
1343                               "Bad message type \"%s\"",
1344                               send_type);
1345               return FALSE;
1346             }
1347         }
1348
1349       if (eavesdrop &&
1350           !(strcmp (eavesdrop, "true") == 0 ||
1351             strcmp (eavesdrop, "false") == 0))
1352         {
1353           dbus_set_error (error, DBUS_ERROR_FAILED,
1354                           "Bad value \"%s\" for %s attribute, must be true or false",
1355                           "eavesdrop", eavesdrop);
1356           return FALSE;
1357         }
1358
1359       if (send_requested_reply &&
1360           !(strcmp (send_requested_reply, "true") == 0 ||
1361             strcmp (send_requested_reply, "false") == 0))
1362         {
1363           dbus_set_error (error, DBUS_ERROR_FAILED,
1364                           "Bad value \"%s\" for %s attribute, must be true or false",
1365                           "send_requested_reply", send_requested_reply);
1366           return FALSE;
1367         }
1368       
1369       rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow); 
1370       if (rule == NULL)
1371         goto nomem;
1372       
1373       if (eavesdrop)
1374         rule->d.send.eavesdrop = (strcmp (eavesdrop, "true") == 0);
1375
1376       if (send_requested_reply)
1377         rule->d.send.requested_reply = (strcmp (send_requested_reply, "true") == 0);
1378
1379       rule->d.send.message_type = message_type;
1380       rule->d.send.path = _dbus_strdup (send_path);
1381       rule->d.send.interface = _dbus_strdup (send_interface);
1382       rule->d.send.member = _dbus_strdup (send_member);
1383       rule->d.send.error = _dbus_strdup (send_error);
1384       rule->d.send.destination = _dbus_strdup (send_destination);
1385       if (send_path && rule->d.send.path == NULL)
1386         goto nomem;
1387       if (send_interface && rule->d.send.interface == NULL)
1388         goto nomem;
1389       if (send_member && rule->d.send.member == NULL)
1390         goto nomem;
1391       if (send_error && rule->d.send.error == NULL)
1392         goto nomem;
1393       if (send_destination && rule->d.send.destination == NULL)
1394         goto nomem;
1395     }
1396   else if (receive_interface || receive_member || receive_error || receive_sender ||
1397            receive_path || receive_type || eavesdrop || receive_requested_reply)
1398     {
1399       int message_type;
1400       
1401       if (IS_WILDCARD (receive_interface))
1402         receive_interface = NULL;
1403       if (IS_WILDCARD (receive_member))
1404         receive_member = NULL;
1405       if (IS_WILDCARD (receive_error))
1406         receive_error = NULL;
1407       if (IS_WILDCARD (receive_sender))
1408         receive_sender = NULL;
1409       if (IS_WILDCARD (receive_path))
1410         receive_path = NULL;
1411       if (IS_WILDCARD (receive_type))
1412         receive_type = NULL;
1413
1414       message_type = DBUS_MESSAGE_TYPE_INVALID;
1415       if (receive_type != NULL)
1416         {
1417           message_type = dbus_message_type_from_string (receive_type);
1418           if (message_type == DBUS_MESSAGE_TYPE_INVALID)
1419             {
1420               dbus_set_error (error, DBUS_ERROR_FAILED,
1421                               "Bad message type \"%s\"",
1422                               receive_type);
1423               return FALSE;
1424             }
1425         }
1426
1427
1428       if (eavesdrop &&
1429           !(strcmp (eavesdrop, "true") == 0 ||
1430             strcmp (eavesdrop, "false") == 0))
1431         {
1432           dbus_set_error (error, DBUS_ERROR_FAILED,
1433                           "Bad value \"%s\" for %s attribute, must be true or false",
1434                           "eavesdrop", eavesdrop);
1435           return FALSE;
1436         }
1437
1438       if (receive_requested_reply &&
1439           !(strcmp (receive_requested_reply, "true") == 0 ||
1440             strcmp (receive_requested_reply, "false") == 0))
1441         {
1442           dbus_set_error (error, DBUS_ERROR_FAILED,
1443                           "Bad value \"%s\" for %s attribute, must be true or false",
1444                           "receive_requested_reply", receive_requested_reply);
1445           return FALSE;
1446         }
1447       
1448       rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow); 
1449       if (rule == NULL)
1450         goto nomem;
1451
1452       if (eavesdrop)
1453         rule->d.receive.eavesdrop = (strcmp (eavesdrop, "true") == 0);
1454
1455       if (receive_requested_reply)
1456         rule->d.receive.requested_reply = (strcmp (receive_requested_reply, "true") == 0);
1457       
1458       rule->d.receive.message_type = message_type;
1459       rule->d.receive.path = _dbus_strdup (receive_path);
1460       rule->d.receive.interface = _dbus_strdup (receive_interface);
1461       rule->d.receive.member = _dbus_strdup (receive_member);
1462       rule->d.receive.error = _dbus_strdup (receive_error);
1463       rule->d.receive.origin = _dbus_strdup (receive_sender);
1464
1465       if (receive_path && rule->d.receive.path == NULL)
1466         goto nomem;
1467       if (receive_interface && rule->d.receive.interface == NULL)
1468         goto nomem;
1469       if (receive_member && rule->d.receive.member == NULL)
1470         goto nomem;
1471       if (receive_error && rule->d.receive.error == NULL)
1472         goto nomem;
1473       if (receive_sender && rule->d.receive.origin == NULL)
1474         goto nomem;
1475     }
1476   else if (own)
1477     {
1478       rule = bus_policy_rule_new (BUS_POLICY_RULE_OWN, allow); 
1479       if (rule == NULL)
1480         goto nomem;
1481
1482       if (IS_WILDCARD (own))
1483         own = NULL;
1484       
1485       rule->d.own.service_name = _dbus_strdup (own);
1486       if (own && rule->d.own.service_name == NULL)
1487         goto nomem;
1488     }
1489   else if (user)
1490     {      
1491       if (IS_WILDCARD (user))
1492         {
1493           rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow); 
1494           if (rule == NULL)
1495             goto nomem;
1496
1497           rule->d.user.uid = DBUS_UID_UNSET;
1498         }
1499       else
1500         {
1501           DBusString username;
1502           dbus_uid_t uid;
1503           
1504           _dbus_string_init_const (&username, user);
1505       
1506           if (_dbus_parse_unix_user_from_config (&username, &uid))
1507             {
1508               rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow); 
1509               if (rule == NULL)
1510                 goto nomem;
1511
1512               rule->d.user.uid = uid;
1513             }
1514           else
1515             {
1516               _dbus_warn ("Unknown username \"%s\" on element <%s>\n",
1517                           user, element_name);
1518             }
1519         }
1520     }
1521   else if (group)
1522     {
1523       if (IS_WILDCARD (group))
1524         {
1525           rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow); 
1526           if (rule == NULL)
1527             goto nomem;
1528
1529           rule->d.group.gid = DBUS_GID_UNSET;
1530         }
1531       else
1532         {
1533           DBusString groupname;
1534           dbus_gid_t gid;
1535           
1536           _dbus_string_init_const (&groupname, group);
1537           
1538           if (_dbus_parse_unix_group_from_config (&groupname, &gid))
1539             {
1540               rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow); 
1541               if (rule == NULL)
1542                 goto nomem;
1543
1544               rule->d.group.gid = gid;
1545             }
1546           else
1547             {
1548               _dbus_warn ("Unknown group \"%s\" on element <%s>\n",
1549                           group, element_name);
1550             }
1551         }
1552     }
1553   else
1554     _dbus_assert_not_reached ("Did not handle some combination of attributes on <allow> or <deny>");
1555
1556   if (rule != NULL)
1557     {
1558       Element *pe;
1559       
1560       pe = peek_element (parser);      
1561       _dbus_assert (pe != NULL);
1562       _dbus_assert (pe->type == ELEMENT_POLICY);
1563
1564       switch (pe->d.policy.type)
1565         {
1566         case POLICY_IGNORED:
1567           /* drop the rule on the floor */
1568           break;
1569           
1570         case POLICY_DEFAULT:
1571           if (!bus_policy_append_default_rule (parser->policy, rule))
1572             goto nomem;
1573           break;
1574         case POLICY_MANDATORY:
1575           if (!bus_policy_append_mandatory_rule (parser->policy, rule))
1576             goto nomem;
1577           break;
1578         case POLICY_USER:
1579           if (!BUS_POLICY_RULE_IS_PER_CLIENT (rule))
1580             {
1581               dbus_set_error (error, DBUS_ERROR_FAILED,
1582                               "<%s> rule cannot be per-user because it has bus-global semantics",
1583                               element_name);
1584               goto failed;
1585             }
1586           
1587           if (!bus_policy_append_user_rule (parser->policy, pe->d.policy.gid_uid_or_at_console,
1588                                             rule))
1589             goto nomem;
1590           break;
1591         case POLICY_GROUP:
1592           if (!BUS_POLICY_RULE_IS_PER_CLIENT (rule))
1593             {
1594               dbus_set_error (error, DBUS_ERROR_FAILED,
1595                               "<%s> rule cannot be per-group because it has bus-global semantics",
1596                               element_name);
1597               goto failed;
1598             }
1599           
1600           if (!bus_policy_append_group_rule (parser->policy, pe->d.policy.gid_uid_or_at_console,
1601                                              rule))
1602             goto nomem;
1603           break;
1604         
1605
1606         case POLICY_CONSOLE:
1607           if (!bus_policy_append_console_rule (parser->policy, pe->d.policy.gid_uid_or_at_console,
1608                                                rule))
1609             goto nomem;
1610           break;
1611         }
1612  
1613       bus_policy_rule_unref (rule);
1614       rule = NULL;
1615     }
1616   
1617   return TRUE;
1618
1619  nomem:
1620   BUS_SET_OOM (error);
1621  failed:
1622   if (rule)
1623     bus_policy_rule_unref (rule);
1624   return FALSE;
1625 }
1626
1627 static dbus_bool_t
1628 start_policy_child (BusConfigParser   *parser,
1629                     const char        *element_name,
1630                     const char       **attribute_names,
1631                     const char       **attribute_values,
1632                     DBusError         *error)
1633 {
1634   if (strcmp (element_name, "allow") == 0)
1635     {
1636       if (!append_rule_from_element (parser, element_name,
1637                                      attribute_names, attribute_values,
1638                                      TRUE, error))
1639         return FALSE;
1640       
1641       if (push_element (parser, ELEMENT_ALLOW) == NULL)
1642         {
1643           BUS_SET_OOM (error);
1644           return FALSE;
1645         }
1646       
1647       return TRUE;
1648     }
1649   else if (strcmp (element_name, "deny") == 0)
1650     {
1651       if (!append_rule_from_element (parser, element_name,
1652                                      attribute_names, attribute_values,
1653                                      FALSE, error))
1654         return FALSE;
1655       
1656       if (push_element (parser, ELEMENT_DENY) == NULL)
1657         {
1658           BUS_SET_OOM (error);
1659           return FALSE;
1660         }
1661       
1662       return TRUE;
1663     }
1664   else
1665     {
1666       dbus_set_error (error, DBUS_ERROR_FAILED,
1667                       "Element <%s> not allowed inside <%s> in configuration file",
1668                       element_name, "policy");
1669       return FALSE;
1670     }
1671 }
1672
1673 static dbus_bool_t
1674 start_selinux_child (BusConfigParser   *parser,
1675                      const char        *element_name,
1676                      const char       **attribute_names,
1677                      const char       **attribute_values,
1678                      DBusError         *error)
1679 {
1680   char *own_copy;
1681   char *context_copy;
1682
1683   own_copy = NULL;
1684   context_copy = NULL;
1685
1686   if (strcmp (element_name, "associate") == 0)
1687     {
1688       const char *own;
1689       const char *context;
1690       
1691       if (!locate_attributes (parser, "associate",
1692                               attribute_names,
1693                               attribute_values,
1694                               error,
1695                               "own", &own,
1696                               "context", &context,
1697                               NULL))
1698         return FALSE;
1699       
1700       if (push_element (parser, ELEMENT_ASSOCIATE) == NULL)
1701         {
1702           BUS_SET_OOM (error);
1703           return FALSE;
1704         }
1705
1706       if (own == NULL || context == NULL)
1707         {
1708           dbus_set_error (error, DBUS_ERROR_FAILED,
1709                           "Element <associate> must have attributes own=\"<servicename>\" and context=\"<selinux context>\"");
1710           return FALSE;
1711         }
1712
1713       own_copy = _dbus_strdup (own);
1714       if (own_copy == NULL)
1715         goto oom;
1716       context_copy = _dbus_strdup (context);
1717       if (context_copy == NULL)
1718         goto oom;
1719
1720       if (!_dbus_hash_table_insert_string (parser->service_context_table,
1721                                            own_copy, context_copy))
1722         goto oom;
1723
1724       return TRUE;
1725     }
1726   else
1727     {
1728       dbus_set_error (error, DBUS_ERROR_FAILED,
1729                       "Element <%s> not allowed inside <%s> in configuration file",
1730                       element_name, "selinux");
1731       return FALSE;
1732     }
1733
1734  oom:
1735   if (own_copy)
1736     dbus_free (own_copy);
1737
1738   if (context_copy)  
1739     dbus_free (context_copy);
1740
1741   BUS_SET_OOM (error);
1742   return FALSE;
1743 }
1744
1745 dbus_bool_t
1746 bus_config_parser_start_element (BusConfigParser   *parser,
1747                                  const char        *element_name,
1748                                  const char       **attribute_names,
1749                                  const char       **attribute_values,
1750                                  DBusError         *error)
1751 {
1752   ElementType t;
1753
1754   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1755
1756   /* printf ("START: %s\n", element_name); */
1757   
1758   t = top_element_type (parser);
1759
1760   if (t == ELEMENT_NONE)
1761     {
1762       if (strcmp (element_name, "busconfig") == 0)
1763         {
1764           if (!check_no_attributes (parser, "busconfig", attribute_names, attribute_values, error))
1765             return FALSE;
1766           
1767           if (push_element (parser, ELEMENT_BUSCONFIG) == NULL)
1768             {
1769               BUS_SET_OOM (error);
1770               return FALSE;
1771             }
1772
1773           return TRUE;
1774         }
1775       else
1776         {
1777           dbus_set_error (error, DBUS_ERROR_FAILED,
1778                           "Unknown element <%s> at root of configuration file",
1779                           element_name);
1780           return FALSE;
1781         }
1782     }
1783   else if (t == ELEMENT_BUSCONFIG)
1784     {
1785       return start_busconfig_child (parser, element_name,
1786                                     attribute_names, attribute_values,
1787                                     error);
1788     }
1789   else if (t == ELEMENT_POLICY)
1790     {
1791       return start_policy_child (parser, element_name,
1792                                  attribute_names, attribute_values,
1793                                  error);
1794     }
1795   else if (t == ELEMENT_SELINUX)
1796     {
1797       return start_selinux_child (parser, element_name,
1798                                   attribute_names, attribute_values,
1799                                   error);
1800     }
1801   else
1802     {
1803       dbus_set_error (error, DBUS_ERROR_FAILED,
1804                       "Element <%s> is not allowed in this context",
1805                       element_name);
1806       return FALSE;
1807     }  
1808 }
1809
1810 static dbus_bool_t
1811 set_limit (BusConfigParser *parser,
1812            const char      *name,
1813            long             value,
1814            DBusError       *error)
1815 {
1816   dbus_bool_t must_be_positive;
1817   dbus_bool_t must_be_int;
1818
1819   must_be_int = FALSE;
1820   must_be_positive = FALSE;
1821   
1822   if (strcmp (name, "max_incoming_bytes") == 0)
1823     {
1824       must_be_positive = TRUE;
1825       parser->limits.max_incoming_bytes = value;
1826     }
1827   else if (strcmp (name, "max_outgoing_bytes") == 0)
1828     {
1829       must_be_positive = TRUE;
1830       parser->limits.max_outgoing_bytes = value;
1831     }
1832   else if (strcmp (name, "max_message_size") == 0)
1833     {
1834       must_be_positive = TRUE;
1835       parser->limits.max_message_size = value;
1836     }
1837   else if (strcmp (name, "service_start_timeout") == 0)
1838     {
1839       must_be_positive = TRUE;
1840       must_be_int = TRUE;
1841       parser->limits.activation_timeout = value;
1842     }
1843   else if (strcmp (name, "auth_timeout") == 0)
1844     {
1845       must_be_positive = TRUE;
1846       must_be_int = TRUE;
1847       parser->limits.auth_timeout = value;
1848     }
1849   else if (strcmp (name, "reply_timeout") == 0)
1850     {
1851       must_be_positive = TRUE;
1852       must_be_int = TRUE;
1853       parser->limits.reply_timeout = value;
1854     }
1855   else if (strcmp (name, "max_completed_connections") == 0)
1856     {
1857       must_be_positive = TRUE;
1858       must_be_int = TRUE;
1859       parser->limits.max_completed_connections = value;
1860     }
1861   else if (strcmp (name, "max_incomplete_connections") == 0)
1862     {
1863       must_be_positive = TRUE;
1864       must_be_int = TRUE;
1865       parser->limits.max_incomplete_connections = value;
1866     }
1867   else if (strcmp (name, "max_connections_per_user") == 0)
1868     {
1869       must_be_positive = TRUE;
1870       must_be_int = TRUE;
1871       parser->limits.max_connections_per_user = value;
1872     }
1873   else if (strcmp (name, "max_pending_service_starts") == 0)
1874     {
1875       must_be_positive = TRUE;
1876       must_be_int = TRUE;
1877       parser->limits.max_pending_activations = value;
1878     }
1879   else if (strcmp (name, "max_names_per_connection") == 0)
1880     {
1881       must_be_positive = TRUE;
1882       must_be_int = TRUE;
1883       parser->limits.max_services_per_connection = value;
1884     }
1885   else if (strcmp (name, "max_match_rules_per_connection") == 0)
1886     {
1887       must_be_positive = TRUE;
1888       must_be_int = TRUE;
1889       parser->limits.max_match_rules_per_connection = value;
1890     }
1891   else if (strcmp (name, "max_replies_per_connection") == 0)
1892     {
1893       must_be_positive = TRUE;
1894       must_be_int = TRUE;
1895       parser->limits.max_replies_per_connection = value;
1896     }
1897   else
1898     {
1899       dbus_set_error (error, DBUS_ERROR_FAILED,
1900                       "There is no limit called \"%s\"\n",
1901                       name);
1902       return FALSE;
1903     }
1904   
1905   if (must_be_positive && value < 0)
1906     {
1907       dbus_set_error (error, DBUS_ERROR_FAILED,
1908                       "<limit name=\"%s\"> must be a positive number\n",
1909                       name);
1910       return FALSE;
1911     }
1912
1913   if (must_be_int &&
1914       (value < _DBUS_INT_MIN || value > _DBUS_INT_MAX))
1915     {
1916       dbus_set_error (error, DBUS_ERROR_FAILED,
1917                       "<limit name=\"%s\"> value is too large\n",
1918                       name);
1919       return FALSE;
1920     }
1921
1922   return TRUE;  
1923 }
1924
1925 dbus_bool_t
1926 bus_config_parser_end_element (BusConfigParser   *parser,
1927                                const char        *element_name,
1928                                DBusError         *error)
1929 {
1930   ElementType t;
1931   const char *n;
1932   Element *e;
1933
1934   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1935
1936   /* printf ("END: %s\n", element_name); */
1937   
1938   t = top_element_type (parser);
1939
1940   if (t == ELEMENT_NONE)
1941     {
1942       /* should probably be an assertion failure but
1943        * being paranoid about XML parsers
1944        */
1945       dbus_set_error (error, DBUS_ERROR_FAILED,
1946                       "XML parser ended element with no element on the stack");
1947       return FALSE;
1948     }
1949
1950   n = bus_config_parser_element_type_to_name (t);
1951   _dbus_assert (n != NULL);
1952   if (strcmp (n, element_name) != 0)
1953     {
1954       /* should probably be an assertion failure but
1955        * being paranoid about XML parsers
1956        */
1957       dbus_set_error (error, DBUS_ERROR_FAILED,
1958                       "XML element <%s> ended but topmost element on the stack was <%s>",
1959                       element_name, n);
1960       return FALSE;
1961     }
1962
1963   e = peek_element (parser);
1964   _dbus_assert (e != NULL);
1965
1966   switch (e->type)
1967     {
1968     case ELEMENT_NONE:
1969       _dbus_assert_not_reached ("element in stack has no type");
1970       break;
1971
1972     case ELEMENT_INCLUDE:
1973     case ELEMENT_USER:
1974     case ELEMENT_TYPE:
1975     case ELEMENT_LISTEN:
1976     case ELEMENT_PIDFILE:
1977     case ELEMENT_AUTH:
1978     case ELEMENT_SERVICEDIR:
1979     case ELEMENT_SERVICEHELPER:
1980     case ELEMENT_INCLUDEDIR:
1981     case ELEMENT_LIMIT:
1982       if (!e->had_content)
1983         {
1984           dbus_set_error (error, DBUS_ERROR_FAILED,
1985                           "XML element <%s> was expected to have content inside it",
1986                           bus_config_parser_element_type_to_name (e->type));
1987           return FALSE;
1988         }
1989
1990       if (e->type == ELEMENT_LIMIT)
1991         {
1992           if (!set_limit (parser, e->d.limit.name, e->d.limit.value,
1993                           error))
1994             return FALSE;
1995         }
1996       break;
1997
1998     case ELEMENT_BUSCONFIG:
1999     case ELEMENT_POLICY:
2000     case ELEMENT_ALLOW:
2001     case ELEMENT_DENY:
2002     case ELEMENT_FORK:
2003     case ELEMENT_KEEP_UMASK:
2004     case ELEMENT_SYSLOG:
2005     case ELEMENT_SELINUX:
2006     case ELEMENT_ASSOCIATE:
2007     case ELEMENT_STANDARD_SESSION_SERVICEDIRS:
2008     case ELEMENT_STANDARD_SYSTEM_SERVICEDIRS:
2009     case ELEMENT_ALLOW_ANONYMOUS:
2010       break;
2011     }
2012
2013   pop_element (parser);
2014
2015   return TRUE;
2016 }
2017
2018 static dbus_bool_t
2019 all_whitespace (const DBusString *str)
2020 {
2021   int i;
2022
2023   _dbus_string_skip_white (str, 0, &i);
2024
2025   return i == _dbus_string_get_length (str);
2026 }
2027
2028 static dbus_bool_t
2029 make_full_path (const DBusString *basedir,
2030                 const DBusString *filename,
2031                 DBusString       *full_path)
2032 {
2033   if (_dbus_path_is_absolute (filename))
2034     {
2035       return _dbus_string_copy (filename, 0, full_path, 0);
2036     }
2037   else
2038     {
2039       if (!_dbus_string_copy (basedir, 0, full_path, 0))
2040         return FALSE;
2041       
2042       if (!_dbus_concat_dir_and_file (full_path, filename))
2043         return FALSE;
2044
2045       return TRUE;
2046     }
2047 }
2048
2049 static dbus_bool_t
2050 include_file (BusConfigParser   *parser,
2051               const DBusString  *filename,
2052               dbus_bool_t        ignore_missing,
2053               DBusError         *error)
2054 {
2055   /* FIXME good test case for this would load each config file in the
2056    * test suite both alone, and as an include, and check
2057    * that the result is the same
2058    */
2059   BusConfigParser *included;
2060   const char *filename_str;
2061   DBusError tmp_error;
2062         
2063   dbus_error_init (&tmp_error);
2064
2065   filename_str = _dbus_string_get_const_data (filename);
2066
2067   /* Check to make sure this file hasn't already been included. */
2068   if (seen_include (parser, filename))
2069     {
2070       dbus_set_error (error, DBUS_ERROR_FAILED,
2071                       "Circular inclusion of file '%s'",
2072                       filename_str);
2073       return FALSE;
2074     }
2075   
2076   if (! _dbus_list_append (&parser->included_files, (void *) filename_str))
2077     {
2078       BUS_SET_OOM (error);
2079       return FALSE;
2080     }
2081
2082   /* Since parser is passed in as the parent, included
2083      inherits parser's limits. */
2084   included = bus_config_load (filename, FALSE, parser, &tmp_error);
2085
2086   _dbus_list_pop_last (&parser->included_files);
2087
2088   if (included == NULL)
2089     {
2090       _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
2091
2092       if (dbus_error_has_name (&tmp_error, DBUS_ERROR_FILE_NOT_FOUND) &&
2093           ignore_missing)
2094         {
2095           dbus_error_free (&tmp_error);
2096           return TRUE;
2097         }
2098       else
2099         {
2100           dbus_move_error (&tmp_error, error);
2101           return FALSE;
2102         }
2103     }
2104   else
2105     {
2106       _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
2107
2108       if (!merge_included (parser, included, error))
2109         {
2110           bus_config_parser_unref (included);
2111           return FALSE;
2112         }
2113
2114       /* Copy included's limits back to parser. */
2115       parser->limits = included->limits;
2116
2117       bus_config_parser_unref (included);
2118       return TRUE;
2119     }
2120 }
2121
2122 static dbus_bool_t
2123 servicehelper_path (BusConfigParser   *parser,
2124                     const DBusString  *filename,
2125                     DBusError         *error)
2126 {
2127   const char *filename_str;
2128   char *servicehelper;
2129
2130   filename_str = _dbus_string_get_const_data (filename);
2131
2132   /* copy to avoid overwriting with NULL on OOM */
2133   servicehelper = _dbus_strdup (filename_str);
2134
2135   /* check for OOM */
2136   if (servicehelper == NULL)
2137     {
2138       BUS_SET_OOM (error);
2139       return FALSE;
2140     }
2141
2142   /* save the latest servicehelper only if not OOM */
2143   dbus_free (parser->servicehelper);
2144   parser->servicehelper = servicehelper;
2145
2146   /* We don't check whether the helper exists; instead we
2147    * would just fail to ever activate anything if it doesn't.
2148    * This allows an admin to fix the problem if it doesn't exist.
2149    * It also allows the parser test suite to successfully parse
2150    * test cases without installing the helper. ;-)
2151    */
2152   
2153   return TRUE;
2154 }
2155
2156 static dbus_bool_t
2157 include_dir (BusConfigParser   *parser,
2158              const DBusString  *dirname,
2159              DBusError         *error)
2160 {
2161   DBusString filename;
2162   dbus_bool_t retval;
2163   DBusError tmp_error;
2164   DBusDirIter *dir;
2165   char *s;
2166   
2167   if (!_dbus_string_init (&filename))
2168     {
2169       BUS_SET_OOM (error);
2170       return FALSE;
2171     }
2172
2173   retval = FALSE;
2174   
2175   dir = _dbus_directory_open (dirname, error);
2176
2177   if (dir == NULL)
2178     goto failed;
2179
2180   dbus_error_init (&tmp_error);
2181   while (_dbus_directory_get_next_file (dir, &filename, &tmp_error))
2182     {
2183       DBusString full_path;
2184
2185       if (!_dbus_string_init (&full_path))
2186         {
2187           BUS_SET_OOM (error);
2188           goto failed;
2189         }
2190
2191       if (!_dbus_string_copy (dirname, 0, &full_path, 0))
2192         {
2193           BUS_SET_OOM (error);
2194           _dbus_string_free (&full_path);
2195           goto failed;
2196         }      
2197
2198       if (!_dbus_concat_dir_and_file (&full_path, &filename))
2199         {
2200           BUS_SET_OOM (error);
2201           _dbus_string_free (&full_path);
2202           goto failed;
2203         }
2204       
2205       if (_dbus_string_ends_with_c_str (&full_path, ".conf"))
2206         {
2207           if (!include_file (parser, &full_path, TRUE, error))
2208             {
2209               _dbus_string_free (&full_path);
2210               goto failed;
2211             }
2212         }
2213
2214       _dbus_string_free (&full_path);
2215     }
2216
2217   if (dbus_error_is_set (&tmp_error))
2218     {
2219       dbus_move_error (&tmp_error, error);
2220       goto failed;
2221     }
2222
2223
2224   if (!_dbus_string_copy_data (dirname, &s))
2225     {
2226       BUS_SET_OOM (error);
2227       goto failed;
2228     }
2229
2230   if (!_dbus_list_append (&parser->conf_dirs, s))
2231     {
2232       dbus_free (s);
2233       BUS_SET_OOM (error);
2234       goto failed;
2235     }
2236
2237   retval = TRUE;
2238   
2239  failed:
2240   _dbus_string_free (&filename);
2241   
2242   if (dir)
2243     _dbus_directory_close (dir);
2244
2245   return retval;
2246 }
2247
2248 dbus_bool_t
2249 bus_config_parser_content (BusConfigParser   *parser,
2250                            const DBusString  *content,
2251                            DBusError         *error)
2252 {
2253   Element *e;
2254
2255   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2256
2257 #if 0
2258   {
2259     const char *c_str;
2260     
2261     _dbus_string_get_const_data (content, &c_str);
2262
2263     printf ("CONTENT %d bytes: %s\n", _dbus_string_get_length (content), c_str);
2264   }
2265 #endif
2266   
2267   e = peek_element (parser);
2268   if (e == NULL)
2269     {
2270       dbus_set_error (error, DBUS_ERROR_FAILED,
2271                       "Text content outside of any XML element in configuration file");
2272       return FALSE;
2273     }
2274   else if (e->had_content)
2275     {
2276       _dbus_assert_not_reached ("Element had multiple content blocks");
2277       return FALSE;
2278     }
2279
2280   switch (top_element_type (parser))
2281     {
2282     case ELEMENT_NONE:
2283       _dbus_assert_not_reached ("element at top of stack has no type");
2284       return FALSE;
2285
2286     case ELEMENT_BUSCONFIG:
2287     case ELEMENT_POLICY:
2288     case ELEMENT_ALLOW:
2289     case ELEMENT_DENY:
2290     case ELEMENT_FORK:
2291     case ELEMENT_KEEP_UMASK:
2292     case ELEMENT_SYSLOG:
2293     case ELEMENT_STANDARD_SESSION_SERVICEDIRS:    
2294     case ELEMENT_STANDARD_SYSTEM_SERVICEDIRS:    
2295     case ELEMENT_ALLOW_ANONYMOUS:
2296     case ELEMENT_SELINUX:
2297     case ELEMENT_ASSOCIATE:
2298       if (all_whitespace (content))
2299         return TRUE;
2300       else
2301         {
2302           dbus_set_error (error, DBUS_ERROR_FAILED,
2303                           "No text content expected inside XML element %s in configuration file",
2304                           bus_config_parser_element_type_to_name (top_element_type (parser)));
2305           return FALSE;
2306         }
2307
2308     case ELEMENT_PIDFILE:
2309       {
2310         char *s;
2311
2312         e->had_content = TRUE;
2313         
2314         if (!_dbus_string_copy_data (content, &s))
2315           goto nomem;
2316           
2317         dbus_free (parser->pidfile);
2318         parser->pidfile = s;
2319       }
2320       break;
2321
2322     case ELEMENT_INCLUDE:
2323       {
2324         DBusString full_path, selinux_policy_root;
2325
2326         e->had_content = TRUE;
2327
2328         if (e->d.include.if_selinux_enabled
2329             && !bus_selinux_enabled ())
2330           break;
2331
2332         if (!_dbus_string_init (&full_path))
2333           goto nomem;
2334
2335         if (e->d.include.selinux_root_relative)
2336           {
2337             if (!bus_selinux_get_policy_root ())
2338               {
2339                 dbus_set_error (error, DBUS_ERROR_FAILED,
2340                                 "Could not determine SELinux policy root for relative inclusion");
2341                 _dbus_string_free (&full_path);
2342                 return FALSE;
2343               }
2344             _dbus_string_init_const (&selinux_policy_root,
2345                                      bus_selinux_get_policy_root ());
2346             if (!make_full_path (&selinux_policy_root, content, &full_path))
2347               {
2348                 _dbus_string_free (&full_path);
2349                 goto nomem;
2350               }
2351           }
2352         else if (!make_full_path (&parser->basedir, content, &full_path))
2353           {
2354             _dbus_string_free (&full_path);
2355             goto nomem;
2356           }
2357
2358         if (!include_file (parser, &full_path,
2359                            e->d.include.ignore_missing, error))
2360           {
2361             _dbus_string_free (&full_path);
2362             return FALSE;
2363           }
2364
2365         _dbus_string_free (&full_path);
2366       }
2367       break;
2368
2369     case ELEMENT_SERVICEHELPER:
2370       {
2371         DBusString full_path;
2372         
2373         e->had_content = TRUE;
2374
2375         if (!_dbus_string_init (&full_path))
2376           goto nomem;
2377         
2378         if (!make_full_path (&parser->basedir, content, &full_path))
2379           {
2380             _dbus_string_free (&full_path);
2381             goto nomem;
2382           }
2383
2384         if (!servicehelper_path (parser, &full_path, error))
2385           {
2386             _dbus_string_free (&full_path);
2387             return FALSE;
2388           }
2389
2390         _dbus_string_free (&full_path);
2391       }
2392       break;
2393       
2394     case ELEMENT_INCLUDEDIR:
2395       {
2396         DBusString full_path;
2397         
2398         e->had_content = TRUE;
2399
2400         if (!_dbus_string_init (&full_path))
2401           goto nomem;
2402         
2403         if (!make_full_path (&parser->basedir, content, &full_path))
2404           {
2405             _dbus_string_free (&full_path);
2406             goto nomem;
2407           }
2408         
2409         if (!include_dir (parser, &full_path, error))
2410           {
2411             _dbus_string_free (&full_path);
2412             return FALSE;
2413           }
2414
2415         _dbus_string_free (&full_path);
2416       }
2417       break;
2418       
2419     case ELEMENT_USER:
2420       {
2421         char *s;
2422
2423         e->had_content = TRUE;
2424         
2425         if (!_dbus_string_copy_data (content, &s))
2426           goto nomem;
2427           
2428         dbus_free (parser->user);
2429         parser->user = s;
2430       }
2431       break;
2432
2433     case ELEMENT_TYPE:
2434       {
2435         char *s;
2436
2437         e->had_content = TRUE;
2438
2439         if (!_dbus_string_copy_data (content, &s))
2440           goto nomem;
2441         
2442         dbus_free (parser->bus_type);
2443         parser->bus_type = s;
2444       }
2445       break;
2446       
2447     case ELEMENT_LISTEN:
2448       {
2449         char *s;
2450
2451         e->had_content = TRUE;
2452         
2453         if (!_dbus_string_copy_data (content, &s))
2454           goto nomem;
2455
2456         if (!_dbus_list_append (&parser->listen_on,
2457                                 s))
2458           {
2459             dbus_free (s);
2460             goto nomem;
2461           }
2462       }
2463       break;
2464
2465     case ELEMENT_AUTH:
2466       {
2467         char *s;
2468         
2469         e->had_content = TRUE;
2470
2471         if (!_dbus_string_copy_data (content, &s))
2472           goto nomem;
2473
2474         if (!_dbus_list_append (&parser->mechanisms,
2475                                 s))
2476           {
2477             dbus_free (s);
2478             goto nomem;
2479           }
2480       }
2481       break;
2482
2483     case ELEMENT_SERVICEDIR:
2484       {
2485         char *s;
2486         DBusString full_path;
2487         
2488         e->had_content = TRUE;
2489
2490         if (!_dbus_string_init (&full_path))
2491           goto nomem;
2492         
2493         if (!make_full_path (&parser->basedir, content, &full_path))
2494           {
2495             _dbus_string_free (&full_path);
2496             goto nomem;
2497           }
2498         
2499         if (!_dbus_string_copy_data (&full_path, &s))
2500           {
2501             _dbus_string_free (&full_path);
2502             goto nomem;
2503           }
2504
2505         /* _only_ extra session directories can be specified */
2506         if (!service_dirs_append_unique_or_free (&parser->service_dirs, s))
2507           {
2508             _dbus_string_free (&full_path);
2509             dbus_free (s);
2510             goto nomem;
2511           }
2512
2513         _dbus_string_free (&full_path);
2514       }
2515       break;
2516
2517     case ELEMENT_LIMIT:
2518       {
2519         long val;
2520
2521         e->had_content = TRUE;
2522
2523         val = 0;
2524         if (!_dbus_string_parse_int (content, 0, &val, NULL))
2525           {
2526             dbus_set_error (error, DBUS_ERROR_FAILED,
2527                             "<limit name=\"%s\"> element has invalid value (could not parse as integer)",
2528                             e->d.limit.name);
2529             return FALSE;
2530           }
2531
2532         e->d.limit.value = val;
2533
2534         _dbus_verbose ("Loaded value %ld for limit %s\n",
2535                        e->d.limit.value,
2536                        e->d.limit.name);
2537       }
2538       break;
2539     }
2540
2541   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2542   return TRUE;
2543
2544  nomem:
2545   BUS_SET_OOM (error);
2546   return FALSE;
2547 }
2548
2549 dbus_bool_t
2550 bus_config_parser_finished (BusConfigParser   *parser,
2551                             DBusError         *error)
2552 {
2553   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2554
2555   if (parser->stack != NULL)
2556     {
2557       dbus_set_error (error, DBUS_ERROR_FAILED,
2558                       "Element <%s> was not closed in configuration file",
2559                       bus_config_parser_element_type_to_name (top_element_type (parser)));
2560
2561       return FALSE;
2562     }
2563
2564   if (parser->is_toplevel && parser->listen_on == NULL)
2565     {
2566       dbus_set_error (error, DBUS_ERROR_FAILED,
2567                       "Configuration file needs one or more <listen> elements giving addresses"); 
2568       return FALSE;
2569     }
2570   
2571   return TRUE;
2572 }
2573
2574 const char*
2575 bus_config_parser_get_user (BusConfigParser *parser)
2576 {
2577   return parser->user;
2578 }
2579
2580 const char*
2581 bus_config_parser_get_type (BusConfigParser *parser)
2582 {
2583   return parser->bus_type;
2584 }
2585
2586 DBusList**
2587 bus_config_parser_get_addresses (BusConfigParser *parser)
2588 {
2589   return &parser->listen_on;
2590 }
2591
2592 DBusList**
2593 bus_config_parser_get_mechanisms (BusConfigParser *parser)
2594 {
2595   return &parser->mechanisms;
2596 }
2597
2598 DBusList**
2599 bus_config_parser_get_service_dirs (BusConfigParser *parser)
2600 {
2601   return &parser->service_dirs;
2602 }
2603
2604 DBusList**
2605 bus_config_parser_get_conf_dirs (BusConfigParser *parser)
2606 {
2607   return &parser->conf_dirs;
2608 }
2609
2610 dbus_bool_t
2611 bus_config_parser_get_fork (BusConfigParser   *parser)
2612 {
2613   return parser->fork;
2614 }
2615
2616 dbus_bool_t
2617 bus_config_parser_get_keep_umask (BusConfigParser   *parser)
2618 {
2619   return parser->keep_umask;
2620 }
2621
2622 dbus_bool_t
2623 bus_config_parser_get_syslog (BusConfigParser   *parser)
2624 {
2625   return parser->syslog;
2626 }
2627
2628 dbus_bool_t
2629 bus_config_parser_get_allow_anonymous (BusConfigParser   *parser)
2630 {
2631   return parser->allow_anonymous;
2632 }
2633
2634 const char *
2635 bus_config_parser_get_pidfile (BusConfigParser   *parser)
2636 {
2637   return parser->pidfile;
2638 }
2639
2640 const char *
2641 bus_config_parser_get_servicehelper (BusConfigParser   *parser)
2642 {
2643   return parser->servicehelper;
2644 }
2645
2646 BusPolicy*
2647 bus_config_parser_steal_policy (BusConfigParser *parser)
2648 {
2649   BusPolicy *policy;
2650
2651   _dbus_assert (parser->policy != NULL); /* can only steal the policy 1 time */
2652   
2653   policy = parser->policy;
2654
2655   parser->policy = NULL;
2656
2657   return policy;
2658 }
2659
2660 /* Overwrite any limits that were set in the configuration file */
2661 void
2662 bus_config_parser_get_limits (BusConfigParser *parser,
2663                               BusLimits       *limits)
2664 {
2665   *limits = parser->limits;
2666 }
2667
2668 DBusHashTable*
2669 bus_config_parser_steal_service_context_table (BusConfigParser *parser)
2670 {
2671   DBusHashTable *table;
2672
2673   _dbus_assert (parser->service_context_table != NULL); /* can only steal once */
2674
2675   table = parser->service_context_table;
2676
2677   parser->service_context_table = NULL;
2678
2679   return table;
2680 }
2681
2682 #ifdef DBUS_BUILD_TESTS
2683 #include <stdio.h>
2684
2685 typedef enum
2686 {
2687   VALID,
2688   INVALID,
2689   UNKNOWN
2690 } Validity;
2691
2692 static dbus_bool_t
2693 do_load (const DBusString *full_path,
2694          Validity          validity,
2695          dbus_bool_t       oom_possible)
2696 {
2697   BusConfigParser *parser;
2698   DBusError error;
2699
2700   dbus_error_init (&error);
2701
2702   parser = bus_config_load (full_path, TRUE, NULL, &error);
2703   if (parser == NULL)
2704     {
2705       _DBUS_ASSERT_ERROR_IS_SET (&error);
2706
2707       if (oom_possible &&
2708           dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
2709         {
2710           _dbus_verbose ("Failed to load valid file due to OOM\n");
2711           dbus_error_free (&error);
2712           return TRUE;
2713         }
2714       else if (validity == VALID)
2715         {
2716           _dbus_warn ("Failed to load valid file but still had memory: %s\n",
2717                       error.message);
2718
2719           dbus_error_free (&error);
2720           return FALSE;
2721         }
2722       else
2723         {
2724           dbus_error_free (&error);
2725           return TRUE;
2726         }
2727     }
2728   else
2729     {
2730       _DBUS_ASSERT_ERROR_IS_CLEAR (&error);
2731
2732       bus_config_parser_unref (parser);
2733
2734       if (validity == INVALID)
2735         {
2736           _dbus_warn ("Accepted invalid file\n");
2737           return FALSE;
2738         }
2739
2740       return TRUE;
2741     }
2742 }
2743
2744 typedef struct
2745 {
2746   const DBusString *full_path;
2747   Validity          validity;
2748 } LoaderOomData;
2749
2750 static dbus_bool_t
2751 check_loader_oom_func (void *data)
2752 {
2753   LoaderOomData *d = data;
2754
2755   return do_load (d->full_path, d->validity, TRUE);
2756 }
2757
2758 static dbus_bool_t
2759 process_test_valid_subdir (const DBusString *test_base_dir,
2760                            const char       *subdir,
2761                            Validity          validity)
2762 {
2763   DBusString test_directory;
2764   DBusString filename;
2765   DBusDirIter *dir;
2766   dbus_bool_t retval;
2767   DBusError error;
2768
2769   retval = FALSE;
2770   dir = NULL;
2771
2772   if (!_dbus_string_init (&test_directory))
2773     _dbus_assert_not_reached ("didn't allocate test_directory\n");
2774
2775   _dbus_string_init_const (&filename, subdir);
2776
2777   if (!_dbus_string_copy (test_base_dir, 0,
2778                           &test_directory, 0))
2779     _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
2780
2781   if (!_dbus_concat_dir_and_file (&test_directory, &filename))
2782     _dbus_assert_not_reached ("couldn't allocate full path");
2783
2784   _dbus_string_free (&filename);
2785   if (!_dbus_string_init (&filename))
2786     _dbus_assert_not_reached ("didn't allocate filename string\n");
2787
2788   dbus_error_init (&error);
2789   dir = _dbus_directory_open (&test_directory, &error);
2790   if (dir == NULL)
2791     {
2792       _dbus_warn ("Could not open %s: %s\n",
2793                   _dbus_string_get_const_data (&test_directory),
2794                   error.message);
2795       dbus_error_free (&error);
2796       goto failed;
2797     }
2798
2799   if (validity == VALID)
2800     printf ("Testing valid files:\n");
2801   else if (validity == INVALID)
2802     printf ("Testing invalid files:\n");
2803   else
2804     printf ("Testing unknown files:\n");
2805
2806  next:
2807   while (_dbus_directory_get_next_file (dir, &filename, &error))
2808     {
2809       DBusString full_path;
2810       LoaderOomData d;
2811
2812       if (!_dbus_string_init (&full_path))
2813         _dbus_assert_not_reached ("couldn't init string");
2814
2815       if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
2816         _dbus_assert_not_reached ("couldn't copy dir to full_path");
2817
2818       if (!_dbus_concat_dir_and_file (&full_path, &filename))
2819         _dbus_assert_not_reached ("couldn't concat file to dir");
2820
2821       if (!_dbus_string_ends_with_c_str (&full_path, ".conf"))
2822         {
2823           _dbus_verbose ("Skipping non-.conf file %s\n",
2824                          _dbus_string_get_const_data (&filename));
2825           _dbus_string_free (&full_path);
2826           goto next;
2827         }
2828
2829       printf ("    %s\n", _dbus_string_get_const_data (&filename));
2830
2831       _dbus_verbose (" expecting %s\n",
2832                      validity == VALID ? "valid" :
2833                      (validity == INVALID ? "invalid" :
2834                       (validity == UNKNOWN ? "unknown" : "???")));
2835
2836       d.full_path = &full_path;
2837       d.validity = validity;
2838
2839       /* FIXME hackaround for an expat problem, see
2840        * https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=124747
2841        * http://freedesktop.org/pipermail/dbus/2004-May/001153.html
2842        */
2843       /* if (!_dbus_test_oom_handling ("config-loader", check_loader_oom_func, &d)) */
2844       if (!check_loader_oom_func (&d))
2845         _dbus_assert_not_reached ("test failed");
2846       
2847       _dbus_string_free (&full_path);
2848     }
2849
2850   if (dbus_error_is_set (&error))
2851     {
2852       _dbus_warn ("Could not get next file in %s: %s\n",
2853                   _dbus_string_get_const_data (&test_directory),
2854                   error.message);
2855       dbus_error_free (&error);
2856       goto failed;
2857     }
2858
2859   retval = TRUE;
2860
2861  failed:
2862
2863   if (dir)
2864     _dbus_directory_close (dir);
2865   _dbus_string_free (&test_directory);
2866   _dbus_string_free (&filename);
2867
2868   return retval;
2869 }
2870
2871 static dbus_bool_t
2872 bools_equal (dbus_bool_t a,
2873              dbus_bool_t b)
2874 {
2875   return a ? b : !b;
2876 }
2877
2878 static dbus_bool_t
2879 strings_equal_or_both_null (const char *a,
2880                             const char *b)
2881 {
2882   if (a == NULL || b == NULL)
2883     return a == b;
2884   else
2885     return !strcmp (a, b);
2886 }
2887
2888 static dbus_bool_t
2889 elements_equal (const Element *a,
2890                 const Element *b)
2891 {
2892   if (a->type != b->type)
2893     return FALSE;
2894
2895   if (!bools_equal (a->had_content, b->had_content))
2896     return FALSE;
2897
2898   switch (a->type)
2899     {
2900
2901     case ELEMENT_INCLUDE:
2902       if (!bools_equal (a->d.include.ignore_missing,
2903                         b->d.include.ignore_missing))
2904         return FALSE;
2905       break;
2906
2907     case ELEMENT_POLICY:
2908       if (a->d.policy.type != b->d.policy.type)
2909         return FALSE;
2910       if (a->d.policy.gid_uid_or_at_console != b->d.policy.gid_uid_or_at_console)
2911         return FALSE;
2912       break;
2913
2914     case ELEMENT_LIMIT:
2915       if (strcmp (a->d.limit.name, b->d.limit.name))
2916         return FALSE;
2917       if (a->d.limit.value != b->d.limit.value)
2918         return FALSE;
2919       break;
2920
2921     default:
2922       /* do nothing */
2923       break;
2924     }
2925
2926   return TRUE;
2927
2928 }
2929
2930 static dbus_bool_t
2931 lists_of_elements_equal (DBusList *a,
2932                          DBusList *b)
2933 {
2934   DBusList *ia;
2935   DBusList *ib;
2936
2937   ia = a;
2938   ib = b;
2939   
2940   while (ia != NULL && ib != NULL)
2941     {
2942       if (elements_equal (ia->data, ib->data))
2943         return FALSE;
2944       ia = _dbus_list_get_next_link (&a, ia);
2945       ib = _dbus_list_get_next_link (&b, ib);
2946     }
2947
2948   return ia == NULL && ib == NULL;
2949 }
2950
2951 static dbus_bool_t
2952 lists_of_c_strings_equal (DBusList *a,
2953                           DBusList *b)
2954 {
2955   DBusList *ia;
2956   DBusList *ib;
2957
2958   ia = a;
2959   ib = b;
2960   
2961   while (ia != NULL && ib != NULL)
2962     {
2963       if (strcmp (ia->data, ib->data))
2964         return FALSE;
2965       ia = _dbus_list_get_next_link (&a, ia);
2966       ib = _dbus_list_get_next_link (&b, ib);
2967     }
2968
2969   return ia == NULL && ib == NULL;
2970 }
2971
2972 static dbus_bool_t
2973 limits_equal (const BusLimits *a,
2974               const BusLimits *b)
2975 {
2976   return
2977     (a->max_incoming_bytes == b->max_incoming_bytes
2978      || a->max_outgoing_bytes == b->max_outgoing_bytes
2979      || a->max_message_size == b->max_message_size
2980      || a->activation_timeout == b->activation_timeout
2981      || a->auth_timeout == b->auth_timeout
2982      || a->max_completed_connections == b->max_completed_connections
2983      || a->max_incomplete_connections == b->max_incomplete_connections
2984      || a->max_connections_per_user == b->max_connections_per_user
2985      || a->max_pending_activations == b->max_pending_activations
2986      || a->max_services_per_connection == b->max_services_per_connection
2987      || a->max_match_rules_per_connection == b->max_match_rules_per_connection
2988      || a->max_replies_per_connection == b->max_replies_per_connection
2989      || a->reply_timeout == b->reply_timeout);
2990 }
2991
2992 static dbus_bool_t
2993 config_parsers_equal (const BusConfigParser *a,
2994                       const BusConfigParser *b)
2995 {
2996   if (!_dbus_string_equal (&a->basedir, &b->basedir))
2997     return FALSE;
2998
2999   if (!lists_of_elements_equal (a->stack, b->stack))
3000     return FALSE;
3001
3002   if (!strings_equal_or_both_null (a->user, b->user))
3003     return FALSE;
3004
3005   if (!lists_of_c_strings_equal (a->listen_on, b->listen_on))
3006     return FALSE;
3007
3008   if (!lists_of_c_strings_equal (a->mechanisms, b->mechanisms))
3009     return FALSE;
3010
3011   if (!lists_of_c_strings_equal (a->service_dirs, b->service_dirs))
3012     return FALSE;
3013   
3014   /* FIXME: compare policy */
3015
3016   /* FIXME: compare service selinux ID table */
3017
3018   if (! limits_equal (&a->limits, &b->limits))
3019     return FALSE;
3020
3021   if (!strings_equal_or_both_null (a->pidfile, b->pidfile))
3022     return FALSE;
3023
3024   if (! bools_equal (a->fork, b->fork))
3025     return FALSE;
3026
3027   if (! bools_equal (a->keep_umask, b->keep_umask))
3028     return FALSE;
3029
3030   if (! bools_equal (a->is_toplevel, b->is_toplevel))
3031     return FALSE;
3032
3033   return TRUE;
3034 }
3035
3036 static dbus_bool_t
3037 all_are_equiv (const DBusString *target_directory)
3038 {
3039   DBusString filename;
3040   DBusDirIter *dir;
3041   BusConfigParser *first_parser;
3042   BusConfigParser *parser;
3043   DBusError error;
3044   dbus_bool_t equal;
3045   dbus_bool_t retval;
3046
3047   dir = NULL;
3048   first_parser = NULL;
3049   parser = NULL;
3050   retval = FALSE;
3051
3052   if (!_dbus_string_init (&filename))
3053     _dbus_assert_not_reached ("didn't allocate filename string");
3054
3055   dbus_error_init (&error);
3056   dir = _dbus_directory_open (target_directory, &error);
3057   if (dir == NULL)
3058     {
3059       _dbus_warn ("Could not open %s: %s\n",
3060                   _dbus_string_get_const_data (target_directory),
3061                   error.message);
3062       dbus_error_free (&error);
3063       goto finished;
3064     }
3065
3066   printf ("Comparing equivalent files:\n");
3067
3068  next:
3069   while (_dbus_directory_get_next_file (dir, &filename, &error))
3070     {
3071       DBusString full_path;
3072
3073       if (!_dbus_string_init (&full_path))
3074         _dbus_assert_not_reached ("couldn't init string");
3075
3076       if (!_dbus_string_copy (target_directory, 0, &full_path, 0))
3077         _dbus_assert_not_reached ("couldn't copy dir to full_path");
3078
3079       if (!_dbus_concat_dir_and_file (&full_path, &filename))
3080         _dbus_assert_not_reached ("couldn't concat file to dir");
3081
3082       if (!_dbus_string_ends_with_c_str (&full_path, ".conf"))
3083         {
3084           _dbus_verbose ("Skipping non-.conf file %s\n",
3085                          _dbus_string_get_const_data (&filename));
3086           _dbus_string_free (&full_path);
3087           goto next;
3088         }
3089
3090       printf ("    %s\n", _dbus_string_get_const_data (&filename));
3091
3092       parser = bus_config_load (&full_path, TRUE, NULL, &error);
3093
3094       if (parser == NULL)
3095         {
3096           _dbus_warn ("Could not load file %s: %s\n",
3097                       _dbus_string_get_const_data (&full_path),
3098                       error.message);
3099           _dbus_string_free (&full_path);
3100           dbus_error_free (&error);
3101           goto finished;
3102         }
3103       else if (first_parser == NULL)
3104         {
3105           _dbus_string_free (&full_path);
3106           first_parser = parser;
3107         }
3108       else
3109         {
3110           _dbus_string_free (&full_path);
3111           equal = config_parsers_equal (first_parser, parser);
3112           bus_config_parser_unref (parser);
3113           if (! equal)
3114             goto finished;
3115         }
3116     }
3117
3118   retval = TRUE;
3119
3120  finished:
3121   _dbus_string_free (&filename);
3122   if (first_parser)
3123     bus_config_parser_unref (first_parser);
3124   if (dir)
3125     _dbus_directory_close (dir);
3126
3127   return retval;
3128   
3129 }
3130
3131 static dbus_bool_t
3132 process_test_equiv_subdir (const DBusString *test_base_dir,
3133                            const char       *subdir)
3134 {
3135   DBusString test_directory;
3136   DBusString filename;
3137   DBusDirIter *dir;
3138   DBusError error;
3139   dbus_bool_t equal;
3140   dbus_bool_t retval;
3141
3142   dir = NULL;
3143   retval = FALSE;
3144
3145   if (!_dbus_string_init (&test_directory))
3146     _dbus_assert_not_reached ("didn't allocate test_directory");
3147
3148   _dbus_string_init_const (&filename, subdir);
3149
3150   if (!_dbus_string_copy (test_base_dir, 0,
3151                           &test_directory, 0))
3152     _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
3153
3154   if (!_dbus_concat_dir_and_file (&test_directory, &filename))
3155     _dbus_assert_not_reached ("couldn't allocate full path");
3156
3157   _dbus_string_free (&filename);
3158   if (!_dbus_string_init (&filename))
3159     _dbus_assert_not_reached ("didn't allocate filename string");
3160
3161   dbus_error_init (&error);
3162   dir = _dbus_directory_open (&test_directory, &error);
3163   if (dir == NULL)
3164     {
3165       _dbus_warn ("Could not open %s: %s\n",
3166                   _dbus_string_get_const_data (&test_directory),
3167                   error.message);
3168       dbus_error_free (&error);
3169       goto finished;
3170     }
3171
3172   while (_dbus_directory_get_next_file (dir, &filename, &error))
3173     {
3174       DBusString full_path;
3175
3176       /* Skip CVS's magic directories! */
3177       if (_dbus_string_equal_c_str (&filename, "CVS"))
3178         continue;
3179
3180       if (!_dbus_string_init (&full_path))
3181         _dbus_assert_not_reached ("couldn't init string");
3182
3183       if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
3184         _dbus_assert_not_reached ("couldn't copy dir to full_path");
3185
3186       if (!_dbus_concat_dir_and_file (&full_path, &filename))
3187         _dbus_assert_not_reached ("couldn't concat file to dir");
3188       
3189       equal = all_are_equiv (&full_path);
3190       _dbus_string_free (&full_path);
3191
3192       if (!equal)
3193         goto finished;
3194     }
3195
3196   retval = TRUE;
3197
3198  finished:
3199   _dbus_string_free (&test_directory);
3200   _dbus_string_free (&filename);
3201   if (dir)
3202     _dbus_directory_close (dir);
3203
3204   return retval;
3205   
3206 }
3207
3208 static const char *test_session_service_dir_matches[] = 
3209         {
3210 #ifdef DBUS_UNIX
3211          "/testusr/testlocal/testshare/dbus-1/services",
3212          "/testusr/testshare/dbus-1/services",
3213 #endif
3214          DBUS_DATADIR"/dbus-1/services",
3215 #ifdef DBUS_UNIX
3216          "/testhome/foo/.testlocal/testshare/dbus-1/services",
3217 #endif
3218          NULL
3219         };
3220
3221 static dbus_bool_t
3222 test_default_session_servicedirs (void)
3223 {
3224   DBusList *dirs;
3225   DBusList *link;
3226   DBusString progs;
3227   const char *common_progs;
3228   int i;
3229
3230   /* On Unix we don't actually use this variable, but it's easier to handle the
3231    * deallocation if we always allocate it, whether needed or not */
3232   if (!_dbus_string_init (&progs))
3233     _dbus_assert_not_reached ("OOM allocating progs");
3234
3235   common_progs = _dbus_getenv ("CommonProgramFiles");
3236 #ifndef DBUS_UNIX
3237   if (common_progs) 
3238     {
3239       if (!_dbus_string_append (&progs, common_progs)) 
3240         {
3241           _dbus_string_free (&progs);
3242           return FALSE;
3243         }
3244
3245       if (!_dbus_string_append (&progs, "/dbus-1/services")) 
3246         {
3247           _dbus_string_free (&progs);
3248           return FALSE;
3249         }
3250       test_session_service_dir_matches[1] = _dbus_string_get_const_data(&progs);
3251     }
3252 #endif
3253   dirs = NULL;
3254
3255   printf ("Testing retrieving the default session service directories\n");
3256   if (!_dbus_get_standard_session_servicedirs (&dirs))
3257     _dbus_assert_not_reached ("couldn't get stardard dirs");
3258
3259   /* make sure our defaults end with share/dbus-1/service */
3260   while ((link = _dbus_list_pop_first_link (&dirs)))
3261     {
3262       DBusString path;
3263       
3264       printf ("    default service dir: %s\n", (char *)link->data);
3265       _dbus_string_init_const (&path, (char *)link->data);
3266       if (!_dbus_string_ends_with_c_str (&path, "dbus-1/services"))
3267         {
3268           printf ("error with default session service directories\n");
3269               dbus_free (link->data);
3270           _dbus_list_free_link (link);
3271           _dbus_string_free (&progs);
3272           return FALSE;
3273         }
3274  
3275       dbus_free (link->data);
3276       _dbus_list_free_link (link);
3277     }
3278
3279 #ifdef DBUS_UNIX
3280   if (!_dbus_setenv ("XDG_DATA_HOME", "/testhome/foo/.testlocal/testshare"))
3281     _dbus_assert_not_reached ("couldn't setenv XDG_DATA_HOME");
3282
3283   if (!_dbus_setenv ("XDG_DATA_DIRS", ":/testusr/testlocal/testshare: :/testusr/testshare:"))
3284     _dbus_assert_not_reached ("couldn't setenv XDG_DATA_DIRS");
3285 #endif
3286   if (!_dbus_get_standard_session_servicedirs (&dirs))
3287     _dbus_assert_not_reached ("couldn't get stardard dirs");
3288
3289   /* make sure we read and parse the env variable correctly */
3290   i = 0;
3291   while ((link = _dbus_list_pop_first_link (&dirs)))
3292     {
3293       printf ("    test service dir: %s\n", (char *)link->data);
3294       if (test_session_service_dir_matches[i] == NULL)
3295         {
3296           printf ("more directories parsed than in match set\n");
3297           dbus_free (link->data);
3298           _dbus_list_free_link (link);
3299           _dbus_string_free (&progs);
3300           return FALSE;
3301         }
3302  
3303       if (strcmp (test_session_service_dir_matches[i], 
3304                   (char *)link->data) != 0)
3305         {
3306           printf ("%s directory does not match %s in the match set\n", 
3307                   (char *)link->data,
3308                   test_session_service_dir_matches[i]);
3309           dbus_free (link->data);
3310           _dbus_list_free_link (link);
3311           _dbus_string_free (&progs);
3312           return FALSE;
3313         }
3314
3315       ++i;
3316
3317       dbus_free (link->data);
3318       _dbus_list_free_link (link);
3319     }
3320   
3321   if (test_session_service_dir_matches[i] != NULL)
3322     {
3323       printf ("extra data %s in the match set was not matched\n",
3324               test_session_service_dir_matches[i]);
3325
3326       _dbus_string_free (&progs);
3327       return FALSE;
3328     }
3329     
3330   _dbus_string_free (&progs);
3331   return TRUE;
3332 }
3333
3334 static const char *test_system_service_dir_matches[] = 
3335         {
3336 #ifdef DBUS_UNIX
3337          "/testusr/testlocal/testshare/dbus-1/system-services",
3338          "/testusr/testshare/dbus-1/system-services",
3339 #endif
3340          DBUS_DATADIR"/dbus-1/system-services",
3341          NULL
3342         };
3343
3344 static dbus_bool_t
3345 test_default_system_servicedirs (void)
3346 {
3347   DBusList *dirs;
3348   DBusList *link;
3349   DBusString progs;
3350   const char *common_progs;
3351   int i;
3352
3353   /* On Unix we don't actually use this variable, but it's easier to handle the
3354    * deallocation if we always allocate it, whether needed or not */
3355   if (!_dbus_string_init (&progs))
3356     _dbus_assert_not_reached ("OOM allocating progs");
3357
3358   common_progs = _dbus_getenv ("CommonProgramFiles");
3359 #ifndef DBUS_UNIX
3360   if (common_progs) 
3361     {
3362       if (!_dbus_string_append (&progs, common_progs)) 
3363         {
3364           _dbus_string_free (&progs);
3365           return FALSE;
3366         }
3367
3368       if (!_dbus_string_append (&progs, "/dbus-1/system-services")) 
3369         {
3370           _dbus_string_free (&progs);
3371           return FALSE;
3372         }
3373       test_system_service_dir_matches[1] = _dbus_string_get_const_data(&progs);
3374     }
3375 #endif
3376   dirs = NULL;
3377
3378   printf ("Testing retrieving the default system service directories\n");
3379   if (!_dbus_get_standard_system_servicedirs (&dirs))
3380     _dbus_assert_not_reached ("couldn't get stardard dirs");
3381
3382   /* make sure our defaults end with share/dbus-1/system-service */
3383   while ((link = _dbus_list_pop_first_link (&dirs)))
3384     {
3385       DBusString path;
3386       
3387       printf ("    default service dir: %s\n", (char *)link->data);
3388       _dbus_string_init_const (&path, (char *)link->data);
3389       if (!_dbus_string_ends_with_c_str (&path, "dbus-1/system-services"))
3390         {
3391           printf ("error with default system service directories\n");
3392               dbus_free (link->data);
3393           _dbus_list_free_link (link);
3394           _dbus_string_free (&progs);
3395           return FALSE;
3396         }
3397  
3398       dbus_free (link->data);
3399       _dbus_list_free_link (link);
3400     }
3401
3402 #ifdef DBUS_UNIX
3403   if (!_dbus_setenv ("XDG_DATA_HOME", "/testhome/foo/.testlocal/testshare"))
3404     _dbus_assert_not_reached ("couldn't setenv XDG_DATA_HOME");
3405
3406   if (!_dbus_setenv ("XDG_DATA_DIRS", ":/testusr/testlocal/testshare: :/testusr/testshare:"))
3407     _dbus_assert_not_reached ("couldn't setenv XDG_DATA_DIRS");
3408 #endif
3409   if (!_dbus_get_standard_system_servicedirs (&dirs))
3410     _dbus_assert_not_reached ("couldn't get stardard dirs");
3411
3412   /* make sure we read and parse the env variable correctly */
3413   i = 0;
3414   while ((link = _dbus_list_pop_first_link (&dirs)))
3415     {
3416       printf ("    test service dir: %s\n", (char *)link->data);
3417       if (test_system_service_dir_matches[i] == NULL)
3418         {
3419           printf ("more directories parsed than in match set\n");
3420           dbus_free (link->data);
3421           _dbus_list_free_link (link);
3422           _dbus_string_free (&progs);
3423           return FALSE;
3424         }
3425  
3426       if (strcmp (test_system_service_dir_matches[i], 
3427                   (char *)link->data) != 0)
3428         {
3429           printf ("%s directory does not match %s in the match set\n", 
3430                   (char *)link->data,
3431                   test_system_service_dir_matches[i]);
3432           dbus_free (link->data);
3433           _dbus_list_free_link (link);
3434           _dbus_string_free (&progs);
3435           return FALSE;
3436         }
3437
3438       ++i;
3439
3440       dbus_free (link->data);
3441       _dbus_list_free_link (link);
3442     }
3443   
3444   if (test_system_service_dir_matches[i] != NULL)
3445     {
3446       printf ("extra data %s in the match set was not matched\n",
3447               test_system_service_dir_matches[i]);
3448
3449       _dbus_string_free (&progs);
3450       return FALSE;
3451     }
3452     
3453   _dbus_string_free (&progs);
3454   return TRUE;
3455 }
3456                    
3457 dbus_bool_t
3458 bus_config_parser_test (const DBusString *test_data_dir)
3459 {
3460   if (test_data_dir == NULL ||
3461       _dbus_string_get_length (test_data_dir) == 0)
3462     {
3463       printf ("No test data\n");
3464       return TRUE;
3465     }
3466
3467   if (!test_default_session_servicedirs())
3468     return FALSE;
3469
3470   if (!test_default_system_servicedirs())
3471     return FALSE;
3472
3473   if (!process_test_valid_subdir (test_data_dir, "valid-config-files", VALID))
3474     return FALSE;
3475
3476   if (!process_test_valid_subdir (test_data_dir, "invalid-config-files", INVALID))
3477     return FALSE;
3478
3479   if (!process_test_equiv_subdir (test_data_dir, "equiv-config-files"))
3480     return FALSE;
3481
3482   return TRUE;
3483 }
3484
3485 #endif /* DBUS_BUILD_TESTS */
3486