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