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