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