Merge branch 'dbus-1.10'
[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",
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",
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>",
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>",
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       if (!_dbus_string_copy (filename, 0, full_path, 0))
2126         return FALSE;
2127     }
2128   else
2129     {
2130       if (!_dbus_string_copy (basedir, 0, full_path, 0))
2131         return FALSE;
2132       
2133       if (!_dbus_concat_dir_and_file (full_path, filename))
2134         return FALSE;
2135     }
2136
2137   if (!_dbus_replace_install_prefix (full_path))
2138     return FALSE;
2139
2140   return TRUE;
2141 }
2142
2143 static dbus_bool_t
2144 include_file (BusConfigParser   *parser,
2145               const DBusString  *filename,
2146               dbus_bool_t        ignore_missing,
2147               DBusError         *error)
2148 {
2149   /* FIXME good test case for this would load each config file in the
2150    * test suite both alone, and as an include, and check
2151    * that the result is the same
2152    */
2153   BusConfigParser *included;
2154   const char *filename_str;
2155   DBusError tmp_error;
2156         
2157   dbus_error_init (&tmp_error);
2158
2159   filename_str = _dbus_string_get_const_data (filename);
2160
2161   /* Check to make sure this file hasn't already been included. */
2162   if (seen_include (parser, filename))
2163     {
2164       dbus_set_error (error, DBUS_ERROR_FAILED,
2165                       "Circular inclusion of file '%s'",
2166                       filename_str);
2167       return FALSE;
2168     }
2169   
2170   if (! _dbus_list_append (&parser->included_files, (void *) filename_str))
2171     {
2172       BUS_SET_OOM (error);
2173       return FALSE;
2174     }
2175
2176   /* Since parser is passed in as the parent, included
2177      inherits parser's limits. */
2178   included = bus_config_load (filename, FALSE, parser, &tmp_error);
2179
2180   _dbus_list_pop_last (&parser->included_files);
2181
2182   if (included == NULL)
2183     {
2184       _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
2185
2186       if (dbus_error_has_name (&tmp_error, DBUS_ERROR_FILE_NOT_FOUND) &&
2187           ignore_missing)
2188         {
2189           dbus_error_free (&tmp_error);
2190           return TRUE;
2191         }
2192       else
2193         {
2194           dbus_move_error (&tmp_error, error);
2195           return FALSE;
2196         }
2197     }
2198   else
2199     {
2200       _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
2201
2202       if (!merge_included (parser, included, error))
2203         {
2204           bus_config_parser_unref (included);
2205           return FALSE;
2206         }
2207
2208       /* Copy included's limits back to parser. */
2209       parser->limits = included->limits;
2210
2211       bus_config_parser_unref (included);
2212       return TRUE;
2213     }
2214 }
2215
2216 static dbus_bool_t
2217 servicehelper_path (BusConfigParser   *parser,
2218                     const DBusString  *filename,
2219                     DBusError         *error)
2220 {
2221   const char *filename_str;
2222   char *servicehelper;
2223
2224   filename_str = _dbus_string_get_const_data (filename);
2225
2226   /* copy to avoid overwriting with NULL on OOM */
2227   servicehelper = _dbus_strdup (filename_str);
2228
2229   /* check for OOM */
2230   if (servicehelper == NULL)
2231     {
2232       BUS_SET_OOM (error);
2233       return FALSE;
2234     }
2235
2236   /* save the latest servicehelper only if not OOM */
2237   dbus_free (parser->servicehelper);
2238   parser->servicehelper = servicehelper;
2239
2240   /* We don't check whether the helper exists; instead we
2241    * would just fail to ever activate anything if it doesn't.
2242    * This allows an admin to fix the problem if it doesn't exist.
2243    * It also allows the parser test suite to successfully parse
2244    * test cases without installing the helper. ;-)
2245    */
2246   
2247   return TRUE;
2248 }
2249
2250 static dbus_bool_t
2251 include_dir (BusConfigParser   *parser,
2252              const DBusString  *dirname,
2253              DBusError         *error)
2254 {
2255   DBusString filename;
2256   dbus_bool_t retval;
2257   DBusError tmp_error;
2258   DBusDirIter *dir;
2259   char *s;
2260   
2261   if (!_dbus_string_init (&filename))
2262     {
2263       BUS_SET_OOM (error);
2264       return FALSE;
2265     }
2266
2267   retval = FALSE;
2268   
2269   dir = _dbus_directory_open (dirname, error);
2270
2271   if (dir == NULL)
2272     {
2273       if (dbus_error_has_name (error, DBUS_ERROR_FILE_NOT_FOUND))
2274         {
2275           dbus_error_free (error);
2276           goto success;
2277         }
2278       else
2279         goto failed;
2280     }
2281
2282   dbus_error_init (&tmp_error);
2283   while (_dbus_directory_get_next_file (dir, &filename, &tmp_error))
2284     {
2285       DBusString full_path;
2286
2287       if (!_dbus_string_init (&full_path))
2288         {
2289           BUS_SET_OOM (error);
2290           goto failed;
2291         }
2292
2293       if (!_dbus_string_copy (dirname, 0, &full_path, 0))
2294         {
2295           BUS_SET_OOM (error);
2296           _dbus_string_free (&full_path);
2297           goto failed;
2298         }      
2299
2300       if (!_dbus_concat_dir_and_file (&full_path, &filename))
2301         {
2302           BUS_SET_OOM (error);
2303           _dbus_string_free (&full_path);
2304           goto failed;
2305         }
2306       
2307       if (_dbus_string_ends_with_c_str (&full_path, ".conf"))
2308         {
2309           if (!include_file (parser, &full_path, TRUE, error))
2310             {
2311               if (dbus_error_is_set (error))
2312                 {
2313                   /* We use both syslog and stderr here, because this is
2314                    * the configuration parser, so we don't yet know whether
2315                    * this bus is going to want to write to syslog! Err on
2316                    * the side of making sure the message gets to the sysadmin
2317                    * somehow. */
2318                   _dbus_init_system_log ("dbus-daemon",
2319                       DBUS_LOG_FLAGS_STDERR | DBUS_LOG_FLAGS_SYSTEM_LOG);
2320                   _dbus_log (DBUS_SYSTEM_LOG_INFO,
2321                              "Encountered error '%s' while parsing '%s'",
2322                              error->message,
2323                              _dbus_string_get_const_data (&full_path));
2324                   dbus_error_free (error);
2325                 }
2326             }
2327         }
2328
2329       _dbus_string_free (&full_path);
2330     }
2331
2332   if (dbus_error_is_set (&tmp_error))
2333     {
2334       dbus_move_error (&tmp_error, error);
2335       goto failed;
2336     }
2337
2338
2339   if (!_dbus_string_copy_data (dirname, &s))
2340     {
2341       BUS_SET_OOM (error);
2342       goto failed;
2343     }
2344
2345   if (!_dbus_list_append (&parser->conf_dirs, s))
2346     {
2347       dbus_free (s);
2348       BUS_SET_OOM (error);
2349       goto failed;
2350     }
2351
2352  success:
2353   retval = TRUE;
2354   
2355  failed:
2356   _dbus_string_free (&filename);
2357   
2358   if (dir)
2359     _dbus_directory_close (dir);
2360
2361   return retval;
2362 }
2363
2364 dbus_bool_t
2365 bus_config_parser_content (BusConfigParser   *parser,
2366                            const DBusString  *content,
2367                            DBusError         *error)
2368 {
2369   Element *e;
2370
2371   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2372
2373 #if 0
2374   {
2375     const char *c_str;
2376     
2377     _dbus_string_get_const_data (content, &c_str);
2378
2379     printf ("CONTENT %d bytes: %s\n", _dbus_string_get_length (content), c_str);
2380   }
2381 #endif
2382   
2383   e = peek_element (parser);
2384   if (e == NULL)
2385     {
2386       dbus_set_error (error, DBUS_ERROR_FAILED,
2387                       "Text content outside of any XML element in configuration file");
2388       return FALSE;
2389     }
2390   else if (e->had_content)
2391     {
2392       _dbus_assert_not_reached ("Element had multiple content blocks");
2393       return FALSE;
2394     }
2395
2396   switch (top_element_type (parser))
2397     {
2398     case ELEMENT_NONE:
2399       _dbus_assert_not_reached ("element at top of stack has no type");
2400       return FALSE;
2401
2402     case ELEMENT_BUSCONFIG:
2403     case ELEMENT_POLICY:
2404     case ELEMENT_ALLOW:
2405     case ELEMENT_DENY:
2406     case ELEMENT_FORK:
2407     case ELEMENT_SYSLOG:
2408     case ELEMENT_KEEP_UMASK:
2409     case ELEMENT_STANDARD_SESSION_SERVICEDIRS:    
2410     case ELEMENT_STANDARD_SYSTEM_SERVICEDIRS:    
2411     case ELEMENT_ALLOW_ANONYMOUS:
2412     case ELEMENT_SELINUX:
2413     case ELEMENT_ASSOCIATE:
2414     case ELEMENT_APPARMOR:
2415       if (all_whitespace (content))
2416         return TRUE;
2417       else
2418         {
2419           dbus_set_error (error, DBUS_ERROR_FAILED,
2420                           "No text content expected inside XML element %s in configuration file",
2421                           bus_config_parser_element_type_to_name (top_element_type (parser)));
2422           return FALSE;
2423         }
2424
2425     case ELEMENT_PIDFILE:
2426       {
2427         char *s;
2428
2429         e->had_content = TRUE;
2430         
2431         if (!_dbus_string_copy_data (content, &s))
2432           goto nomem;
2433           
2434         dbus_free (parser->pidfile);
2435         parser->pidfile = s;
2436       }
2437       break;
2438
2439     case ELEMENT_INCLUDE:
2440       {
2441         DBusString full_path, selinux_policy_root;
2442
2443         e->had_content = TRUE;
2444
2445         if (e->d.include.if_selinux_enabled
2446             && !bus_selinux_enabled ())
2447           break;
2448
2449         if (!_dbus_string_init (&full_path))
2450           goto nomem;
2451
2452         if (e->d.include.selinux_root_relative)
2453           {
2454             if (!bus_selinux_get_policy_root ())
2455               {
2456                 dbus_set_error (error, DBUS_ERROR_FAILED,
2457                                 "Could not determine SELinux policy root for relative inclusion");
2458                 _dbus_string_free (&full_path);
2459                 return FALSE;
2460               }
2461             _dbus_string_init_const (&selinux_policy_root,
2462                                      bus_selinux_get_policy_root ());
2463             if (!make_full_path (&selinux_policy_root, content, &full_path))
2464               {
2465                 _dbus_string_free (&full_path);
2466                 goto nomem;
2467               }
2468           }
2469         else if (!make_full_path (&parser->basedir, content, &full_path))
2470           {
2471             _dbus_string_free (&full_path);
2472             goto nomem;
2473           }
2474
2475         if (!include_file (parser, &full_path,
2476                            e->d.include.ignore_missing, error))
2477           {
2478             _dbus_string_free (&full_path);
2479             return FALSE;
2480           }
2481
2482         _dbus_string_free (&full_path);
2483       }
2484       break;
2485
2486     case ELEMENT_SERVICEHELPER:
2487       {
2488         DBusString full_path;
2489         
2490         e->had_content = TRUE;
2491
2492         if (!_dbus_string_init (&full_path))
2493           goto nomem;
2494         
2495         if (!make_full_path (&parser->basedir, content, &full_path))
2496           {
2497             _dbus_string_free (&full_path);
2498             goto nomem;
2499           }
2500
2501         if (!servicehelper_path (parser, &full_path, error))
2502           {
2503             _dbus_string_free (&full_path);
2504             return FALSE;
2505           }
2506
2507         _dbus_string_free (&full_path);
2508       }
2509       break;
2510       
2511     case ELEMENT_INCLUDEDIR:
2512       {
2513         DBusString full_path;
2514         
2515         e->had_content = TRUE;
2516
2517         if (!_dbus_string_init (&full_path))
2518           goto nomem;
2519         
2520         if (!make_full_path (&parser->basedir, content, &full_path))
2521           {
2522             _dbus_string_free (&full_path);
2523             goto nomem;
2524           }
2525         
2526         if (!include_dir (parser, &full_path, error))
2527           {
2528             _dbus_string_free (&full_path);
2529             return FALSE;
2530           }
2531
2532         _dbus_string_free (&full_path);
2533       }
2534       break;
2535       
2536     case ELEMENT_USER:
2537       {
2538         char *s;
2539
2540         e->had_content = TRUE;
2541         
2542         if (!_dbus_string_copy_data (content, &s))
2543           goto nomem;
2544           
2545         dbus_free (parser->user);
2546         parser->user = s;
2547       }
2548       break;
2549
2550     case ELEMENT_CONFIGTYPE:
2551       {
2552         char *s;
2553
2554         e->had_content = TRUE;
2555
2556         if (!_dbus_string_copy_data (content, &s))
2557           goto nomem;
2558         
2559         dbus_free (parser->bus_type);
2560         parser->bus_type = s;
2561       }
2562       break;
2563       
2564     case ELEMENT_LISTEN:
2565       {
2566         char *s;
2567
2568         e->had_content = TRUE;
2569         
2570         if (!_dbus_string_copy_data (content, &s))
2571           goto nomem;
2572
2573         if (!_dbus_list_append (&parser->listen_on,
2574                                 s))
2575           {
2576             dbus_free (s);
2577             goto nomem;
2578           }
2579       }
2580       break;
2581
2582     case ELEMENT_AUTH:
2583       {
2584         char *s;
2585         
2586         e->had_content = TRUE;
2587
2588         if (!_dbus_string_copy_data (content, &s))
2589           goto nomem;
2590
2591         if (!_dbus_list_append (&parser->mechanisms,
2592                                 s))
2593           {
2594             dbus_free (s);
2595             goto nomem;
2596           }
2597       }
2598       break;
2599
2600     case ELEMENT_SERVICEDIR:
2601       {
2602         char *s;
2603         DBusString full_path;
2604         
2605         e->had_content = TRUE;
2606
2607         if (!_dbus_string_init (&full_path))
2608           goto nomem;
2609         
2610         if (!make_full_path (&parser->basedir, content, &full_path))
2611           {
2612             _dbus_string_free (&full_path);
2613             goto nomem;
2614           }
2615         
2616         if (!_dbus_string_copy_data (&full_path, &s))
2617           {
2618             _dbus_string_free (&full_path);
2619             goto nomem;
2620           }
2621
2622         /* _only_ extra session directories can be specified */
2623         if (!service_dirs_append_unique_or_free (&parser->service_dirs, s))
2624           {
2625             _dbus_string_free (&full_path);
2626             dbus_free (s);
2627             goto nomem;
2628           }
2629
2630         _dbus_string_free (&full_path);
2631       }
2632       break;
2633
2634     case ELEMENT_LIMIT:
2635       {
2636         long val;
2637
2638         e->had_content = TRUE;
2639
2640         val = 0;
2641         if (!_dbus_string_parse_int (content, 0, &val, NULL))
2642           {
2643             dbus_set_error (error, DBUS_ERROR_FAILED,
2644                             "<limit name=\"%s\"> element has invalid value (could not parse as integer)",
2645                             e->d.limit.name);
2646             return FALSE;
2647           }
2648
2649         e->d.limit.value = val;
2650
2651         _dbus_verbose ("Loaded value %ld for limit %s\n",
2652                        e->d.limit.value,
2653                        e->d.limit.name);
2654       }
2655       break;
2656     }
2657
2658   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2659   return TRUE;
2660
2661  nomem:
2662   BUS_SET_OOM (error);
2663   return FALSE;
2664 }
2665
2666 dbus_bool_t
2667 bus_config_parser_finished (BusConfigParser   *parser,
2668                             DBusError         *error)
2669 {
2670   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2671
2672   if (parser->stack != NULL)
2673     {
2674       dbus_set_error (error, DBUS_ERROR_FAILED,
2675                       "Element <%s> was not closed in configuration file",
2676                       bus_config_parser_element_type_to_name (top_element_type (parser)));
2677
2678       return FALSE;
2679     }
2680
2681   if (parser->is_toplevel && parser->listen_on == NULL)
2682     {
2683       dbus_set_error (error, DBUS_ERROR_FAILED,
2684                       "Configuration file needs one or more <listen> elements giving addresses"); 
2685       return FALSE;
2686     }
2687   
2688   return TRUE;
2689 }
2690
2691 const char*
2692 bus_config_parser_get_user (BusConfigParser *parser)
2693 {
2694   return parser->user;
2695 }
2696
2697 const char*
2698 bus_config_parser_get_type (BusConfigParser *parser)
2699 {
2700   return parser->bus_type;
2701 }
2702
2703 DBusList**
2704 bus_config_parser_get_addresses (BusConfigParser *parser)
2705 {
2706   return &parser->listen_on;
2707 }
2708
2709 DBusList**
2710 bus_config_parser_get_mechanisms (BusConfigParser *parser)
2711 {
2712   return &parser->mechanisms;
2713 }
2714
2715 DBusList**
2716 bus_config_parser_get_service_dirs (BusConfigParser *parser)
2717 {
2718   return &parser->service_dirs;
2719 }
2720
2721 DBusList**
2722 bus_config_parser_get_conf_dirs (BusConfigParser *parser)
2723 {
2724   return &parser->conf_dirs;
2725 }
2726
2727 dbus_bool_t
2728 bus_config_parser_get_fork (BusConfigParser   *parser)
2729 {
2730   return parser->fork;
2731 }
2732
2733 dbus_bool_t
2734 bus_config_parser_get_syslog (BusConfigParser   *parser)
2735 {
2736   return parser->syslog;
2737 }
2738
2739 dbus_bool_t
2740 bus_config_parser_get_keep_umask (BusConfigParser   *parser)
2741 {
2742   return parser->keep_umask;
2743 }
2744
2745 dbus_bool_t
2746 bus_config_parser_get_allow_anonymous (BusConfigParser   *parser)
2747 {
2748   return parser->allow_anonymous;
2749 }
2750
2751 const char *
2752 bus_config_parser_get_pidfile (BusConfigParser   *parser)
2753 {
2754   return parser->pidfile;
2755 }
2756
2757 const char *
2758 bus_config_parser_get_servicehelper (BusConfigParser   *parser)
2759 {
2760   return parser->servicehelper;
2761 }
2762
2763 BusPolicy*
2764 bus_config_parser_steal_policy (BusConfigParser *parser)
2765 {
2766   BusPolicy *policy;
2767
2768   _dbus_assert (parser->policy != NULL); /* can only steal the policy 1 time */
2769   
2770   policy = parser->policy;
2771
2772   parser->policy = NULL;
2773
2774   return policy;
2775 }
2776
2777 /* Overwrite any limits that were set in the configuration file */
2778 void
2779 bus_config_parser_get_limits (BusConfigParser *parser,
2780                               BusLimits       *limits)
2781 {
2782   *limits = parser->limits;
2783 }
2784
2785 DBusHashTable*
2786 bus_config_parser_steal_service_context_table (BusConfigParser *parser)
2787 {
2788   DBusHashTable *table;
2789
2790   _dbus_assert (parser->service_context_table != NULL); /* can only steal once */
2791
2792   table = parser->service_context_table;
2793
2794   parser->service_context_table = NULL;
2795
2796   return table;
2797 }
2798
2799 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
2800 #include <stdio.h>
2801
2802 typedef enum
2803 {
2804   VALID,
2805   INVALID,
2806   UNKNOWN
2807 } Validity;
2808
2809 static dbus_bool_t
2810 do_check_own_rules (BusPolicy  *policy)
2811 {
2812   const struct {
2813     const char *name;
2814     dbus_bool_t allowed;
2815   } checks[] = {
2816     {"org.freedesktop", FALSE},
2817     {"org.freedesktop.ManySystem", FALSE},
2818     {"org.freedesktop.ManySystems", TRUE},
2819     {"org.freedesktop.ManySystems.foo", TRUE},
2820     {"org.freedesktop.ManySystems.foo.bar", TRUE},
2821     {"org.freedesktop.ManySystems2", FALSE},
2822     {"org.freedesktop.ManySystems2.foo", FALSE},
2823     {"org.freedesktop.ManySystems2.foo.bar", FALSE},
2824     {NULL, FALSE}
2825   };
2826   int i = 0;
2827
2828   while (checks[i].name)
2829     {
2830       DBusString service_name;
2831       dbus_bool_t ret;
2832
2833       if (!_dbus_string_init (&service_name))
2834         _dbus_assert_not_reached ("couldn't init string");
2835       if (!_dbus_string_append (&service_name, checks[i].name))
2836         _dbus_assert_not_reached ("couldn't append string");
2837
2838       ret = bus_policy_check_can_own (policy, &service_name);
2839       printf ("        Check name %s: %s\n", checks[i].name,
2840               ret ? "allowed" : "not allowed");
2841       if (checks[i].allowed && !ret)
2842         {
2843           _dbus_warn ("Cannot own %s", checks[i].name);
2844           return FALSE;
2845         }
2846       if (!checks[i].allowed && ret)
2847         {
2848           _dbus_warn ("Can own %s", checks[i].name);
2849           return FALSE;
2850         }
2851       _dbus_string_free (&service_name);
2852
2853       i++;
2854     }
2855
2856   return TRUE;
2857 }
2858
2859 static dbus_bool_t
2860 do_load (const DBusString *full_path,
2861          Validity          validity,
2862          dbus_bool_t       oom_possible,
2863          dbus_bool_t       check_own_rules)
2864 {
2865   BusConfigParser *parser;
2866   DBusError error;
2867
2868   dbus_error_init (&error);
2869
2870   parser = bus_config_load (full_path, TRUE, NULL, &error);
2871   if (parser == NULL)
2872     {
2873       _DBUS_ASSERT_ERROR_IS_SET (&error);
2874
2875       if (oom_possible &&
2876           dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
2877         {
2878           _dbus_verbose ("Failed to load valid file due to OOM\n");
2879           dbus_error_free (&error);
2880           return TRUE;
2881         }
2882       else if (validity == VALID)
2883         {
2884           _dbus_warn ("Failed to load valid file but still had memory: %s",
2885                       error.message);
2886
2887           dbus_error_free (&error);
2888           return FALSE;
2889         }
2890       else
2891         {
2892           dbus_error_free (&error);
2893           return TRUE;
2894         }
2895     }
2896   else
2897     {
2898       _DBUS_ASSERT_ERROR_IS_CLEAR (&error);
2899
2900       if (check_own_rules && do_check_own_rules (parser->policy) == FALSE)
2901         {
2902           return FALSE;
2903         }
2904
2905       bus_config_parser_unref (parser);
2906
2907       if (validity == INVALID)
2908         {
2909           _dbus_warn ("Accepted invalid file");
2910           return FALSE;
2911         }
2912
2913       return TRUE;
2914     }
2915 }
2916
2917 typedef struct
2918 {
2919   const DBusString *full_path;
2920   Validity          validity;
2921   dbus_bool_t       check_own_rules;
2922 } LoaderOomData;
2923
2924 static dbus_bool_t
2925 check_loader_oom_func (void *data)
2926 {
2927   LoaderOomData *d = data;
2928
2929   return do_load (d->full_path, d->validity, TRUE, d->check_own_rules);
2930 }
2931
2932 static dbus_bool_t
2933 process_test_valid_subdir (const DBusString *test_base_dir,
2934                            const char       *subdir,
2935                            Validity          validity)
2936 {
2937   DBusString test_directory;
2938   DBusString filename;
2939   DBusDirIter *dir;
2940   dbus_bool_t retval;
2941   DBusError error;
2942
2943   retval = FALSE;
2944   dir = NULL;
2945
2946   if (!_dbus_string_init (&test_directory))
2947     _dbus_assert_not_reached ("didn't allocate test_directory");
2948
2949   _dbus_string_init_const (&filename, subdir);
2950
2951   if (!_dbus_string_copy (test_base_dir, 0,
2952                           &test_directory, 0))
2953     _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
2954
2955   if (!_dbus_concat_dir_and_file (&test_directory, &filename))
2956     _dbus_assert_not_reached ("couldn't allocate full path");
2957
2958   _dbus_string_free (&filename);
2959   if (!_dbus_string_init (&filename))
2960     _dbus_assert_not_reached ("didn't allocate filename string");
2961
2962   dbus_error_init (&error);
2963   dir = _dbus_directory_open (&test_directory, &error);
2964   if (dir == NULL)
2965     {
2966       _dbus_warn ("Could not open %s: %s",
2967                   _dbus_string_get_const_data (&test_directory),
2968                   error.message);
2969       dbus_error_free (&error);
2970       goto failed;
2971     }
2972
2973   if (validity == VALID)
2974     printf ("Testing valid files:\n");
2975   else if (validity == INVALID)
2976     printf ("Testing invalid files:\n");
2977   else
2978     printf ("Testing unknown files:\n");
2979
2980  next:
2981   while (_dbus_directory_get_next_file (dir, &filename, &error))
2982     {
2983       DBusString full_path;
2984       LoaderOomData d;
2985
2986       if (!_dbus_string_init (&full_path))
2987         _dbus_assert_not_reached ("couldn't init string");
2988
2989       if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
2990         _dbus_assert_not_reached ("couldn't copy dir to full_path");
2991
2992       if (!_dbus_concat_dir_and_file (&full_path, &filename))
2993         _dbus_assert_not_reached ("couldn't concat file to dir");
2994
2995       if (!_dbus_string_ends_with_c_str (&full_path, ".conf"))
2996         {
2997           _dbus_verbose ("Skipping non-.conf file %s\n",
2998                          _dbus_string_get_const_data (&filename));
2999           _dbus_string_free (&full_path);
3000           goto next;
3001         }
3002
3003       printf ("    %s\n", _dbus_string_get_const_data (&filename));
3004
3005       _dbus_verbose (" expecting %s\n",
3006                      validity == VALID ? "valid" :
3007                      (validity == INVALID ? "invalid" :
3008                       (validity == UNKNOWN ? "unknown" : "???")));
3009
3010       d.full_path = &full_path;
3011       d.validity = validity;
3012       d.check_own_rules = _dbus_string_ends_with_c_str (&full_path,
3013           "check-own-rules.conf");
3014
3015       /* FIXME hackaround for an expat problem, see
3016        * https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=124747
3017        * http://freedesktop.org/pipermail/dbus/2004-May/001153.html
3018        */
3019       /* if (!_dbus_test_oom_handling ("config-loader", check_loader_oom_func, &d)) */
3020       if (!check_loader_oom_func (&d))
3021         _dbus_assert_not_reached ("test failed");
3022       
3023       _dbus_string_free (&full_path);
3024     }
3025
3026   if (dbus_error_is_set (&error))
3027     {
3028       _dbus_warn ("Could not get next file in %s: %s",
3029                   _dbus_string_get_const_data (&test_directory),
3030                   error.message);
3031       dbus_error_free (&error);
3032       goto failed;
3033     }
3034
3035   retval = TRUE;
3036
3037  failed:
3038
3039   if (dir)
3040     _dbus_directory_close (dir);
3041   _dbus_string_free (&test_directory);
3042   _dbus_string_free (&filename);
3043
3044   return retval;
3045 }
3046
3047 static dbus_bool_t
3048 bools_equal (dbus_bool_t a,
3049              dbus_bool_t b)
3050 {
3051   return a ? b : !b;
3052 }
3053
3054 static dbus_bool_t
3055 strings_equal_or_both_null (const char *a,
3056                             const char *b)
3057 {
3058   if (a == NULL || b == NULL)
3059     return a == b;
3060   else
3061     return !strcmp (a, b);
3062 }
3063
3064 static dbus_bool_t
3065 elements_equal (const Element *a,
3066                 const Element *b)
3067 {
3068   if (a->type != b->type)
3069     return FALSE;
3070
3071   if (!bools_equal (a->had_content, b->had_content))
3072     return FALSE;
3073
3074   switch (a->type)
3075     {
3076
3077     case ELEMENT_INCLUDE:
3078       if (!bools_equal (a->d.include.ignore_missing,
3079                         b->d.include.ignore_missing))
3080         return FALSE;
3081       break;
3082
3083     case ELEMENT_POLICY:
3084       if (a->d.policy.type != b->d.policy.type)
3085         return FALSE;
3086       if (a->d.policy.gid_uid_or_at_console != b->d.policy.gid_uid_or_at_console)
3087         return FALSE;
3088       break;
3089
3090     case ELEMENT_LIMIT:
3091       if (strcmp (a->d.limit.name, b->d.limit.name))
3092         return FALSE;
3093       if (a->d.limit.value != b->d.limit.value)
3094         return FALSE;
3095       break;
3096
3097     default:
3098       /* do nothing */
3099       break;
3100     }
3101
3102   return TRUE;
3103
3104 }
3105
3106 static dbus_bool_t
3107 lists_of_elements_equal (DBusList *a,
3108                          DBusList *b)
3109 {
3110   DBusList *ia;
3111   DBusList *ib;
3112
3113   ia = a;
3114   ib = b;
3115   
3116   while (ia != NULL && ib != NULL)
3117     {
3118       if (elements_equal (ia->data, ib->data))
3119         return FALSE;
3120       ia = _dbus_list_get_next_link (&a, ia);
3121       ib = _dbus_list_get_next_link (&b, ib);
3122     }
3123
3124   return ia == NULL && ib == NULL;
3125 }
3126
3127 static dbus_bool_t
3128 lists_of_c_strings_equal (DBusList *a,
3129                           DBusList *b)
3130 {
3131   DBusList *ia;
3132   DBusList *ib;
3133
3134   ia = a;
3135   ib = b;
3136   
3137   while (ia != NULL && ib != NULL)
3138     {
3139       if (strcmp (ia->data, ib->data))
3140         return FALSE;
3141       ia = _dbus_list_get_next_link (&a, ia);
3142       ib = _dbus_list_get_next_link (&b, ib);
3143     }
3144
3145   return ia == NULL && ib == NULL;
3146 }
3147
3148 static dbus_bool_t
3149 limits_equal (const BusLimits *a,
3150               const BusLimits *b)
3151 {
3152   return
3153     (a->max_incoming_bytes == b->max_incoming_bytes
3154      || a->max_incoming_unix_fds == b->max_incoming_unix_fds
3155      || a->max_outgoing_bytes == b->max_outgoing_bytes
3156      || a->max_outgoing_unix_fds == b->max_outgoing_unix_fds
3157      || a->max_message_size == b->max_message_size
3158      || a->max_message_unix_fds == b->max_message_unix_fds
3159      || a->activation_timeout == b->activation_timeout
3160      || a->auth_timeout == b->auth_timeout
3161      || a->pending_fd_timeout == b->pending_fd_timeout
3162      || a->max_completed_connections == b->max_completed_connections
3163      || a->max_incomplete_connections == b->max_incomplete_connections
3164      || a->max_connections_per_user == b->max_connections_per_user
3165      || a->max_pending_activations == b->max_pending_activations
3166      || a->max_services_per_connection == b->max_services_per_connection
3167      || a->max_match_rules_per_connection == b->max_match_rules_per_connection
3168      || a->max_replies_per_connection == b->max_replies_per_connection
3169      || a->reply_timeout == b->reply_timeout);
3170 }
3171
3172 static dbus_bool_t
3173 config_parsers_equal (const BusConfigParser *a,
3174                       const BusConfigParser *b)
3175 {
3176   if (!_dbus_string_equal (&a->basedir, &b->basedir))
3177     return FALSE;
3178
3179   if (!lists_of_elements_equal (a->stack, b->stack))
3180     return FALSE;
3181
3182   if (!strings_equal_or_both_null (a->user, b->user))
3183     return FALSE;
3184
3185   if (!lists_of_c_strings_equal (a->listen_on, b->listen_on))
3186     return FALSE;
3187
3188   if (!lists_of_c_strings_equal (a->mechanisms, b->mechanisms))
3189     return FALSE;
3190
3191   if (!lists_of_c_strings_equal (a->service_dirs, b->service_dirs))
3192     return FALSE;
3193   
3194   /* FIXME: compare policy */
3195
3196   /* FIXME: compare service selinux ID table */
3197
3198   if (! limits_equal (&a->limits, &b->limits))
3199     return FALSE;
3200
3201   if (!strings_equal_or_both_null (a->pidfile, b->pidfile))
3202     return FALSE;
3203
3204   if (! bools_equal (a->fork, b->fork))
3205     return FALSE;
3206
3207   if (! bools_equal (a->keep_umask, b->keep_umask))
3208     return FALSE;
3209
3210   if (! bools_equal (a->is_toplevel, b->is_toplevel))
3211     return FALSE;
3212
3213   return TRUE;
3214 }
3215
3216 static dbus_bool_t
3217 all_are_equiv (const DBusString *target_directory)
3218 {
3219   DBusString filename;
3220   DBusDirIter *dir;
3221   BusConfigParser *first_parser;
3222   BusConfigParser *parser;
3223   DBusError error;
3224   dbus_bool_t equal;
3225   dbus_bool_t retval;
3226
3227   dir = NULL;
3228   first_parser = NULL;
3229   parser = NULL;
3230   retval = FALSE;
3231
3232   if (!_dbus_string_init (&filename))
3233     _dbus_assert_not_reached ("didn't allocate filename string");
3234
3235   dbus_error_init (&error);
3236   dir = _dbus_directory_open (target_directory, &error);
3237   if (dir == NULL)
3238     {
3239       _dbus_warn ("Could not open %s: %s",
3240                   _dbus_string_get_const_data (target_directory),
3241                   error.message);
3242       dbus_error_free (&error);
3243       goto finished;
3244     }
3245
3246   printf ("Comparing equivalent files:\n");
3247
3248  next:
3249   while (_dbus_directory_get_next_file (dir, &filename, &error))
3250     {
3251       DBusString full_path;
3252
3253       if (!_dbus_string_init (&full_path))
3254         _dbus_assert_not_reached ("couldn't init string");
3255
3256       if (!_dbus_string_copy (target_directory, 0, &full_path, 0))
3257         _dbus_assert_not_reached ("couldn't copy dir to full_path");
3258
3259       if (!_dbus_concat_dir_and_file (&full_path, &filename))
3260         _dbus_assert_not_reached ("couldn't concat file to dir");
3261
3262       if (!_dbus_string_ends_with_c_str (&full_path, ".conf"))
3263         {
3264           _dbus_verbose ("Skipping non-.conf file %s\n",
3265                          _dbus_string_get_const_data (&filename));
3266           _dbus_string_free (&full_path);
3267           goto next;
3268         }
3269
3270       printf ("    %s\n", _dbus_string_get_const_data (&filename));
3271
3272       parser = bus_config_load (&full_path, TRUE, NULL, &error);
3273
3274       if (parser == NULL)
3275         {
3276           _dbus_warn ("Could not load file %s: %s",
3277                       _dbus_string_get_const_data (&full_path),
3278                       error.message);
3279           _dbus_string_free (&full_path);
3280           dbus_error_free (&error);
3281           goto finished;
3282         }
3283       else if (first_parser == NULL)
3284         {
3285           _dbus_string_free (&full_path);
3286           first_parser = parser;
3287         }
3288       else
3289         {
3290           _dbus_string_free (&full_path);
3291           equal = config_parsers_equal (first_parser, parser);
3292           bus_config_parser_unref (parser);
3293           if (! equal)
3294             goto finished;
3295         }
3296     }
3297
3298   retval = TRUE;
3299
3300  finished:
3301   _dbus_string_free (&filename);
3302   if (first_parser)
3303     bus_config_parser_unref (first_parser);
3304   if (dir)
3305     _dbus_directory_close (dir);
3306
3307   return retval;
3308   
3309 }
3310
3311 static dbus_bool_t
3312 process_test_equiv_subdir (const DBusString *test_base_dir,
3313                            const char       *subdir)
3314 {
3315   DBusString test_directory;
3316   DBusString filename;
3317   DBusDirIter *dir;
3318   DBusError error;
3319   dbus_bool_t equal;
3320   dbus_bool_t retval;
3321
3322   dir = NULL;
3323   retval = FALSE;
3324
3325   if (!_dbus_string_init (&test_directory))
3326     _dbus_assert_not_reached ("didn't allocate test_directory");
3327
3328   _dbus_string_init_const (&filename, subdir);
3329
3330   if (!_dbus_string_copy (test_base_dir, 0,
3331                           &test_directory, 0))
3332     _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
3333
3334   if (!_dbus_concat_dir_and_file (&test_directory, &filename))
3335     _dbus_assert_not_reached ("couldn't allocate full path");
3336
3337   _dbus_string_free (&filename);
3338   if (!_dbus_string_init (&filename))
3339     _dbus_assert_not_reached ("didn't allocate filename string");
3340
3341   dbus_error_init (&error);
3342   dir = _dbus_directory_open (&test_directory, &error);
3343   if (dir == NULL)
3344     {
3345       _dbus_warn ("Could not open %s: %s",
3346                   _dbus_string_get_const_data (&test_directory),
3347                   error.message);
3348       dbus_error_free (&error);
3349       goto finished;
3350     }
3351
3352   while (_dbus_directory_get_next_file (dir, &filename, &error))
3353     {
3354       DBusString full_path;
3355
3356       /* Skip CVS's magic directories! */
3357       if (_dbus_string_equal_c_str (&filename, "CVS"))
3358         continue;
3359
3360       if (!_dbus_string_init (&full_path))
3361         _dbus_assert_not_reached ("couldn't init string");
3362
3363       if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
3364         _dbus_assert_not_reached ("couldn't copy dir to full_path");
3365
3366       if (!_dbus_concat_dir_and_file (&full_path, &filename))
3367         _dbus_assert_not_reached ("couldn't concat file to dir");
3368       
3369       equal = all_are_equiv (&full_path);
3370       _dbus_string_free (&full_path);
3371
3372       if (!equal)
3373         goto finished;
3374     }
3375
3376   retval = TRUE;
3377
3378  finished:
3379   _dbus_string_free (&test_directory);
3380   _dbus_string_free (&filename);
3381   if (dir)
3382     _dbus_directory_close (dir);
3383
3384   return retval;
3385   
3386 }
3387
3388 static const char *test_session_service_dir_matches[] = 
3389         {
3390 #ifdef DBUS_UNIX
3391          "/testhome/foo/.testlocal/testshare/dbus-1/services",
3392          "/testusr/testlocal/testshare/dbus-1/services",
3393          "/testusr/testshare/dbus-1/services",
3394          DBUS_DATADIR"/dbus-1/services",
3395 #endif
3396 /* will be filled in test_default_session_servicedirs() */
3397 #ifdef DBUS_WIN
3398          NULL,
3399          NULL,
3400 #endif
3401          NULL
3402         };
3403
3404 static dbus_bool_t
3405 test_default_session_servicedirs (void)
3406 {
3407   DBusList *dirs;
3408   DBusList *link;
3409   DBusString progs;
3410   DBusString install_root_based;
3411   int i;
3412   dbus_bool_t ret = FALSE;
3413 #ifdef DBUS_WIN
3414   const char *common_progs;
3415 #endif
3416
3417   /* On Unix we don't actually use these, but it's easier to handle the
3418    * deallocation if we always allocate them, whether needed or not */
3419   if (!_dbus_string_init (&progs) ||
3420       !_dbus_string_init (&install_root_based))
3421     _dbus_assert_not_reached ("OOM allocating strings");
3422
3423 #ifdef DBUS_WIN
3424   if (!_dbus_string_append (&install_root_based, DBUS_DATADIR) ||
3425       !_dbus_string_append (&install_root_based, "/dbus-1/services") ||
3426       !_dbus_replace_install_prefix (&install_root_based))
3427     goto out;
3428
3429   _dbus_assert (_dbus_path_is_absolute (&install_root_based));
3430
3431   test_session_service_dir_matches[0] = _dbus_string_get_const_data (
3432       &install_root_based);
3433
3434   common_progs = _dbus_getenv ("CommonProgramFiles");
3435
3436   if (common_progs) 
3437     {
3438       if (!_dbus_string_append (&progs, common_progs)) 
3439         goto out;
3440
3441       if (!_dbus_string_append (&progs, "/dbus-1/services")) 
3442         goto out;
3443
3444       test_session_service_dir_matches[1] = _dbus_string_get_const_data(&progs);
3445     }
3446 #endif
3447   dirs = NULL;
3448
3449   printf ("Testing retrieving the default session service directories\n");
3450   if (!_dbus_get_standard_session_servicedirs (&dirs))
3451     _dbus_assert_not_reached ("couldn't get stardard dirs");
3452
3453   /* make sure our defaults end with share/dbus-1/service */
3454   while ((link = _dbus_list_pop_first_link (&dirs)))
3455     {
3456       DBusString path;
3457       
3458       printf ("    default service dir: %s\n", (char *)link->data);
3459       _dbus_string_init_const (&path, (char *)link->data);
3460       if (!_dbus_string_ends_with_c_str (&path, "dbus-1/services"))
3461         {
3462           printf ("error with default session service directories\n");
3463               dbus_free (link->data);
3464           _dbus_list_free_link (link);
3465           goto out;
3466         }
3467  
3468       dbus_free (link->data);
3469       _dbus_list_free_link (link);
3470     }
3471
3472 #ifdef DBUS_UNIX
3473   if (!dbus_setenv ("XDG_DATA_HOME", "/testhome/foo/.testlocal/testshare"))
3474     _dbus_assert_not_reached ("couldn't setenv XDG_DATA_HOME");
3475
3476   if (!dbus_setenv ("XDG_DATA_DIRS", ":/testusr/testlocal/testshare: :/testusr/testshare:"))
3477     _dbus_assert_not_reached ("couldn't setenv XDG_DATA_DIRS");
3478 #endif
3479   if (!_dbus_get_standard_session_servicedirs (&dirs))
3480     _dbus_assert_not_reached ("couldn't get stardard dirs");
3481
3482   /* make sure we read and parse the env variable correctly */
3483   i = 0;
3484   while ((link = _dbus_list_pop_first_link (&dirs)))
3485     {
3486       printf ("    test service dir: '%s'\n", (char *)link->data);
3487       printf ("    current standard service dir: '%s'\n", test_session_service_dir_matches[i]);
3488       if (test_session_service_dir_matches[i] == NULL)
3489         {
3490           printf ("more directories parsed than in match set\n");
3491           dbus_free (link->data);
3492           _dbus_list_free_link (link);
3493           goto out;
3494         }
3495  
3496       if (strcmp (test_session_service_dir_matches[i], 
3497                   (char *)link->data) != 0)
3498         {
3499           printf ("'%s' directory does not match '%s' in the match set\n",
3500                   (char *)link->data,
3501                   test_session_service_dir_matches[i]);
3502           dbus_free (link->data);
3503           _dbus_list_free_link (link);
3504           goto out;
3505         }
3506
3507       ++i;
3508
3509       dbus_free (link->data);
3510       _dbus_list_free_link (link);
3511     }
3512   
3513   if (test_session_service_dir_matches[i] != NULL)
3514     {
3515       printf ("extra data %s in the match set was not matched\n",
3516               test_session_service_dir_matches[i]);
3517       goto out;
3518     }
3519
3520   ret = TRUE;
3521
3522 out:
3523   _dbus_string_free (&install_root_based);
3524   _dbus_string_free (&progs);
3525   return ret;
3526 }
3527
3528 #ifndef DBUS_WIN
3529 static const char *test_system_service_dir_matches[] = 
3530         {
3531          "/usr/local/share/dbus-1/system-services",
3532          "/usr/share/dbus-1/system-services",
3533          DBUS_DATADIR"/dbus-1/system-services",
3534          "/lib/dbus-1/system-services",
3535          NULL
3536         };
3537
3538 static dbus_bool_t
3539 test_default_system_servicedirs (void)
3540 {
3541   DBusList *dirs;
3542   DBusList *link;
3543   DBusString progs;
3544   int i;
3545
3546   /* On Unix we don't actually use this variable, but it's easier to handle the
3547    * deallocation if we always allocate it, whether needed or not */
3548   if (!_dbus_string_init (&progs))
3549     _dbus_assert_not_reached ("OOM allocating progs");
3550
3551   dirs = NULL;
3552
3553   printf ("Testing retrieving the default system service directories\n");
3554   if (!_dbus_get_standard_system_servicedirs (&dirs))
3555     _dbus_assert_not_reached ("couldn't get stardard dirs");
3556
3557   /* make sure our defaults end with share/dbus-1/system-service */
3558   while ((link = _dbus_list_pop_first_link (&dirs)))
3559     {
3560       DBusString path;
3561       
3562       printf ("    default service dir: %s\n", (char *)link->data);
3563       _dbus_string_init_const (&path, (char *)link->data);
3564       if (!_dbus_string_ends_with_c_str (&path, "dbus-1/system-services"))
3565         {
3566           printf ("error with default system service directories\n");
3567               dbus_free (link->data);
3568           _dbus_list_free_link (link);
3569           _dbus_string_free (&progs);
3570           return FALSE;
3571         }
3572  
3573       dbus_free (link->data);
3574       _dbus_list_free_link (link);
3575     }
3576
3577   if (!dbus_setenv ("XDG_DATA_HOME", "/testhome/foo/.testlocal/testshare"))
3578     _dbus_assert_not_reached ("couldn't setenv XDG_DATA_HOME");
3579
3580   if (!dbus_setenv ("XDG_DATA_DIRS", ":/testusr/testlocal/testshare: :/testusr/testshare:"))
3581     _dbus_assert_not_reached ("couldn't setenv XDG_DATA_DIRS");
3582
3583   if (!_dbus_get_standard_system_servicedirs (&dirs))
3584     _dbus_assert_not_reached ("couldn't get stardard dirs");
3585
3586   /* make sure we read and parse the env variable correctly */
3587   i = 0;
3588   while ((link = _dbus_list_pop_first_link (&dirs)))
3589     {
3590       printf ("    test service dir: %s\n", (char *)link->data);
3591       if (test_system_service_dir_matches[i] == NULL)
3592         {
3593           printf ("more directories parsed than in match set\n");
3594           dbus_free (link->data);
3595           _dbus_list_free_link (link);
3596           _dbus_string_free (&progs);
3597           return FALSE;
3598         }
3599  
3600       if (strcmp (test_system_service_dir_matches[i], 
3601                   (char *)link->data) != 0)
3602         {
3603           printf ("%s directory does not match %s in the match set\n", 
3604                   (char *)link->data,
3605                   test_system_service_dir_matches[i]);
3606           dbus_free (link->data);
3607           _dbus_list_free_link (link);
3608           _dbus_string_free (&progs);
3609           return FALSE;
3610         }
3611
3612       ++i;
3613
3614       dbus_free (link->data);
3615       _dbus_list_free_link (link);
3616     }
3617   
3618   if (test_system_service_dir_matches[i] != NULL)
3619     {
3620       printf ("extra data %s in the match set was not matched\n",
3621               test_system_service_dir_matches[i]);
3622
3623       _dbus_string_free (&progs);
3624       return FALSE;
3625     }
3626     
3627   _dbus_string_free (&progs);
3628   return TRUE;
3629 }
3630 #endif
3631                    
3632 dbus_bool_t
3633 bus_config_parser_test (const DBusString *test_data_dir)
3634 {
3635   if (test_data_dir == NULL ||
3636       _dbus_string_get_length (test_data_dir) == 0)
3637     {
3638       printf ("No test data\n");
3639       return TRUE;
3640     }
3641
3642   if (!test_default_session_servicedirs())
3643     return FALSE;
3644
3645 #ifdef DBUS_WIN
3646   printf("default system service dir skipped\n");
3647 #else
3648   if (!test_default_system_servicedirs())
3649     return FALSE;
3650 #endif
3651
3652   if (!process_test_valid_subdir (test_data_dir, "valid-config-files", VALID))
3653     return FALSE;
3654
3655 #ifndef DBUS_WIN
3656   if (!process_test_valid_subdir (test_data_dir, "valid-config-files-system", VALID))
3657     return FALSE;
3658 #endif
3659
3660   if (!process_test_valid_subdir (test_data_dir, "invalid-config-files", INVALID))
3661     return FALSE;
3662
3663   if (!process_test_equiv_subdir (test_data_dir, "equiv-config-files"))
3664     return FALSE;
3665
3666   return TRUE;
3667 }
3668
3669 #endif /* DBUS_ENABLE_EMBEDDED_TESTS */
3670