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\n",
1053                         user);
1054         }
1055       else if (group != NULL)
1056         {
1057           DBusString group_name;
1058           _dbus_string_init_const (&group_name, group);
1059
1060           if (_dbus_parse_unix_group_from_config (&group_name,
1061                                                   &e->d.policy.gid_uid_or_at_console))
1062             e->d.policy.type = POLICY_GROUP;
1063           else
1064             _dbus_warn ("Unknown group \"%s\" in message bus configuration file\n",
1065                         group);          
1066         }
1067       else if (at_console != NULL)
1068         {
1069            dbus_bool_t t;
1070            t = (strcmp (at_console, "true") == 0);
1071            if (t || strcmp (at_console, "false") == 0)
1072              {
1073                e->d.policy.gid_uid_or_at_console = t; 
1074                e->d.policy.type = POLICY_CONSOLE;
1075              }  
1076            else
1077              {
1078                dbus_set_error (error, DBUS_ERROR_FAILED,
1079                               "Unknown value \"%s\" for at_console in message bus configuration file",
1080                               at_console);
1081
1082                return FALSE;
1083              }
1084         }
1085       else
1086         {
1087           _dbus_assert_not_reached ("all <policy> attributes null and we didn't set error");
1088         }
1089       
1090       return TRUE;
1091     }
1092   else if (element_type == ELEMENT_LIMIT)
1093     {
1094       Element *e;
1095       const char *name;
1096
1097       if ((e = push_element (parser, ELEMENT_LIMIT)) == NULL)
1098         {
1099           BUS_SET_OOM (error);
1100           return FALSE;
1101         }
1102       
1103       if (!locate_attributes (parser, "limit",
1104                               attribute_names,
1105                               attribute_values,
1106                               error,
1107                               "name", &name,
1108                               NULL))
1109         return FALSE;
1110
1111       if (name == NULL)
1112         {
1113           dbus_set_error (error, DBUS_ERROR_FAILED,
1114                           "<limit> element must have a \"name\" attribute");
1115           return FALSE;
1116         }
1117
1118       e->d.limit.name = _dbus_strdup (name);
1119       if (e->d.limit.name == NULL)
1120         {
1121           BUS_SET_OOM (error);
1122           return FALSE;
1123         }
1124
1125       return TRUE;
1126     }
1127   else if (element_type == ELEMENT_SELINUX)
1128     {
1129       if (!check_no_attributes (parser, "selinux", attribute_names, attribute_values, error))
1130         return FALSE;
1131
1132       if (push_element (parser, ELEMENT_SELINUX) == NULL)
1133         {
1134           BUS_SET_OOM (error);
1135           return FALSE;
1136         }
1137
1138       return TRUE;
1139     }
1140   else if (element_type == ELEMENT_APPARMOR)
1141     {
1142       Element *e;
1143       const char *mode;
1144
1145       if ((e = push_element (parser, ELEMENT_APPARMOR)) == NULL)
1146         {
1147           BUS_SET_OOM (error);
1148           return FALSE;
1149         }
1150
1151       if (!locate_attributes (parser, "apparmor",
1152                               attribute_names,
1153                               attribute_values,
1154                               error,
1155                               "mode", &mode,
1156                               NULL))
1157         return FALSE;
1158
1159       return bus_apparmor_set_mode_from_config (mode, error);
1160     }
1161   else
1162     {
1163       dbus_set_error (error, DBUS_ERROR_FAILED,
1164                       "Element <%s> not allowed inside <%s> in configuration file",
1165                       element_name, "busconfig");
1166       return FALSE;
1167     }
1168 }
1169
1170 static dbus_bool_t
1171 append_rule_from_element (BusConfigParser   *parser,
1172                           const char        *element_name,
1173                           const char       **attribute_names,
1174                           const char       **attribute_values,
1175                           dbus_bool_t        allow,
1176                           DBusError         *error)
1177 {
1178   const char *log;
1179   const char *send_interface;
1180   const char *send_member;
1181   const char *send_error;
1182   const char *send_destination;
1183   const char *send_path;
1184   const char *send_type;
1185   const char *receive_interface;
1186   const char *receive_member;
1187   const char *receive_error;
1188   const char *receive_sender;
1189   const char *receive_path;
1190   const char *receive_type;
1191   const char *eavesdrop;
1192   const char *send_requested_reply;
1193   const char *receive_requested_reply;
1194   const char *own;
1195   const char *own_prefix;
1196   const char *user;
1197   const char *group;
1198
1199   BusPolicyRule *rule;
1200   
1201   if (!locate_attributes (parser, element_name,
1202                           attribute_names,
1203                           attribute_values,
1204                           error,
1205                           "send_interface", &send_interface,
1206                           "send_member", &send_member,
1207                           "send_error", &send_error,
1208                           "send_destination", &send_destination,
1209                           "send_path", &send_path,
1210                           "send_type", &send_type,
1211                           "receive_interface", &receive_interface,
1212                           "receive_member", &receive_member,
1213                           "receive_error", &receive_error,
1214                           "receive_sender", &receive_sender,
1215                           "receive_path", &receive_path,
1216                           "receive_type", &receive_type,
1217                           "eavesdrop", &eavesdrop,
1218                           "send_requested_reply", &send_requested_reply,
1219                           "receive_requested_reply", &receive_requested_reply,
1220                           "own", &own,
1221                           "own_prefix", &own_prefix,
1222                           "user", &user,
1223                           "group", &group,
1224                           "log", &log,
1225                           NULL))
1226     return FALSE;
1227
1228   if (!(send_interface || send_member || send_error || send_destination ||
1229         send_type || send_path ||
1230         receive_interface || receive_member || receive_error || receive_sender ||
1231         receive_type || receive_path || eavesdrop ||
1232         send_requested_reply || receive_requested_reply ||
1233         own || own_prefix || user || group))
1234     {
1235       dbus_set_error (error, DBUS_ERROR_FAILED,
1236                       "Element <%s> must have one or more attributes",
1237                       element_name);
1238       return FALSE;
1239     }
1240
1241   if ((send_member && (send_interface == NULL && send_path == NULL)) ||
1242       (receive_member && (receive_interface == NULL && receive_path == NULL)))
1243     {
1244       dbus_set_error (error, DBUS_ERROR_FAILED,
1245                       "On element <%s>, if you specify a member you must specify an interface or a path. Keep in mind that not all messages have an interface field.",
1246                       element_name);
1247       return FALSE;
1248     }
1249   
1250   /* Allowed combinations of elements are:
1251    *
1252    *   base, must be all send or all receive:
1253    *     nothing
1254    *     interface
1255    *     interface + member
1256    *     error
1257    * 
1258    *   base send_ can combine with send_destination, send_path, send_type, send_requested_reply
1259    *   base receive_ with receive_sender, receive_path, receive_type, receive_requested_reply, eavesdrop
1260    *
1261    *   user, group, own, own_prefix must occur alone
1262    *
1263    * Pretty sure the below stuff is broken, FIXME think about it more.
1264    */
1265
1266   if ((send_interface && (send_error ||
1267                           receive_interface ||
1268                           receive_member ||
1269                           receive_error ||
1270                           receive_sender ||
1271                           receive_requested_reply ||
1272                           own || own_prefix ||
1273                           user ||
1274                           group)) ||
1275
1276       (send_member && (send_error ||
1277                        receive_interface ||
1278                        receive_member ||
1279                        receive_error ||
1280                        receive_sender ||
1281                        receive_requested_reply ||
1282                        own || own_prefix ||
1283                        user ||
1284                        group)) ||
1285
1286       (send_error && (receive_interface ||
1287                       receive_member ||
1288                       receive_error ||
1289                       receive_sender ||
1290                       receive_requested_reply ||
1291                       own || own_prefix ||
1292                       user ||
1293                       group)) ||
1294
1295       (send_destination && (receive_interface ||
1296                             receive_member ||
1297                             receive_error ||
1298                             receive_sender ||
1299                             receive_requested_reply ||
1300                             own || own_prefix ||
1301                             user ||
1302                             group)) ||
1303
1304       (send_type && (receive_interface ||
1305                      receive_member ||
1306                      receive_error ||
1307                      receive_sender ||
1308                      receive_requested_reply ||
1309                      own || own_prefix ||
1310                      user ||
1311                      group)) ||
1312
1313       (send_path && (receive_interface ||
1314                      receive_member ||
1315                      receive_error ||
1316                      receive_sender ||
1317                      receive_requested_reply ||
1318                      own || own_prefix ||
1319                      user ||
1320                      group)) ||
1321
1322       (send_requested_reply && (receive_interface ||
1323                                 receive_member ||
1324                                 receive_error ||
1325                                 receive_sender ||
1326                                 receive_requested_reply ||
1327                                 own || own_prefix ||
1328                                 user ||
1329                                 group)) ||
1330
1331       (receive_interface && (receive_error ||
1332                              own || own_prefix ||
1333                              user ||
1334                              group)) ||
1335
1336       (receive_member && (receive_error ||
1337                           own || own_prefix ||
1338                           user ||
1339                           group)) ||
1340
1341       (receive_error && (own || own_prefix ||
1342                          user ||
1343                          group)) ||
1344
1345       (eavesdrop && (own || own_prefix ||
1346                      user ||
1347                      group)) ||
1348
1349       (receive_requested_reply && (own || own_prefix ||
1350                                    user ||
1351                                    group)) ||
1352
1353       (own && (own_prefix || user || group)) ||
1354
1355       (own_prefix && (own || user || group)) ||
1356
1357       (user && group))
1358     {
1359       dbus_set_error (error, DBUS_ERROR_FAILED,
1360                       "Invalid combination of attributes on element <%s>",
1361                       element_name);
1362       return FALSE;
1363     }
1364   
1365   rule = NULL;
1366
1367   /* In BusPolicyRule, NULL represents wildcard.
1368    * In the config file, '*' represents it.
1369    */
1370 #define IS_WILDCARD(str) ((str) && ((str)[0]) == '*' && ((str)[1]) == '\0')
1371
1372   if (send_interface || send_member || send_error || send_destination ||
1373       send_path || send_type || send_requested_reply)
1374     {
1375       int message_type;
1376       
1377       if (IS_WILDCARD (send_interface))
1378         send_interface = NULL;
1379       if (IS_WILDCARD (send_member))
1380         send_member = NULL;
1381       if (IS_WILDCARD (send_error))
1382         send_error = NULL;
1383       if (IS_WILDCARD (send_destination))
1384         send_destination = NULL;
1385       if (IS_WILDCARD (send_path))
1386         send_path = NULL;
1387       if (IS_WILDCARD (send_type))
1388         send_type = NULL;
1389
1390       message_type = DBUS_MESSAGE_TYPE_INVALID;
1391       if (send_type != NULL)
1392         {
1393           message_type = dbus_message_type_from_string (send_type);
1394           if (message_type == DBUS_MESSAGE_TYPE_INVALID)
1395             {
1396               dbus_set_error (error, DBUS_ERROR_FAILED,
1397                               "Bad message type \"%s\"",
1398                               send_type);
1399               return FALSE;
1400             }
1401         }
1402
1403       if (eavesdrop &&
1404           !(strcmp (eavesdrop, "true") == 0 ||
1405             strcmp (eavesdrop, "false") == 0))
1406         {
1407           dbus_set_error (error, DBUS_ERROR_FAILED,
1408                           "Bad value \"%s\" for %s attribute, must be true or false",
1409                           "eavesdrop", eavesdrop);
1410           return FALSE;
1411         }
1412
1413       if (send_requested_reply &&
1414           !(strcmp (send_requested_reply, "true") == 0 ||
1415             strcmp (send_requested_reply, "false") == 0))
1416         {
1417           dbus_set_error (error, DBUS_ERROR_FAILED,
1418                           "Bad value \"%s\" for %s attribute, must be true or false",
1419                           "send_requested_reply", send_requested_reply);
1420           return FALSE;
1421         }
1422       
1423       rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow); 
1424       if (rule == NULL)
1425         goto nomem;
1426       
1427       if (eavesdrop)
1428         rule->d.send.eavesdrop = (strcmp (eavesdrop, "true") == 0);
1429
1430       if (log)
1431         rule->d.send.log = (strcmp (log, "true") == 0);
1432
1433       if (send_requested_reply)
1434         rule->d.send.requested_reply = (strcmp (send_requested_reply, "true") == 0);
1435
1436       rule->d.send.message_type = message_type;
1437       rule->d.send.path = _dbus_strdup (send_path);
1438       rule->d.send.interface = _dbus_strdup (send_interface);
1439       rule->d.send.member = _dbus_strdup (send_member);
1440       rule->d.send.error = _dbus_strdup (send_error);
1441       rule->d.send.destination = _dbus_strdup (send_destination);
1442       if (send_path && rule->d.send.path == NULL)
1443         goto nomem;
1444       if (send_interface && rule->d.send.interface == NULL)
1445         goto nomem;
1446       if (send_member && rule->d.send.member == NULL)
1447         goto nomem;
1448       if (send_error && rule->d.send.error == NULL)
1449         goto nomem;
1450       if (send_destination && rule->d.send.destination == NULL)
1451         goto nomem;
1452     }
1453   else if (receive_interface || receive_member || receive_error || receive_sender ||
1454            receive_path || receive_type || eavesdrop || receive_requested_reply)
1455     {
1456       int message_type;
1457       
1458       if (IS_WILDCARD (receive_interface))
1459         receive_interface = NULL;
1460       if (IS_WILDCARD (receive_member))
1461         receive_member = NULL;
1462       if (IS_WILDCARD (receive_error))
1463         receive_error = NULL;
1464       if (IS_WILDCARD (receive_sender))
1465         receive_sender = NULL;
1466       if (IS_WILDCARD (receive_path))
1467         receive_path = NULL;
1468       if (IS_WILDCARD (receive_type))
1469         receive_type = NULL;
1470
1471       message_type = DBUS_MESSAGE_TYPE_INVALID;
1472       if (receive_type != NULL)
1473         {
1474           message_type = dbus_message_type_from_string (receive_type);
1475           if (message_type == DBUS_MESSAGE_TYPE_INVALID)
1476             {
1477               dbus_set_error (error, DBUS_ERROR_FAILED,
1478                               "Bad message type \"%s\"",
1479                               receive_type);
1480               return FALSE;
1481             }
1482         }
1483
1484
1485       if (eavesdrop &&
1486           !(strcmp (eavesdrop, "true") == 0 ||
1487             strcmp (eavesdrop, "false") == 0))
1488         {
1489           dbus_set_error (error, DBUS_ERROR_FAILED,
1490                           "Bad value \"%s\" for %s attribute, must be true or false",
1491                           "eavesdrop", eavesdrop);
1492           return FALSE;
1493         }
1494
1495       if (receive_requested_reply &&
1496           !(strcmp (receive_requested_reply, "true") == 0 ||
1497             strcmp (receive_requested_reply, "false") == 0))
1498         {
1499           dbus_set_error (error, DBUS_ERROR_FAILED,
1500                           "Bad value \"%s\" for %s attribute, must be true or false",
1501                           "receive_requested_reply", receive_requested_reply);
1502           return FALSE;
1503         }
1504       
1505       rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow); 
1506       if (rule == NULL)
1507         goto nomem;
1508
1509       if (eavesdrop)
1510         rule->d.receive.eavesdrop = (strcmp (eavesdrop, "true") == 0);
1511
1512       if (receive_requested_reply)
1513         rule->d.receive.requested_reply = (strcmp (receive_requested_reply, "true") == 0);
1514       
1515       rule->d.receive.message_type = message_type;
1516       rule->d.receive.path = _dbus_strdup (receive_path);
1517       rule->d.receive.interface = _dbus_strdup (receive_interface);
1518       rule->d.receive.member = _dbus_strdup (receive_member);
1519       rule->d.receive.error = _dbus_strdup (receive_error);
1520       rule->d.receive.origin = _dbus_strdup (receive_sender);
1521
1522       if (receive_path && rule->d.receive.path == NULL)
1523         goto nomem;
1524       if (receive_interface && rule->d.receive.interface == NULL)
1525         goto nomem;
1526       if (receive_member && rule->d.receive.member == NULL)
1527         goto nomem;
1528       if (receive_error && rule->d.receive.error == NULL)
1529         goto nomem;
1530       if (receive_sender && rule->d.receive.origin == NULL)
1531         goto nomem;
1532     }
1533   else if (own || own_prefix)
1534     {
1535       rule = bus_policy_rule_new (BUS_POLICY_RULE_OWN, allow); 
1536       if (rule == NULL)
1537         goto nomem;
1538
1539       if (own)
1540         {
1541           if (IS_WILDCARD (own))
1542             own = NULL;
1543       
1544           rule->d.own.prefix = 0;
1545           rule->d.own.service_name = _dbus_strdup (own);
1546           if (own && rule->d.own.service_name == NULL)
1547             goto nomem;
1548         }
1549       else
1550         {
1551           rule->d.own.prefix = 1;
1552           rule->d.own.service_name = _dbus_strdup (own_prefix);
1553           if (rule->d.own.service_name == NULL)
1554             goto nomem;
1555         }
1556     }
1557   else if (user)
1558     {      
1559       if (IS_WILDCARD (user))
1560         {
1561           rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow); 
1562           if (rule == NULL)
1563             goto nomem;
1564
1565           rule->d.user.uid = DBUS_UID_UNSET;
1566         }
1567       else
1568         {
1569           DBusString username;
1570           dbus_uid_t uid;
1571           
1572           _dbus_string_init_const (&username, user);
1573       
1574           if (_dbus_parse_unix_user_from_config (&username, &uid))
1575             {
1576               rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow); 
1577               if (rule == NULL)
1578                 goto nomem;
1579
1580               rule->d.user.uid = uid;
1581             }
1582           else
1583             {
1584               _dbus_warn ("Unknown username \"%s\" on element <%s>\n",
1585                           user, element_name);
1586             }
1587         }
1588     }
1589   else if (group)
1590     {
1591       if (IS_WILDCARD (group))
1592         {
1593           rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow); 
1594           if (rule == NULL)
1595             goto nomem;
1596
1597           rule->d.group.gid = DBUS_GID_UNSET;
1598         }
1599       else
1600         {
1601           DBusString groupname;
1602           dbus_gid_t gid;
1603           
1604           _dbus_string_init_const (&groupname, group);
1605           
1606           if (_dbus_parse_unix_group_from_config (&groupname, &gid))
1607             {
1608               rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow); 
1609               if (rule == NULL)
1610                 goto nomem;
1611
1612               rule->d.group.gid = gid;
1613             }
1614           else
1615             {
1616               _dbus_warn ("Unknown group \"%s\" on element <%s>\n",
1617                           group, element_name);
1618             }
1619         }
1620     }
1621   else
1622     _dbus_assert_not_reached ("Did not handle some combination of attributes on <allow> or <deny>");
1623
1624   if (rule != NULL)
1625     {
1626       Element *pe;
1627       
1628       pe = peek_element (parser);      
1629       _dbus_assert (pe != NULL);
1630       _dbus_assert (pe->type == ELEMENT_POLICY);
1631
1632       switch (pe->d.policy.type)
1633         {
1634         case POLICY_IGNORED:
1635           /* drop the rule on the floor */
1636           break;
1637           
1638         case POLICY_DEFAULT:
1639           if (!bus_policy_append_default_rule (parser->policy, rule))
1640             goto nomem;
1641           break;
1642         case POLICY_MANDATORY:
1643           if (!bus_policy_append_mandatory_rule (parser->policy, rule))
1644             goto nomem;
1645           break;
1646         case POLICY_USER:
1647           if (!BUS_POLICY_RULE_IS_PER_CLIENT (rule))
1648             {
1649               dbus_set_error (error, DBUS_ERROR_FAILED,
1650                               "<%s> rule cannot be per-user because it has bus-global semantics",
1651                               element_name);
1652               goto failed;
1653             }
1654           
1655           if (!bus_policy_append_user_rule (parser->policy, pe->d.policy.gid_uid_or_at_console,
1656                                             rule))
1657             goto nomem;
1658           break;
1659         case POLICY_GROUP:
1660           if (!BUS_POLICY_RULE_IS_PER_CLIENT (rule))
1661             {
1662               dbus_set_error (error, DBUS_ERROR_FAILED,
1663                               "<%s> rule cannot be per-group because it has bus-global semantics",
1664                               element_name);
1665               goto failed;
1666             }
1667           
1668           if (!bus_policy_append_group_rule (parser->policy, pe->d.policy.gid_uid_or_at_console,
1669                                              rule))
1670             goto nomem;
1671           break;
1672         
1673
1674         case POLICY_CONSOLE:
1675           if (!bus_policy_append_console_rule (parser->policy, pe->d.policy.gid_uid_or_at_console,
1676                                                rule))
1677             goto nomem;
1678           break;
1679         }
1680  
1681       bus_policy_rule_unref (rule);
1682       rule = NULL;
1683     }
1684   
1685   return TRUE;
1686
1687  nomem:
1688   BUS_SET_OOM (error);
1689  failed:
1690   if (rule)
1691     bus_policy_rule_unref (rule);
1692   return FALSE;
1693 }
1694
1695 static dbus_bool_t
1696 start_policy_child (BusConfigParser   *parser,
1697                     const char        *element_name,
1698                     const char       **attribute_names,
1699                     const char       **attribute_values,
1700                     DBusError         *error)
1701 {
1702   if (strcmp (element_name, "allow") == 0)
1703     {
1704       if (!append_rule_from_element (parser, element_name,
1705                                      attribute_names, attribute_values,
1706                                      TRUE, error))
1707         return FALSE;
1708       
1709       if (push_element (parser, ELEMENT_ALLOW) == NULL)
1710         {
1711           BUS_SET_OOM (error);
1712           return FALSE;
1713         }
1714       
1715       return TRUE;
1716     }
1717   else if (strcmp (element_name, "deny") == 0)
1718     {
1719       if (!append_rule_from_element (parser, element_name,
1720                                      attribute_names, attribute_values,
1721                                      FALSE, error))
1722         return FALSE;
1723       
1724       if (push_element (parser, ELEMENT_DENY) == NULL)
1725         {
1726           BUS_SET_OOM (error);
1727           return FALSE;
1728         }
1729       
1730       return TRUE;
1731     }
1732   else
1733     {
1734       dbus_set_error (error, DBUS_ERROR_FAILED,
1735                       "Element <%s> not allowed inside <%s> in configuration file",
1736                       element_name, "policy");
1737       return FALSE;
1738     }
1739 }
1740
1741 static dbus_bool_t
1742 start_selinux_child (BusConfigParser   *parser,
1743                      const char        *element_name,
1744                      const char       **attribute_names,
1745                      const char       **attribute_values,
1746                      DBusError         *error)
1747 {
1748   char *own_copy;
1749   char *context_copy;
1750
1751   own_copy = NULL;
1752   context_copy = NULL;
1753
1754   if (strcmp (element_name, "associate") == 0)
1755     {
1756       const char *own;
1757       const char *context;
1758       
1759       if (!locate_attributes (parser, "associate",
1760                               attribute_names,
1761                               attribute_values,
1762                               error,
1763                               "own", &own,
1764                               "context", &context,
1765                               NULL))
1766         return FALSE;
1767       
1768       if (push_element (parser, ELEMENT_ASSOCIATE) == NULL)
1769         {
1770           BUS_SET_OOM (error);
1771           return FALSE;
1772         }
1773
1774       if (own == NULL || context == NULL)
1775         {
1776           dbus_set_error (error, DBUS_ERROR_FAILED,
1777                           "Element <associate> must have attributes own=\"<servicename>\" and context=\"<selinux context>\"");
1778           return FALSE;
1779         }
1780
1781       own_copy = _dbus_strdup (own);
1782       if (own_copy == NULL)
1783         goto oom;
1784       context_copy = _dbus_strdup (context);
1785       if (context_copy == NULL)
1786         goto oom;
1787
1788       if (!_dbus_hash_table_insert_string (parser->service_context_table,
1789                                            own_copy, context_copy))
1790         goto oom;
1791
1792       return TRUE;
1793     }
1794   else
1795     {
1796       dbus_set_error (error, DBUS_ERROR_FAILED,
1797                       "Element <%s> not allowed inside <%s> in configuration file",
1798                       element_name, "selinux");
1799       return FALSE;
1800     }
1801
1802  oom:
1803   if (own_copy)
1804     dbus_free (own_copy);
1805
1806   if (context_copy)  
1807     dbus_free (context_copy);
1808
1809   BUS_SET_OOM (error);
1810   return FALSE;
1811 }
1812
1813 dbus_bool_t
1814 bus_config_parser_start_element (BusConfigParser   *parser,
1815                                  const char        *element_name,
1816                                  const char       **attribute_names,
1817                                  const char       **attribute_values,
1818                                  DBusError         *error)
1819 {
1820   ElementType t;
1821
1822   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1823
1824   /* printf ("START: %s\n", element_name); */
1825   
1826   t = top_element_type (parser);
1827
1828   if (t == ELEMENT_NONE)
1829     {
1830       if (strcmp (element_name, "busconfig") == 0)
1831         {
1832           if (!check_no_attributes (parser, "busconfig", attribute_names, attribute_values, error))
1833             return FALSE;
1834           
1835           if (push_element (parser, ELEMENT_BUSCONFIG) == NULL)
1836             {
1837               BUS_SET_OOM (error);
1838               return FALSE;
1839             }
1840
1841           return TRUE;
1842         }
1843       else
1844         {
1845           dbus_set_error (error, DBUS_ERROR_FAILED,
1846                           "Unknown element <%s> at root of configuration file",
1847                           element_name);
1848           return FALSE;
1849         }
1850     }
1851   else if (t == ELEMENT_BUSCONFIG)
1852     {
1853       return start_busconfig_child (parser, element_name,
1854                                     attribute_names, attribute_values,
1855                                     error);
1856     }
1857   else if (t == ELEMENT_POLICY)
1858     {
1859       return start_policy_child (parser, element_name,
1860                                  attribute_names, attribute_values,
1861                                  error);
1862     }
1863   else if (t == ELEMENT_SELINUX)
1864     {
1865       return start_selinux_child (parser, element_name,
1866                                   attribute_names, attribute_values,
1867                                   error);
1868     }
1869   else
1870     {
1871       dbus_set_error (error, DBUS_ERROR_FAILED,
1872                       "Element <%s> is not allowed in this context",
1873                       element_name);
1874       return FALSE;
1875     }  
1876 }
1877
1878 static dbus_bool_t
1879 set_limit (BusConfigParser *parser,
1880            const char      *name,
1881            long             value,
1882            DBusError       *error)
1883 {
1884   dbus_bool_t must_be_positive;
1885   dbus_bool_t must_be_int;
1886
1887   must_be_int = FALSE;
1888   must_be_positive = FALSE;
1889   
1890   if (strcmp (name, "max_incoming_bytes") == 0)
1891     {
1892       must_be_positive = TRUE;
1893       parser->limits.max_incoming_bytes = value;
1894     }
1895   else if (strcmp (name, "max_incoming_unix_fds") == 0)
1896     {
1897       must_be_positive = TRUE;
1898       parser->limits.max_incoming_unix_fds = value;
1899     }
1900   else if (strcmp (name, "max_outgoing_bytes") == 0)
1901     {
1902       must_be_positive = TRUE;
1903       parser->limits.max_outgoing_bytes = value;
1904     }
1905   else if (strcmp (name, "max_outgoing_unix_fds") == 0)
1906     {
1907       must_be_positive = TRUE;
1908       parser->limits.max_outgoing_unix_fds = value;
1909     }
1910   else if (strcmp (name, "max_message_size") == 0)
1911     {
1912       must_be_positive = TRUE;
1913       parser->limits.max_message_size = value;
1914     }
1915   else if (strcmp (name, "max_message_unix_fds") == 0)
1916     {
1917       must_be_positive = TRUE;
1918       parser->limits.max_message_unix_fds = value;
1919     }
1920   else if (strcmp (name, "service_start_timeout") == 0)
1921     {
1922       must_be_positive = TRUE;
1923       must_be_int = TRUE;
1924       parser->limits.activation_timeout = value;
1925     }
1926   else if (strcmp (name, "auth_timeout") == 0)
1927     {
1928       must_be_positive = TRUE;
1929       must_be_int = TRUE;
1930       parser->limits.auth_timeout = value;
1931     }
1932   else if (strcmp (name, "pending_fd_timeout") == 0)
1933     {
1934       must_be_positive = TRUE;
1935       must_be_int = TRUE;
1936       parser->limits.pending_fd_timeout = value;
1937     }
1938   else if (strcmp (name, "reply_timeout") == 0)
1939     {
1940       must_be_positive = TRUE;
1941       must_be_int = TRUE;
1942       parser->limits.reply_timeout = value;
1943     }
1944   else if (strcmp (name, "max_completed_connections") == 0)
1945     {
1946       must_be_positive = TRUE;
1947       must_be_int = TRUE;
1948       parser->limits.max_completed_connections = value;
1949     }
1950   else if (strcmp (name, "max_incomplete_connections") == 0)
1951     {
1952       must_be_positive = TRUE;
1953       must_be_int = TRUE;
1954       parser->limits.max_incomplete_connections = value;
1955     }
1956   else if (strcmp (name, "max_connections_per_user") == 0)
1957     {
1958       must_be_positive = TRUE;
1959       must_be_int = TRUE;
1960       parser->limits.max_connections_per_user = value;
1961     }
1962   else if (strcmp (name, "max_pending_service_starts") == 0)
1963     {
1964       must_be_positive = TRUE;
1965       must_be_int = TRUE;
1966       parser->limits.max_pending_activations = value;
1967     }
1968   else if (strcmp (name, "max_names_per_connection") == 0)
1969     {
1970       must_be_positive = TRUE;
1971       must_be_int = TRUE;
1972       parser->limits.max_services_per_connection = value;
1973     }
1974   else if (strcmp (name, "max_match_rules_per_connection") == 0)
1975     {
1976       must_be_positive = TRUE;
1977       must_be_int = TRUE;
1978       parser->limits.max_match_rules_per_connection = value;
1979     }
1980   else if (strcmp (name, "max_replies_per_connection") == 0)
1981     {
1982       must_be_positive = TRUE;
1983       must_be_int = TRUE;
1984       parser->limits.max_replies_per_connection = value;
1985     }
1986   else
1987     {
1988       dbus_set_error (error, DBUS_ERROR_FAILED,
1989                       "There is no limit called \"%s\"\n",
1990                       name);
1991       return FALSE;
1992     }
1993   
1994   if (must_be_positive && value < 0)
1995     {
1996       dbus_set_error (error, DBUS_ERROR_FAILED,
1997                       "<limit name=\"%s\"> must be a positive number\n",
1998                       name);
1999       return FALSE;
2000     }
2001
2002   if (must_be_int &&
2003       (value < _DBUS_INT_MIN || value > _DBUS_INT_MAX))
2004     {
2005       dbus_set_error (error, DBUS_ERROR_FAILED,
2006                       "<limit name=\"%s\"> value is too large\n",
2007                       name);
2008       return FALSE;
2009     }
2010
2011   return TRUE;  
2012 }
2013
2014 dbus_bool_t
2015 bus_config_parser_end_element (BusConfigParser   *parser,
2016                                const char        *element_name,
2017                                DBusError         *error)
2018 {
2019   ElementType t;
2020   const char *n;
2021   Element *e;
2022
2023   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2024
2025   /* printf ("END: %s\n", element_name); */
2026   
2027   t = top_element_type (parser);
2028
2029   if (t == ELEMENT_NONE)
2030     {
2031       /* should probably be an assertion failure but
2032        * being paranoid about XML parsers
2033        */
2034       dbus_set_error (error, DBUS_ERROR_FAILED,
2035                       "XML parser ended element with no element on the stack");
2036       return FALSE;
2037     }
2038
2039   n = bus_config_parser_element_type_to_name (t);
2040   _dbus_assert (n != NULL);
2041   if (strcmp (n, element_name) != 0)
2042     {
2043       /* should probably be an assertion failure but
2044        * being paranoid about XML parsers
2045        */
2046       dbus_set_error (error, DBUS_ERROR_FAILED,
2047                       "XML element <%s> ended but topmost element on the stack was <%s>",
2048                       element_name, n);
2049       return FALSE;
2050     }
2051
2052   e = peek_element (parser);
2053   _dbus_assert (e != NULL);
2054
2055   switch (e->type)
2056     {
2057     case ELEMENT_NONE:
2058       _dbus_assert_not_reached ("element in stack has no type");
2059       break;
2060
2061     case ELEMENT_INCLUDE:
2062     case ELEMENT_USER:
2063     case ELEMENT_CONFIGTYPE:
2064     case ELEMENT_LISTEN:
2065     case ELEMENT_PIDFILE:
2066     case ELEMENT_AUTH:
2067     case ELEMENT_SERVICEDIR:
2068     case ELEMENT_SERVICEHELPER:
2069     case ELEMENT_INCLUDEDIR:
2070     case ELEMENT_LIMIT:
2071       if (!e->had_content)
2072         {
2073           dbus_set_error (error, DBUS_ERROR_FAILED,
2074                           "XML element <%s> was expected to have content inside it",
2075                           bus_config_parser_element_type_to_name (e->type));
2076           return FALSE;
2077         }
2078
2079       if (e->type == ELEMENT_LIMIT)
2080         {
2081           if (!set_limit (parser, e->d.limit.name, e->d.limit.value,
2082                           error))
2083             return FALSE;
2084         }
2085       break;
2086
2087     case ELEMENT_BUSCONFIG:
2088     case ELEMENT_POLICY:
2089     case ELEMENT_ALLOW:
2090     case ELEMENT_DENY:
2091     case ELEMENT_FORK:
2092     case ELEMENT_SYSLOG:
2093     case ELEMENT_KEEP_UMASK:
2094     case ELEMENT_SELINUX:
2095     case ELEMENT_ASSOCIATE:
2096     case ELEMENT_STANDARD_SESSION_SERVICEDIRS:
2097     case ELEMENT_STANDARD_SYSTEM_SERVICEDIRS:
2098     case ELEMENT_ALLOW_ANONYMOUS:
2099     case ELEMENT_APPARMOR:
2100       break;
2101     }
2102
2103   pop_element (parser);
2104
2105   return TRUE;
2106 }
2107
2108 static dbus_bool_t
2109 all_whitespace (const DBusString *str)
2110 {
2111   int i;
2112
2113   _dbus_string_skip_white (str, 0, &i);
2114
2115   return i == _dbus_string_get_length (str);
2116 }
2117
2118 static dbus_bool_t
2119 make_full_path (const DBusString *basedir,
2120                 const DBusString *filename,
2121                 DBusString       *full_path)
2122 {
2123   if (_dbus_path_is_absolute (filename))
2124     {
2125       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 log to syslog unconditionally 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! (There's
2316                    * also some layer inversion going on, if we want to use
2317                    * the bus context.) */
2318                   _dbus_system_log (DBUS_SYSTEM_LOG_INFO,
2319                                     "Encountered error '%s' while parsing '%s'\n",
2320                                     error->message,
2321                                     _dbus_string_get_const_data (&full_path));
2322                   dbus_error_free (error);
2323                 }
2324             }
2325         }
2326
2327       _dbus_string_free (&full_path);
2328     }
2329
2330   if (dbus_error_is_set (&tmp_error))
2331     {
2332       dbus_move_error (&tmp_error, error);
2333       goto failed;
2334     }
2335
2336
2337   if (!_dbus_string_copy_data (dirname, &s))
2338     {
2339       BUS_SET_OOM (error);
2340       goto failed;
2341     }
2342
2343   if (!_dbus_list_append (&parser->conf_dirs, s))
2344     {
2345       dbus_free (s);
2346       BUS_SET_OOM (error);
2347       goto failed;
2348     }
2349
2350  success:
2351   retval = TRUE;
2352   
2353  failed:
2354   _dbus_string_free (&filename);
2355   
2356   if (dir)
2357     _dbus_directory_close (dir);
2358
2359   return retval;
2360 }
2361
2362 dbus_bool_t
2363 bus_config_parser_content (BusConfigParser   *parser,
2364                            const DBusString  *content,
2365                            DBusError         *error)
2366 {
2367   Element *e;
2368
2369   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2370
2371 #if 0
2372   {
2373     const char *c_str;
2374     
2375     _dbus_string_get_const_data (content, &c_str);
2376
2377     printf ("CONTENT %d bytes: %s\n", _dbus_string_get_length (content), c_str);
2378   }
2379 #endif
2380   
2381   e = peek_element (parser);
2382   if (e == NULL)
2383     {
2384       dbus_set_error (error, DBUS_ERROR_FAILED,
2385                       "Text content outside of any XML element in configuration file");
2386       return FALSE;
2387     }
2388   else if (e->had_content)
2389     {
2390       _dbus_assert_not_reached ("Element had multiple content blocks");
2391       return FALSE;
2392     }
2393
2394   switch (top_element_type (parser))
2395     {
2396     case ELEMENT_NONE:
2397       _dbus_assert_not_reached ("element at top of stack has no type");
2398       return FALSE;
2399
2400     case ELEMENT_BUSCONFIG:
2401     case ELEMENT_POLICY:
2402     case ELEMENT_ALLOW:
2403     case ELEMENT_DENY:
2404     case ELEMENT_FORK:
2405     case ELEMENT_SYSLOG:
2406     case ELEMENT_KEEP_UMASK:
2407     case ELEMENT_STANDARD_SESSION_SERVICEDIRS:    
2408     case ELEMENT_STANDARD_SYSTEM_SERVICEDIRS:    
2409     case ELEMENT_ALLOW_ANONYMOUS:
2410     case ELEMENT_SELINUX:
2411     case ELEMENT_ASSOCIATE:
2412     case ELEMENT_APPARMOR:
2413       if (all_whitespace (content))
2414         return TRUE;
2415       else
2416         {
2417           dbus_set_error (error, DBUS_ERROR_FAILED,
2418                           "No text content expected inside XML element %s in configuration file",
2419                           bus_config_parser_element_type_to_name (top_element_type (parser)));
2420           return FALSE;
2421         }
2422
2423     case ELEMENT_PIDFILE:
2424       {
2425         char *s;
2426
2427         e->had_content = TRUE;
2428         
2429         if (!_dbus_string_copy_data (content, &s))
2430           goto nomem;
2431           
2432         dbus_free (parser->pidfile);
2433         parser->pidfile = s;
2434       }
2435       break;
2436
2437     case ELEMENT_INCLUDE:
2438       {
2439         DBusString full_path, selinux_policy_root;
2440
2441         e->had_content = TRUE;
2442
2443         if (e->d.include.if_selinux_enabled
2444             && !bus_selinux_enabled ())
2445           break;
2446
2447         if (!_dbus_string_init (&full_path))
2448           goto nomem;
2449
2450         if (e->d.include.selinux_root_relative)
2451           {
2452             if (!bus_selinux_get_policy_root ())
2453               {
2454                 dbus_set_error (error, DBUS_ERROR_FAILED,
2455                                 "Could not determine SELinux policy root for relative inclusion");
2456                 _dbus_string_free (&full_path);
2457                 return FALSE;
2458               }
2459             _dbus_string_init_const (&selinux_policy_root,
2460                                      bus_selinux_get_policy_root ());
2461             if (!make_full_path (&selinux_policy_root, content, &full_path))
2462               {
2463                 _dbus_string_free (&full_path);
2464                 goto nomem;
2465               }
2466           }
2467         else if (!make_full_path (&parser->basedir, content, &full_path))
2468           {
2469             _dbus_string_free (&full_path);
2470             goto nomem;
2471           }
2472
2473         if (!include_file (parser, &full_path,
2474                            e->d.include.ignore_missing, error))
2475           {
2476             _dbus_string_free (&full_path);
2477             return FALSE;
2478           }
2479
2480         _dbus_string_free (&full_path);
2481       }
2482       break;
2483
2484     case ELEMENT_SERVICEHELPER:
2485       {
2486         DBusString full_path;
2487         
2488         e->had_content = TRUE;
2489
2490         if (!_dbus_string_init (&full_path))
2491           goto nomem;
2492         
2493         if (!make_full_path (&parser->basedir, content, &full_path))
2494           {
2495             _dbus_string_free (&full_path);
2496             goto nomem;
2497           }
2498
2499         if (!servicehelper_path (parser, &full_path, error))
2500           {
2501             _dbus_string_free (&full_path);
2502             return FALSE;
2503           }
2504
2505         _dbus_string_free (&full_path);
2506       }
2507       break;
2508       
2509     case ELEMENT_INCLUDEDIR:
2510       {
2511         DBusString full_path;
2512         
2513         e->had_content = TRUE;
2514
2515         if (!_dbus_string_init (&full_path))
2516           goto nomem;
2517         
2518         if (!make_full_path (&parser->basedir, content, &full_path))
2519           {
2520             _dbus_string_free (&full_path);
2521             goto nomem;
2522           }
2523         
2524         if (!include_dir (parser, &full_path, error))
2525           {
2526             _dbus_string_free (&full_path);
2527             return FALSE;
2528           }
2529
2530         _dbus_string_free (&full_path);
2531       }
2532       break;
2533       
2534     case ELEMENT_USER:
2535       {
2536         char *s;
2537
2538         e->had_content = TRUE;
2539         
2540         if (!_dbus_string_copy_data (content, &s))
2541           goto nomem;
2542           
2543         dbus_free (parser->user);
2544         parser->user = s;
2545       }
2546       break;
2547
2548     case ELEMENT_CONFIGTYPE:
2549       {
2550         char *s;
2551
2552         e->had_content = TRUE;
2553
2554         if (!_dbus_string_copy_data (content, &s))
2555           goto nomem;
2556         
2557         dbus_free (parser->bus_type);
2558         parser->bus_type = s;
2559       }
2560       break;
2561       
2562     case ELEMENT_LISTEN:
2563       {
2564         char *s;
2565
2566         e->had_content = TRUE;
2567         
2568         if (!_dbus_string_copy_data (content, &s))
2569           goto nomem;
2570
2571         if (!_dbus_list_append (&parser->listen_on,
2572                                 s))
2573           {
2574             dbus_free (s);
2575             goto nomem;
2576           }
2577       }
2578       break;
2579
2580     case ELEMENT_AUTH:
2581       {
2582         char *s;
2583         
2584         e->had_content = TRUE;
2585
2586         if (!_dbus_string_copy_data (content, &s))
2587           goto nomem;
2588
2589         if (!_dbus_list_append (&parser->mechanisms,
2590                                 s))
2591           {
2592             dbus_free (s);
2593             goto nomem;
2594           }
2595       }
2596       break;
2597
2598     case ELEMENT_SERVICEDIR:
2599       {
2600         char *s;
2601         DBusString full_path;
2602         
2603         e->had_content = TRUE;
2604
2605         if (!_dbus_string_init (&full_path))
2606           goto nomem;
2607         
2608         if (!make_full_path (&parser->basedir, content, &full_path))
2609           {
2610             _dbus_string_free (&full_path);
2611             goto nomem;
2612           }
2613         
2614         if (!_dbus_string_copy_data (&full_path, &s))
2615           {
2616             _dbus_string_free (&full_path);
2617             goto nomem;
2618           }
2619
2620         /* _only_ extra session directories can be specified */
2621         if (!service_dirs_append_unique_or_free (&parser->service_dirs, s))
2622           {
2623             _dbus_string_free (&full_path);
2624             dbus_free (s);
2625             goto nomem;
2626           }
2627
2628         _dbus_string_free (&full_path);
2629       }
2630       break;
2631
2632     case ELEMENT_LIMIT:
2633       {
2634         long val;
2635
2636         e->had_content = TRUE;
2637
2638         val = 0;
2639         if (!_dbus_string_parse_int (content, 0, &val, NULL))
2640           {
2641             dbus_set_error (error, DBUS_ERROR_FAILED,
2642                             "<limit name=\"%s\"> element has invalid value (could not parse as integer)",
2643                             e->d.limit.name);
2644             return FALSE;
2645           }
2646
2647         e->d.limit.value = val;
2648
2649         _dbus_verbose ("Loaded value %ld for limit %s\n",
2650                        e->d.limit.value,
2651                        e->d.limit.name);
2652       }
2653       break;
2654     }
2655
2656   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2657   return TRUE;
2658
2659  nomem:
2660   BUS_SET_OOM (error);
2661   return FALSE;
2662 }
2663
2664 dbus_bool_t
2665 bus_config_parser_finished (BusConfigParser   *parser,
2666                             DBusError         *error)
2667 {
2668   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2669
2670   if (parser->stack != NULL)
2671     {
2672       dbus_set_error (error, DBUS_ERROR_FAILED,
2673                       "Element <%s> was not closed in configuration file",
2674                       bus_config_parser_element_type_to_name (top_element_type (parser)));
2675
2676       return FALSE;
2677     }
2678
2679   if (parser->is_toplevel && parser->listen_on == NULL)
2680     {
2681       dbus_set_error (error, DBUS_ERROR_FAILED,
2682                       "Configuration file needs one or more <listen> elements giving addresses"); 
2683       return FALSE;
2684     }
2685   
2686   return TRUE;
2687 }
2688
2689 const char*
2690 bus_config_parser_get_user (BusConfigParser *parser)
2691 {
2692   return parser->user;
2693 }
2694
2695 const char*
2696 bus_config_parser_get_type (BusConfigParser *parser)
2697 {
2698   return parser->bus_type;
2699 }
2700
2701 DBusList**
2702 bus_config_parser_get_addresses (BusConfigParser *parser)
2703 {
2704   return &parser->listen_on;
2705 }
2706
2707 DBusList**
2708 bus_config_parser_get_mechanisms (BusConfigParser *parser)
2709 {
2710   return &parser->mechanisms;
2711 }
2712
2713 DBusList**
2714 bus_config_parser_get_service_dirs (BusConfigParser *parser)
2715 {
2716   return &parser->service_dirs;
2717 }
2718
2719 DBusList**
2720 bus_config_parser_get_conf_dirs (BusConfigParser *parser)
2721 {
2722   return &parser->conf_dirs;
2723 }
2724
2725 dbus_bool_t
2726 bus_config_parser_get_fork (BusConfigParser   *parser)
2727 {
2728   return parser->fork;
2729 }
2730
2731 dbus_bool_t
2732 bus_config_parser_get_syslog (BusConfigParser   *parser)
2733 {
2734   return parser->syslog;
2735 }
2736
2737 dbus_bool_t
2738 bus_config_parser_get_keep_umask (BusConfigParser   *parser)
2739 {
2740   return parser->keep_umask;
2741 }
2742
2743 dbus_bool_t
2744 bus_config_parser_get_allow_anonymous (BusConfigParser   *parser)
2745 {
2746   return parser->allow_anonymous;
2747 }
2748
2749 const char *
2750 bus_config_parser_get_pidfile (BusConfigParser   *parser)
2751 {
2752   return parser->pidfile;
2753 }
2754
2755 const char *
2756 bus_config_parser_get_servicehelper (BusConfigParser   *parser)
2757 {
2758   return parser->servicehelper;
2759 }
2760
2761 BusPolicy*
2762 bus_config_parser_steal_policy (BusConfigParser *parser)
2763 {
2764   BusPolicy *policy;
2765
2766   _dbus_assert (parser->policy != NULL); /* can only steal the policy 1 time */
2767   
2768   policy = parser->policy;
2769
2770   parser->policy = NULL;
2771
2772   return policy;
2773 }
2774
2775 /* Overwrite any limits that were set in the configuration file */
2776 void
2777 bus_config_parser_get_limits (BusConfigParser *parser,
2778                               BusLimits       *limits)
2779 {
2780   *limits = parser->limits;
2781 }
2782
2783 DBusHashTable*
2784 bus_config_parser_steal_service_context_table (BusConfigParser *parser)
2785 {
2786   DBusHashTable *table;
2787
2788   _dbus_assert (parser->service_context_table != NULL); /* can only steal once */
2789
2790   table = parser->service_context_table;
2791
2792   parser->service_context_table = NULL;
2793
2794   return table;
2795 }
2796
2797 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
2798 #include <stdio.h>
2799
2800 typedef enum
2801 {
2802   VALID,
2803   INVALID,
2804   UNKNOWN
2805 } Validity;
2806
2807 static dbus_bool_t
2808 do_check_own_rules (BusPolicy  *policy)
2809 {
2810   const struct {
2811     char *name;
2812     dbus_bool_t allowed;
2813   } checks[] = {
2814     {"org.freedesktop", FALSE},
2815     {"org.freedesktop.ManySystem", FALSE},
2816     {"org.freedesktop.ManySystems", TRUE},
2817     {"org.freedesktop.ManySystems.foo", TRUE},
2818     {"org.freedesktop.ManySystems.foo.bar", TRUE},
2819     {"org.freedesktop.ManySystems2", FALSE},
2820     {"org.freedesktop.ManySystems2.foo", FALSE},
2821     {"org.freedesktop.ManySystems2.foo.bar", FALSE},
2822     {NULL, FALSE}
2823   };
2824   int i = 0;
2825
2826   while (checks[i].name)
2827     {
2828       DBusString service_name;
2829       dbus_bool_t ret;
2830
2831       if (!_dbus_string_init (&service_name))
2832         _dbus_assert_not_reached ("couldn't init string");
2833       if (!_dbus_string_append (&service_name, checks[i].name))
2834         _dbus_assert_not_reached ("couldn't append string");
2835
2836       ret = bus_policy_check_can_own (policy, &service_name);
2837       printf ("        Check name %s: %s\n", checks[i].name,
2838               ret ? "allowed" : "not allowed");
2839       if (checks[i].allowed && !ret)
2840         {
2841           _dbus_warn ("Cannot own %s\n", checks[i].name);
2842           return FALSE;
2843         }
2844       if (!checks[i].allowed && ret)
2845         {
2846           _dbus_warn ("Can own %s\n", checks[i].name);
2847           return FALSE;
2848         }
2849       _dbus_string_free (&service_name);
2850
2851       i++;
2852     }
2853
2854   return TRUE;
2855 }
2856
2857 static dbus_bool_t
2858 do_load (const DBusString *full_path,
2859          Validity          validity,
2860          dbus_bool_t       oom_possible,
2861          dbus_bool_t       check_own_rules)
2862 {
2863   BusConfigParser *parser;
2864   DBusError error;
2865
2866   dbus_error_init (&error);
2867
2868   parser = bus_config_load (full_path, TRUE, NULL, &error);
2869   if (parser == NULL)
2870     {
2871       _DBUS_ASSERT_ERROR_IS_SET (&error);
2872
2873       if (oom_possible &&
2874           dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
2875         {
2876           _dbus_verbose ("Failed to load valid file due to OOM\n");
2877           dbus_error_free (&error);
2878           return TRUE;
2879         }
2880       else if (validity == VALID)
2881         {
2882           _dbus_warn ("Failed to load valid file but still had memory: %s\n",
2883                       error.message);
2884
2885           dbus_error_free (&error);
2886           return FALSE;
2887         }
2888       else
2889         {
2890           dbus_error_free (&error);
2891           return TRUE;
2892         }
2893     }
2894   else
2895     {
2896       _DBUS_ASSERT_ERROR_IS_CLEAR (&error);
2897
2898       if (check_own_rules && do_check_own_rules (parser->policy) == FALSE)
2899         {
2900           return FALSE;
2901         }
2902
2903       bus_config_parser_unref (parser);
2904
2905       if (validity == INVALID)
2906         {
2907           _dbus_warn ("Accepted invalid file\n");
2908           return FALSE;
2909         }
2910
2911       return TRUE;
2912     }
2913 }
2914
2915 typedef struct
2916 {
2917   const DBusString *full_path;
2918   Validity          validity;
2919   dbus_bool_t       check_own_rules;
2920 } LoaderOomData;
2921
2922 static dbus_bool_t
2923 check_loader_oom_func (void *data)
2924 {
2925   LoaderOomData *d = data;
2926
2927   return do_load (d->full_path, d->validity, TRUE, d->check_own_rules);
2928 }
2929
2930 static dbus_bool_t
2931 process_test_valid_subdir (const DBusString *test_base_dir,
2932                            const char       *subdir,
2933                            Validity          validity)
2934 {
2935   DBusString test_directory;
2936   DBusString filename;
2937   DBusDirIter *dir;
2938   dbus_bool_t retval;
2939   DBusError error;
2940
2941   retval = FALSE;
2942   dir = NULL;
2943
2944   if (!_dbus_string_init (&test_directory))
2945     _dbus_assert_not_reached ("didn't allocate test_directory\n");
2946
2947   _dbus_string_init_const (&filename, subdir);
2948
2949   if (!_dbus_string_copy (test_base_dir, 0,
2950                           &test_directory, 0))
2951     _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
2952
2953   if (!_dbus_concat_dir_and_file (&test_directory, &filename))
2954     _dbus_assert_not_reached ("couldn't allocate full path");
2955
2956   _dbus_string_free (&filename);
2957   if (!_dbus_string_init (&filename))
2958     _dbus_assert_not_reached ("didn't allocate filename string\n");
2959
2960   dbus_error_init (&error);
2961   dir = _dbus_directory_open (&test_directory, &error);
2962   if (dir == NULL)
2963     {
2964       _dbus_warn ("Could not open %s: %s\n",
2965                   _dbus_string_get_const_data (&test_directory),
2966                   error.message);
2967       dbus_error_free (&error);
2968       goto failed;
2969     }
2970
2971   if (validity == VALID)
2972     printf ("Testing valid files:\n");
2973   else if (validity == INVALID)
2974     printf ("Testing invalid files:\n");
2975   else
2976     printf ("Testing unknown files:\n");
2977
2978  next:
2979   while (_dbus_directory_get_next_file (dir, &filename, &error))
2980     {
2981       DBusString full_path;
2982       LoaderOomData d;
2983
2984       if (!_dbus_string_init (&full_path))
2985         _dbus_assert_not_reached ("couldn't init string");
2986
2987       if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
2988         _dbus_assert_not_reached ("couldn't copy dir to full_path");
2989
2990       if (!_dbus_concat_dir_and_file (&full_path, &filename))
2991         _dbus_assert_not_reached ("couldn't concat file to dir");
2992
2993       if (!_dbus_string_ends_with_c_str (&full_path, ".conf"))
2994         {
2995           _dbus_verbose ("Skipping non-.conf file %s\n",
2996                          _dbus_string_get_const_data (&filename));
2997           _dbus_string_free (&full_path);
2998           goto next;
2999         }
3000
3001       printf ("    %s\n", _dbus_string_get_const_data (&filename));
3002
3003       _dbus_verbose (" expecting %s\n",
3004                      validity == VALID ? "valid" :
3005                      (validity == INVALID ? "invalid" :
3006                       (validity == UNKNOWN ? "unknown" : "???")));
3007
3008       d.full_path = &full_path;
3009       d.validity = validity;
3010       d.check_own_rules = _dbus_string_ends_with_c_str (&full_path,
3011           "check-own-rules.conf");
3012
3013       /* FIXME hackaround for an expat problem, see
3014        * https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=124747
3015        * http://freedesktop.org/pipermail/dbus/2004-May/001153.html
3016        */
3017       /* if (!_dbus_test_oom_handling ("config-loader", check_loader_oom_func, &d)) */
3018       if (!check_loader_oom_func (&d))
3019         _dbus_assert_not_reached ("test failed");
3020       
3021       _dbus_string_free (&full_path);
3022     }
3023
3024   if (dbus_error_is_set (&error))
3025     {
3026       _dbus_warn ("Could not get next file in %s: %s\n",
3027                   _dbus_string_get_const_data (&test_directory),
3028                   error.message);
3029       dbus_error_free (&error);
3030       goto failed;
3031     }
3032
3033   retval = TRUE;
3034
3035  failed:
3036
3037   if (dir)
3038     _dbus_directory_close (dir);
3039   _dbus_string_free (&test_directory);
3040   _dbus_string_free (&filename);
3041
3042   return retval;
3043 }
3044
3045 static dbus_bool_t
3046 bools_equal (dbus_bool_t a,
3047              dbus_bool_t b)
3048 {
3049   return a ? b : !b;
3050 }
3051
3052 static dbus_bool_t
3053 strings_equal_or_both_null (const char *a,
3054                             const char *b)
3055 {
3056   if (a == NULL || b == NULL)
3057     return a == b;
3058   else
3059     return !strcmp (a, b);
3060 }
3061
3062 static dbus_bool_t
3063 elements_equal (const Element *a,
3064                 const Element *b)
3065 {
3066   if (a->type != b->type)
3067     return FALSE;
3068
3069   if (!bools_equal (a->had_content, b->had_content))
3070     return FALSE;
3071
3072   switch (a->type)
3073     {
3074
3075     case ELEMENT_INCLUDE:
3076       if (!bools_equal (a->d.include.ignore_missing,
3077                         b->d.include.ignore_missing))
3078         return FALSE;
3079       break;
3080
3081     case ELEMENT_POLICY:
3082       if (a->d.policy.type != b->d.policy.type)
3083         return FALSE;
3084       if (a->d.policy.gid_uid_or_at_console != b->d.policy.gid_uid_or_at_console)
3085         return FALSE;
3086       break;
3087
3088     case ELEMENT_LIMIT:
3089       if (strcmp (a->d.limit.name, b->d.limit.name))
3090         return FALSE;
3091       if (a->d.limit.value != b->d.limit.value)
3092         return FALSE;
3093       break;
3094
3095     default:
3096       /* do nothing */
3097       break;
3098     }
3099
3100   return TRUE;
3101
3102 }
3103
3104 static dbus_bool_t
3105 lists_of_elements_equal (DBusList *a,
3106                          DBusList *b)
3107 {
3108   DBusList *ia;
3109   DBusList *ib;
3110
3111   ia = a;
3112   ib = b;
3113   
3114   while (ia != NULL && ib != NULL)
3115     {
3116       if (elements_equal (ia->data, ib->data))
3117         return FALSE;
3118       ia = _dbus_list_get_next_link (&a, ia);
3119       ib = _dbus_list_get_next_link (&b, ib);
3120     }
3121
3122   return ia == NULL && ib == NULL;
3123 }
3124
3125 static dbus_bool_t
3126 lists_of_c_strings_equal (DBusList *a,
3127                           DBusList *b)
3128 {
3129   DBusList *ia;
3130   DBusList *ib;
3131
3132   ia = a;
3133   ib = b;
3134   
3135   while (ia != NULL && ib != NULL)
3136     {
3137       if (strcmp (ia->data, ib->data))
3138         return FALSE;
3139       ia = _dbus_list_get_next_link (&a, ia);
3140       ib = _dbus_list_get_next_link (&b, ib);
3141     }
3142
3143   return ia == NULL && ib == NULL;
3144 }
3145
3146 static dbus_bool_t
3147 limits_equal (const BusLimits *a,
3148               const BusLimits *b)
3149 {
3150   return
3151     (a->max_incoming_bytes == b->max_incoming_bytes
3152      || a->max_incoming_unix_fds == b->max_incoming_unix_fds
3153      || a->max_outgoing_bytes == b->max_outgoing_bytes
3154      || a->max_outgoing_unix_fds == b->max_outgoing_unix_fds
3155      || a->max_message_size == b->max_message_size
3156      || a->max_message_unix_fds == b->max_message_unix_fds
3157      || a->activation_timeout == b->activation_timeout
3158      || a->auth_timeout == b->auth_timeout
3159      || a->pending_fd_timeout == b->pending_fd_timeout
3160      || a->max_completed_connections == b->max_completed_connections
3161      || a->max_incomplete_connections == b->max_incomplete_connections
3162      || a->max_connections_per_user == b->max_connections_per_user
3163      || a->max_pending_activations == b->max_pending_activations
3164      || a->max_services_per_connection == b->max_services_per_connection
3165      || a->max_match_rules_per_connection == b->max_match_rules_per_connection
3166      || a->max_replies_per_connection == b->max_replies_per_connection
3167      || a->reply_timeout == b->reply_timeout);
3168 }
3169
3170 static dbus_bool_t
3171 config_parsers_equal (const BusConfigParser *a,
3172                       const BusConfigParser *b)
3173 {
3174   if (!_dbus_string_equal (&a->basedir, &b->basedir))
3175     return FALSE;
3176
3177   if (!lists_of_elements_equal (a->stack, b->stack))
3178     return FALSE;
3179
3180   if (!strings_equal_or_both_null (a->user, b->user))
3181     return FALSE;
3182
3183   if (!lists_of_c_strings_equal (a->listen_on, b->listen_on))
3184     return FALSE;
3185
3186   if (!lists_of_c_strings_equal (a->mechanisms, b->mechanisms))
3187     return FALSE;
3188
3189   if (!lists_of_c_strings_equal (a->service_dirs, b->service_dirs))
3190     return FALSE;
3191   
3192   /* FIXME: compare policy */
3193
3194   /* FIXME: compare service selinux ID table */
3195
3196   if (! limits_equal (&a->limits, &b->limits))
3197     return FALSE;
3198
3199   if (!strings_equal_or_both_null (a->pidfile, b->pidfile))
3200     return FALSE;
3201
3202   if (! bools_equal (a->fork, b->fork))
3203     return FALSE;
3204
3205   if (! bools_equal (a->keep_umask, b->keep_umask))
3206     return FALSE;
3207
3208   if (! bools_equal (a->is_toplevel, b->is_toplevel))
3209     return FALSE;
3210
3211   return TRUE;
3212 }
3213
3214 static dbus_bool_t
3215 all_are_equiv (const DBusString *target_directory)
3216 {
3217   DBusString filename;
3218   DBusDirIter *dir;
3219   BusConfigParser *first_parser;
3220   BusConfigParser *parser;
3221   DBusError error;
3222   dbus_bool_t equal;
3223   dbus_bool_t retval;
3224
3225   dir = NULL;
3226   first_parser = NULL;
3227   parser = NULL;
3228   retval = FALSE;
3229
3230   if (!_dbus_string_init (&filename))
3231     _dbus_assert_not_reached ("didn't allocate filename string");
3232
3233   dbus_error_init (&error);
3234   dir = _dbus_directory_open (target_directory, &error);
3235   if (dir == NULL)
3236     {
3237       _dbus_warn ("Could not open %s: %s\n",
3238                   _dbus_string_get_const_data (target_directory),
3239                   error.message);
3240       dbus_error_free (&error);
3241       goto finished;
3242     }
3243
3244   printf ("Comparing equivalent files:\n");
3245
3246  next:
3247   while (_dbus_directory_get_next_file (dir, &filename, &error))
3248     {
3249       DBusString full_path;
3250
3251       if (!_dbus_string_init (&full_path))
3252         _dbus_assert_not_reached ("couldn't init string");
3253
3254       if (!_dbus_string_copy (target_directory, 0, &full_path, 0))
3255         _dbus_assert_not_reached ("couldn't copy dir to full_path");
3256
3257       if (!_dbus_concat_dir_and_file (&full_path, &filename))
3258         _dbus_assert_not_reached ("couldn't concat file to dir");
3259
3260       if (!_dbus_string_ends_with_c_str (&full_path, ".conf"))
3261         {
3262           _dbus_verbose ("Skipping non-.conf file %s\n",
3263                          _dbus_string_get_const_data (&filename));
3264           _dbus_string_free (&full_path);
3265           goto next;
3266         }
3267
3268       printf ("    %s\n", _dbus_string_get_const_data (&filename));
3269
3270       parser = bus_config_load (&full_path, TRUE, NULL, &error);
3271
3272       if (parser == NULL)
3273         {
3274           _dbus_warn ("Could not load file %s: %s\n",
3275                       _dbus_string_get_const_data (&full_path),
3276                       error.message);
3277           _dbus_string_free (&full_path);
3278           dbus_error_free (&error);
3279           goto finished;
3280         }
3281       else if (first_parser == NULL)
3282         {
3283           _dbus_string_free (&full_path);
3284           first_parser = parser;
3285         }
3286       else
3287         {
3288           _dbus_string_free (&full_path);
3289           equal = config_parsers_equal (first_parser, parser);
3290           bus_config_parser_unref (parser);
3291           if (! equal)
3292             goto finished;
3293         }
3294     }
3295
3296   retval = TRUE;
3297
3298  finished:
3299   _dbus_string_free (&filename);
3300   if (first_parser)
3301     bus_config_parser_unref (first_parser);
3302   if (dir)
3303     _dbus_directory_close (dir);
3304
3305   return retval;
3306   
3307 }
3308
3309 static dbus_bool_t
3310 process_test_equiv_subdir (const DBusString *test_base_dir,
3311                            const char       *subdir)
3312 {
3313   DBusString test_directory;
3314   DBusString filename;
3315   DBusDirIter *dir;
3316   DBusError error;
3317   dbus_bool_t equal;
3318   dbus_bool_t retval;
3319
3320   dir = NULL;
3321   retval = FALSE;
3322
3323   if (!_dbus_string_init (&test_directory))
3324     _dbus_assert_not_reached ("didn't allocate test_directory");
3325
3326   _dbus_string_init_const (&filename, subdir);
3327
3328   if (!_dbus_string_copy (test_base_dir, 0,
3329                           &test_directory, 0))
3330     _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
3331
3332   if (!_dbus_concat_dir_and_file (&test_directory, &filename))
3333     _dbus_assert_not_reached ("couldn't allocate full path");
3334
3335   _dbus_string_free (&filename);
3336   if (!_dbus_string_init (&filename))
3337     _dbus_assert_not_reached ("didn't allocate filename string");
3338
3339   dbus_error_init (&error);
3340   dir = _dbus_directory_open (&test_directory, &error);
3341   if (dir == NULL)
3342     {
3343       _dbus_warn ("Could not open %s: %s\n",
3344                   _dbus_string_get_const_data (&test_directory),
3345                   error.message);
3346       dbus_error_free (&error);
3347       goto finished;
3348     }
3349
3350   while (_dbus_directory_get_next_file (dir, &filename, &error))
3351     {
3352       DBusString full_path;
3353
3354       /* Skip CVS's magic directories! */
3355       if (_dbus_string_equal_c_str (&filename, "CVS"))
3356         continue;
3357
3358       if (!_dbus_string_init (&full_path))
3359         _dbus_assert_not_reached ("couldn't init string");
3360
3361       if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
3362         _dbus_assert_not_reached ("couldn't copy dir to full_path");
3363
3364       if (!_dbus_concat_dir_and_file (&full_path, &filename))
3365         _dbus_assert_not_reached ("couldn't concat file to dir");
3366       
3367       equal = all_are_equiv (&full_path);
3368       _dbus_string_free (&full_path);
3369
3370       if (!equal)
3371         goto finished;
3372     }
3373
3374   retval = TRUE;
3375
3376  finished:
3377   _dbus_string_free (&test_directory);
3378   _dbus_string_free (&filename);
3379   if (dir)
3380     _dbus_directory_close (dir);
3381
3382   return retval;
3383   
3384 }
3385
3386 static const char *test_session_service_dir_matches[] = 
3387         {
3388 #ifdef DBUS_UNIX
3389          "/testhome/foo/.testlocal/testshare/dbus-1/services",
3390          "/testusr/testlocal/testshare/dbus-1/services",
3391          "/testusr/testshare/dbus-1/services",
3392          DBUS_DATADIR"/dbus-1/services",
3393 #endif
3394 /* will be filled in test_default_session_servicedirs() */
3395 #ifdef DBUS_WIN
3396          NULL,
3397          NULL,
3398 #endif
3399          NULL
3400         };
3401
3402 static dbus_bool_t
3403 test_default_session_servicedirs (void)
3404 {
3405   DBusList *dirs;
3406   DBusList *link;
3407   DBusString progs;
3408   DBusString install_root_based;
3409   int i;
3410   dbus_bool_t ret = FALSE;
3411 #ifdef DBUS_WIN
3412   const char *common_progs;
3413 #endif
3414
3415   /* On Unix we don't actually use these, but it's easier to handle the
3416    * deallocation if we always allocate them, whether needed or not */
3417   if (!_dbus_string_init (&progs) ||
3418       !_dbus_string_init (&install_root_based))
3419     _dbus_assert_not_reached ("OOM allocating strings");
3420
3421 #ifdef DBUS_WIN
3422   if (!_dbus_string_append (&install_root_based, DBUS_DATADIR) ||
3423       !_dbus_string_append (&install_root_based, "/dbus-1/services") ||
3424       !_dbus_replace_install_prefix (&install_root_based))
3425     goto out;
3426
3427   _dbus_assert (_dbus_path_is_absolute (&install_root_based));
3428
3429   test_session_service_dir_matches[0] = _dbus_string_get_const_data (
3430       &install_root_based);
3431
3432   common_progs = _dbus_getenv ("CommonProgramFiles");
3433
3434   if (common_progs) 
3435     {
3436       if (!_dbus_string_append (&progs, common_progs)) 
3437         goto out;
3438
3439       if (!_dbus_string_append (&progs, "/dbus-1/services")) 
3440         goto out;
3441
3442       test_session_service_dir_matches[1] = _dbus_string_get_const_data(&progs);
3443     }
3444 #endif
3445   dirs = NULL;
3446
3447   printf ("Testing retrieving the default session service directories\n");
3448   if (!_dbus_get_standard_session_servicedirs (&dirs))
3449     _dbus_assert_not_reached ("couldn't get stardard dirs");
3450
3451   /* make sure our defaults end with share/dbus-1/service */
3452   while ((link = _dbus_list_pop_first_link (&dirs)))
3453     {
3454       DBusString path;
3455       
3456       printf ("    default service dir: %s\n", (char *)link->data);
3457       _dbus_string_init_const (&path, (char *)link->data);
3458       if (!_dbus_string_ends_with_c_str (&path, "dbus-1/services"))
3459         {
3460           printf ("error with default session service directories\n");
3461               dbus_free (link->data);
3462           _dbus_list_free_link (link);
3463           goto out;
3464         }
3465  
3466       dbus_free (link->data);
3467       _dbus_list_free_link (link);
3468     }
3469
3470 #ifdef DBUS_UNIX
3471   if (!dbus_setenv ("XDG_DATA_HOME", "/testhome/foo/.testlocal/testshare"))
3472     _dbus_assert_not_reached ("couldn't setenv XDG_DATA_HOME");
3473
3474   if (!dbus_setenv ("XDG_DATA_DIRS", ":/testusr/testlocal/testshare: :/testusr/testshare:"))
3475     _dbus_assert_not_reached ("couldn't setenv XDG_DATA_DIRS");
3476 #endif
3477   if (!_dbus_get_standard_session_servicedirs (&dirs))
3478     _dbus_assert_not_reached ("couldn't get stardard dirs");
3479
3480   /* make sure we read and parse the env variable correctly */
3481   i = 0;
3482   while ((link = _dbus_list_pop_first_link (&dirs)))
3483     {
3484       printf ("    test service dir: '%s'\n", (char *)link->data);
3485       printf ("    current standard service dir: '%s'\n", test_session_service_dir_matches[i]);
3486       if (test_session_service_dir_matches[i] == NULL)
3487         {
3488           printf ("more directories parsed than in match set\n");
3489           dbus_free (link->data);
3490           _dbus_list_free_link (link);
3491           goto out;
3492         }
3493  
3494       if (strcmp (test_session_service_dir_matches[i], 
3495                   (char *)link->data) != 0)
3496         {
3497           printf ("'%s' directory does not match '%s' in the match set\n",
3498                   (char *)link->data,
3499                   test_session_service_dir_matches[i]);
3500           dbus_free (link->data);
3501           _dbus_list_free_link (link);
3502           goto out;
3503         }
3504
3505       ++i;
3506
3507       dbus_free (link->data);
3508       _dbus_list_free_link (link);
3509     }
3510   
3511   if (test_session_service_dir_matches[i] != NULL)
3512     {
3513       printf ("extra data %s in the match set was not matched\n",
3514               test_session_service_dir_matches[i]);
3515       goto out;
3516     }
3517
3518   ret = TRUE;
3519
3520 out:
3521   _dbus_string_free (&install_root_based);
3522   _dbus_string_free (&progs);
3523   return ret;
3524 }
3525
3526 static const char *test_system_service_dir_matches[] = 
3527         {
3528 #ifdef DBUS_UNIX
3529          "/usr/local/share/dbus-1/system-services",
3530          "/usr/share/dbus-1/system-services",
3531 #endif
3532          DBUS_DATADIR"/dbus-1/system-services",
3533 #ifdef DBUS_UNIX
3534          "/lib/dbus-1/system-services",
3535 #endif
3536
3537 #ifdef DBUS_WIN
3538          NULL,
3539 #endif
3540          NULL
3541         };
3542
3543 static dbus_bool_t
3544 test_default_system_servicedirs (void)
3545 {
3546   DBusList *dirs;
3547   DBusList *link;
3548   DBusString progs;
3549 #ifndef DBUS_UNIX
3550   const char *common_progs;
3551 #endif
3552   int i;
3553
3554   /* On Unix we don't actually use this variable, but it's easier to handle the
3555    * deallocation if we always allocate it, whether needed or not */
3556   if (!_dbus_string_init (&progs))
3557     _dbus_assert_not_reached ("OOM allocating progs");
3558
3559 #ifndef DBUS_UNIX
3560   common_progs = _dbus_getenv ("CommonProgramFiles");
3561
3562   if (common_progs) 
3563     {
3564       if (!_dbus_string_append (&progs, common_progs)) 
3565         {
3566           _dbus_string_free (&progs);
3567           return FALSE;
3568         }
3569
3570       if (!_dbus_string_append (&progs, "/dbus-1/system-services")) 
3571         {
3572           _dbus_string_free (&progs);
3573           return FALSE;
3574         }
3575       test_system_service_dir_matches[1] = _dbus_string_get_const_data(&progs);
3576     }
3577 #endif
3578   dirs = NULL;
3579
3580   printf ("Testing retrieving the default system service directories\n");
3581   if (!_dbus_get_standard_system_servicedirs (&dirs))
3582     _dbus_assert_not_reached ("couldn't get stardard dirs");
3583
3584   /* make sure our defaults end with share/dbus-1/system-service */
3585   while ((link = _dbus_list_pop_first_link (&dirs)))
3586     {
3587       DBusString path;
3588       
3589       printf ("    default service dir: %s\n", (char *)link->data);
3590       _dbus_string_init_const (&path, (char *)link->data);
3591       if (!_dbus_string_ends_with_c_str (&path, "dbus-1/system-services"))
3592         {
3593           printf ("error with default system service directories\n");
3594               dbus_free (link->data);
3595           _dbus_list_free_link (link);
3596           _dbus_string_free (&progs);
3597           return FALSE;
3598         }
3599  
3600       dbus_free (link->data);
3601       _dbus_list_free_link (link);
3602     }
3603
3604 #ifdef DBUS_UNIX
3605   if (!dbus_setenv ("XDG_DATA_HOME", "/testhome/foo/.testlocal/testshare"))
3606     _dbus_assert_not_reached ("couldn't setenv XDG_DATA_HOME");
3607
3608   if (!dbus_setenv ("XDG_DATA_DIRS", ":/testusr/testlocal/testshare: :/testusr/testshare:"))
3609     _dbus_assert_not_reached ("couldn't setenv XDG_DATA_DIRS");
3610 #endif
3611   if (!_dbus_get_standard_system_servicedirs (&dirs))
3612     _dbus_assert_not_reached ("couldn't get stardard dirs");
3613
3614   /* make sure we read and parse the env variable correctly */
3615   i = 0;
3616   while ((link = _dbus_list_pop_first_link (&dirs)))
3617     {
3618       printf ("    test service dir: %s\n", (char *)link->data);
3619       if (test_system_service_dir_matches[i] == NULL)
3620         {
3621           printf ("more directories parsed than in match set\n");
3622           dbus_free (link->data);
3623           _dbus_list_free_link (link);
3624           _dbus_string_free (&progs);
3625           return FALSE;
3626         }
3627  
3628       if (strcmp (test_system_service_dir_matches[i], 
3629                   (char *)link->data) != 0)
3630         {
3631           printf ("%s directory does not match %s in the match set\n", 
3632                   (char *)link->data,
3633                   test_system_service_dir_matches[i]);
3634           dbus_free (link->data);
3635           _dbus_list_free_link (link);
3636           _dbus_string_free (&progs);
3637           return FALSE;
3638         }
3639
3640       ++i;
3641
3642       dbus_free (link->data);
3643       _dbus_list_free_link (link);
3644     }
3645   
3646   if (test_system_service_dir_matches[i] != NULL)
3647     {
3648       printf ("extra data %s in the match set was not matched\n",
3649               test_system_service_dir_matches[i]);
3650
3651       _dbus_string_free (&progs);
3652       return FALSE;
3653     }
3654     
3655   _dbus_string_free (&progs);
3656   return TRUE;
3657 }
3658                    
3659 dbus_bool_t
3660 bus_config_parser_test (const DBusString *test_data_dir)
3661 {
3662   if (test_data_dir == NULL ||
3663       _dbus_string_get_length (test_data_dir) == 0)
3664     {
3665       printf ("No test data\n");
3666       return TRUE;
3667     }
3668
3669   if (!test_default_session_servicedirs())
3670     return FALSE;
3671
3672 #ifdef DBUS_WIN
3673   printf("default system service dir skipped\n");
3674 #else
3675   if (!test_default_system_servicedirs())
3676     return FALSE;
3677 #endif
3678
3679   if (!process_test_valid_subdir (test_data_dir, "valid-config-files", VALID))
3680     return FALSE;
3681
3682 #ifndef DBUS_WIN
3683   if (!process_test_valid_subdir (test_data_dir, "valid-config-files-system", VALID))
3684     return FALSE;
3685 #endif
3686
3687   if (!process_test_valid_subdir (test_data_dir, "invalid-config-files", INVALID))
3688     return FALSE;
3689
3690   if (!process_test_equiv_subdir (test_data_dir, "equiv-config-files"))
3691     return FALSE;
3692
3693   return TRUE;
3694 }
3695
3696 #endif /* DBUS_ENABLE_EMBEDDED_TESTS */
3697