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