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