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