Merge dbus-1.12.16 into tizen
[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 = 512; /* 256 -> 512 */
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 = 1024; /* 128 -> 1024 */
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 25
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       DBusError local_error = DBUS_ERROR_INIT;
901       DBusList *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_set_up_transient_session_servicedirs (&dirs, &local_error))
913         {
914           if (!service_dirs_absorb_string_list (&parser->service_dirs, &dirs,
915                 BUS_SERVICE_DIR_FLAGS_NO_WATCH |
916                 BUS_SERVICE_DIR_FLAGS_STRICT_NAMING))
917             {
918               BUS_SET_OOM (error);
919               _dbus_list_foreach (&dirs, (DBusForeachFunction) dbus_free,
920                   NULL);
921               _dbus_list_clear (&dirs);
922               return FALSE;
923             }
924         }
925       else
926         {
927           /* Failing to set these up isn't fatal */
928           _dbus_warn ("Unable to set up transient service directory: %s",
929                       local_error.message);
930           dbus_error_free (&local_error);
931         }
932
933       _dbus_assert (dirs == NULL);
934
935       if (!_dbus_get_standard_session_servicedirs (&dirs))
936         {
937           BUS_SET_OOM (error);
938           return FALSE;
939         }
940
941       /* We have traditionally watched the standard session service
942        * directories with inotify, and allowed service files whose names do not
943        * match the bus name */
944       if (!service_dirs_absorb_string_list (&parser->service_dirs, &dirs,
945                                             BUS_SERVICE_DIR_FLAGS_NONE))
946         {
947           BUS_SET_OOM (error);
948           _dbus_list_foreach (&dirs, (DBusForeachFunction) dbus_free,
949               NULL);
950           _dbus_list_clear (&dirs);
951           return FALSE;
952         }
953
954       _dbus_assert (dirs == NULL);
955
956       return TRUE;
957     }
958   else if (element_type == ELEMENT_STANDARD_SYSTEM_SERVICEDIRS)
959     {
960       DBusList *dirs;
961       dirs = NULL;
962
963       if (!check_no_attributes (parser, "standard_system_servicedirs", attribute_names, attribute_values, error))
964         return FALSE;
965
966       if (push_element (parser, ELEMENT_STANDARD_SYSTEM_SERVICEDIRS) == NULL)
967         {
968           BUS_SET_OOM (error);
969           return FALSE;
970         }
971
972       if (!_dbus_get_standard_system_servicedirs (&dirs))
973         {
974           BUS_SET_OOM (error);
975           return FALSE;
976         }
977
978       /* We have traditionally watched the standard system service
979        * directories with inotify, and allowed service files whose names do not
980        * match the bus name (the servicehelper won't successfully activate
981        * them, but we do still parse them) */
982       if (!service_dirs_absorb_string_list (&parser->service_dirs, &dirs,
983                                             BUS_SERVICE_DIR_FLAGS_NONE))
984         {
985           BUS_SET_OOM (error);
986           _dbus_list_foreach (&dirs, (DBusForeachFunction) dbus_free,
987               NULL);
988           _dbus_list_clear (&dirs);
989           return FALSE;
990         }
991
992       return TRUE;
993     }
994   else if (element_type == ELEMENT_ALLOW_ANONYMOUS)
995     {
996       if (!check_no_attributes (parser, "allow_anonymous", attribute_names, attribute_values, error))
997         return FALSE;
998
999       if (push_element (parser, ELEMENT_ALLOW_ANONYMOUS) == NULL)
1000         {
1001           BUS_SET_OOM (error);
1002           return FALSE;
1003         }
1004
1005       parser->allow_anonymous = TRUE;
1006       return TRUE;
1007     }
1008   else if (element_type == ELEMENT_SERVICEDIR)
1009     {
1010       if (!check_no_attributes (parser, "servicedir", attribute_names, attribute_values, error))
1011         return FALSE;
1012
1013       if (push_element (parser, ELEMENT_SERVICEDIR) == NULL)
1014         {
1015           BUS_SET_OOM (error);
1016           return FALSE;
1017         }
1018
1019       return TRUE;
1020     }
1021   else if (element_type == ELEMENT_INCLUDE)
1022     {
1023       Element *e;
1024       const char *if_selinux_enabled;
1025       const char *ignore_missing;
1026       const char *selinux_root_relative;
1027
1028       if ((e = push_element (parser, ELEMENT_INCLUDE)) == NULL)
1029         {
1030           BUS_SET_OOM (error);
1031           return FALSE;
1032         }
1033
1034       e->d.include.ignore_missing = FALSE;
1035       e->d.include.if_selinux_enabled = FALSE;
1036       e->d.include.selinux_root_relative = FALSE;
1037
1038       if (!locate_attributes (parser, "include",
1039                               attribute_names,
1040                               attribute_values,
1041                               error,
1042                               "ignore_missing", &ignore_missing,
1043                               "if_selinux_enabled", &if_selinux_enabled,
1044                               "selinux_root_relative", &selinux_root_relative,
1045                               NULL))
1046         return FALSE;
1047
1048       if (ignore_missing != NULL)
1049         {
1050           if (strcmp (ignore_missing, "yes") == 0)
1051             e->d.include.ignore_missing = TRUE;
1052           else if (strcmp (ignore_missing, "no") == 0)
1053             e->d.include.ignore_missing = FALSE;
1054           else
1055             {
1056               dbus_set_error (error, DBUS_ERROR_FAILED,
1057                               "ignore_missing attribute must have value \"yes\" or \"no\"");
1058               return FALSE;
1059             }
1060         }
1061
1062       if (if_selinux_enabled != NULL)
1063         {
1064           if (strcmp (if_selinux_enabled, "yes") == 0)
1065             e->d.include.if_selinux_enabled = TRUE;
1066           else if (strcmp (if_selinux_enabled, "no") == 0)
1067             e->d.include.if_selinux_enabled = FALSE;
1068           else
1069             {
1070               dbus_set_error (error, DBUS_ERROR_FAILED,
1071                               "if_selinux_enabled attribute must have value"
1072                               " \"yes\" or \"no\"");
1073               return FALSE;
1074             }
1075         }
1076       
1077       if (selinux_root_relative != NULL)
1078         {
1079           if (strcmp (selinux_root_relative, "yes") == 0)
1080             e->d.include.selinux_root_relative = TRUE;
1081           else if (strcmp (selinux_root_relative, "no") == 0)
1082             e->d.include.selinux_root_relative = FALSE;
1083           else
1084             {
1085               dbus_set_error (error, DBUS_ERROR_FAILED,
1086                               "selinux_root_relative attribute must have value"
1087                               " \"yes\" or \"no\"");
1088               return FALSE;
1089             }
1090         }
1091
1092       return TRUE;
1093     }
1094   else if (element_type == ELEMENT_POLICY)
1095     {
1096       Element *e;
1097       const char *context;
1098       const char *user;
1099       const char *group;
1100       const char *at_console;
1101
1102       if ((e = push_element (parser, ELEMENT_POLICY)) == NULL)
1103         {
1104           BUS_SET_OOM (error);
1105           return FALSE;
1106         }
1107
1108       e->d.policy.type = POLICY_IGNORED;
1109       
1110       if (!locate_attributes (parser, "policy",
1111                               attribute_names,
1112                               attribute_values,
1113                               error,
1114                               "context", &context,
1115                               "user", &user,
1116                               "group", &group,
1117                               "at_console", &at_console,
1118                               NULL))
1119         return FALSE;
1120
1121       if (((context && user) ||
1122            (context && group) ||
1123            (context && at_console)) ||
1124            ((user && group) ||
1125            (user && at_console)) ||
1126            (group && at_console) ||
1127           !(context || user || group || at_console))
1128         {
1129           dbus_set_error (error, DBUS_ERROR_FAILED,
1130                           "<policy> element must have exactly one of (context|user|group|at_console) attributes");
1131           return FALSE;
1132         }
1133
1134       if (context != NULL)
1135         {
1136           if (strcmp (context, "default") == 0)
1137             {
1138               e->d.policy.type = POLICY_DEFAULT;
1139             }
1140           else if (strcmp (context, "mandatory") == 0)
1141             {
1142               e->d.policy.type = POLICY_MANDATORY;
1143             }
1144           else
1145             {
1146               dbus_set_error (error, DBUS_ERROR_FAILED,
1147                               "context attribute on <policy> must have the value \"default\" or \"mandatory\", not \"%s\"",
1148                               context);
1149               return FALSE;
1150             }
1151         }
1152       else if (user != NULL)
1153         {
1154           DBusString username;
1155           _dbus_string_init_const (&username, user);
1156
1157           if (_dbus_parse_unix_user_from_config (&username,
1158                                                  &e->d.policy.gid_uid_or_at_console))
1159             e->d.policy.type = POLICY_USER;
1160           else
1161             _dbus_warn ("Unknown username \"%s\" in message bus configuration file",
1162                         user);
1163         }
1164       else if (group != NULL)
1165         {
1166           DBusString group_name;
1167           _dbus_string_init_const (&group_name, group);
1168
1169           if (_dbus_parse_unix_group_from_config (&group_name,
1170                                                   &e->d.policy.gid_uid_or_at_console))
1171             e->d.policy.type = POLICY_GROUP;
1172           else
1173             _dbus_warn ("Unknown group \"%s\" in message bus configuration file",
1174                         group);          
1175         }
1176       else if (at_console != NULL)
1177         {
1178            dbus_bool_t t;
1179            t = (strcmp (at_console, "true") == 0);
1180            if (t || strcmp (at_console, "false") == 0)
1181              {
1182                e->d.policy.gid_uid_or_at_console = t; 
1183                e->d.policy.type = POLICY_CONSOLE;
1184              }  
1185            else
1186              {
1187                dbus_set_error (error, DBUS_ERROR_FAILED,
1188                               "Unknown value \"%s\" for at_console in message bus configuration file",
1189                               at_console);
1190
1191                return FALSE;
1192              }
1193         }
1194       else
1195         {
1196           _dbus_assert_not_reached ("all <policy> attributes null and we didn't set error");
1197         }
1198       
1199       return TRUE;
1200     }
1201   else if (element_type == ELEMENT_LIMIT)
1202     {
1203       Element *e;
1204       const char *name;
1205
1206       if ((e = push_element (parser, ELEMENT_LIMIT)) == NULL)
1207         {
1208           BUS_SET_OOM (error);
1209           return FALSE;
1210         }
1211       
1212       if (!locate_attributes (parser, "limit",
1213                               attribute_names,
1214                               attribute_values,
1215                               error,
1216                               "name", &name,
1217                               NULL))
1218         return FALSE;
1219
1220       if (name == NULL)
1221         {
1222           dbus_set_error (error, DBUS_ERROR_FAILED,
1223                           "<limit> element must have a \"name\" attribute");
1224           return FALSE;
1225         }
1226
1227       e->d.limit.name = _dbus_strdup (name);
1228       if (e->d.limit.name == NULL)
1229         {
1230           BUS_SET_OOM (error);
1231           return FALSE;
1232         }
1233
1234       return TRUE;
1235     }
1236   else if (element_type == ELEMENT_SELINUX)
1237     {
1238       if (!check_no_attributes (parser, "selinux", attribute_names, attribute_values, error))
1239         return FALSE;
1240
1241       if (push_element (parser, ELEMENT_SELINUX) == NULL)
1242         {
1243           BUS_SET_OOM (error);
1244           return FALSE;
1245         }
1246
1247       return TRUE;
1248     }
1249   else if (element_type == ELEMENT_APPARMOR)
1250     {
1251       Element *e;
1252       const char *mode;
1253
1254       if ((e = push_element (parser, ELEMENT_APPARMOR)) == NULL)
1255         {
1256           BUS_SET_OOM (error);
1257           return FALSE;
1258         }
1259
1260       if (!locate_attributes (parser, "apparmor",
1261                               attribute_names,
1262                               attribute_values,
1263                               error,
1264                               "mode", &mode,
1265                               NULL))
1266         return FALSE;
1267
1268       return bus_apparmor_set_mode_from_config (mode, error);
1269     }
1270   else
1271     {
1272       dbus_set_error (error, DBUS_ERROR_FAILED,
1273                       "Element <%s> not allowed inside <%s> in configuration file",
1274                       element_name, "busconfig");
1275       return FALSE;
1276     }
1277 }
1278
1279 /*
1280  * Parse an attribute named name, whose content is content, or NULL if
1281  * missing. It is meant to be a (long) integer between min and max inclusive.
1282  * If it is missing, use def as the default value (which does not
1283  * necessarily need to be between min and max).
1284  */
1285 static dbus_bool_t
1286 parse_int_attribute (const char *name,
1287                      const char *content,
1288                      long        min,
1289                      long        max,
1290                      long        def,
1291                      long       *value,
1292                      DBusError  *error)
1293 {
1294   DBusString parse_string;
1295
1296   *value = def;
1297
1298   if (content == NULL)
1299     return TRUE;
1300
1301   _dbus_string_init_const (&parse_string, content);
1302
1303   if (!_dbus_string_parse_int (&parse_string, 0, value, NULL) ||
1304       *value < min || *value > max)
1305     {
1306       dbus_set_error (error, DBUS_ERROR_FAILED,
1307                       "Bad value \"%s\" for %s attribute, must be an "
1308                       "integer in range %ld to %ld inclusive",
1309                       content, name, min, max);
1310       return FALSE;
1311     }
1312
1313   return TRUE;
1314 }
1315
1316 static dbus_bool_t
1317 append_rule_from_element (BusConfigParser   *parser,
1318                           const char        *element_name,
1319                           const char       **attribute_names,
1320                           const char       **attribute_values,
1321                           BusPolicyRuleAccess access,
1322                           DBusError         *error)
1323 {
1324   const char *log;
1325
1326   /* Group: send_ attributes */
1327   const char *send_interface;
1328   const char *send_member;
1329   const char *send_error;
1330   const char *send_destination;
1331   const char *send_destination_prefix;
1332   const char *send_path;
1333   const char *send_type;
1334   const char *send_requested_reply;
1335   const char *send_broadcast;
1336   /* TRUE if any send_ attribute is present */
1337   dbus_bool_t any_send_attribute;
1338
1339   /* Group: receive_ attributes */
1340   const char *receive_interface;
1341   const char *receive_member;
1342   const char *receive_error;
1343   const char *receive_sender;
1344   const char *receive_path;
1345   const char *receive_type;
1346   const char *receive_requested_reply;
1347   /* TRUE if any receive_ attribute is present */
1348   dbus_bool_t any_receive_attribute;
1349
1350   /* Group: message-matching modifiers that can go on send_ or receive_ */
1351   const char *eavesdrop;
1352   const char *max_fds_attr;
1353   long max_fds = DBUS_MAXIMUM_MESSAGE_UNIX_FDS;
1354   const char *min_fds_attr;
1355   long min_fds = 0;
1356   /* TRUE if any message-matching modifier is present */
1357   dbus_bool_t any_message_attribute;
1358
1359   /* Non-message-related attributes */
1360   const char *own;
1361   const char *own_prefix;
1362   const char *user;
1363   const char *group;
1364   const char *privilege;
1365
1366   BusPolicyRule *rule;
1367
1368   if (!locate_attributes (parser, element_name,
1369                           attribute_names,
1370                           attribute_values,
1371                           error,
1372                           "send_interface", &send_interface,
1373                           "send_member", &send_member,
1374                           "send_error", &send_error,
1375                           "send_destination", &send_destination,
1376                           "send_destination_prefix", &send_destination_prefix,
1377                           "send_path", &send_path,
1378                           "send_type", &send_type,
1379                           "send_broadcast", &send_broadcast,
1380                           "receive_interface", &receive_interface,
1381                           "receive_member", &receive_member,
1382                           "receive_error", &receive_error,
1383                           "receive_sender", &receive_sender,
1384                           "receive_path", &receive_path,
1385                           "receive_type", &receive_type,
1386                           "eavesdrop", &eavesdrop,
1387                           "max_fds", &max_fds_attr,
1388                           "min_fds", &min_fds_attr,
1389                           "send_requested_reply", &send_requested_reply,
1390                           "receive_requested_reply", &receive_requested_reply,
1391                           "own", &own,
1392                           "own_prefix", &own_prefix,
1393                           "user", &user,
1394                           "group", &group,
1395                           "log", &log,
1396                           "privilege", &privilege,
1397                           NULL))
1398     return FALSE;
1399
1400   any_send_attribute = (send_destination != NULL ||
1401                         send_destination_prefix != NULL ||
1402                         send_broadcast != NULL ||
1403                         send_path != NULL ||
1404                         send_type != NULL ||
1405                         send_interface != NULL ||
1406                         send_member != NULL ||
1407                         send_error != NULL ||
1408                         send_requested_reply != NULL);
1409   any_receive_attribute = (receive_sender != NULL ||
1410                            receive_path != NULL ||
1411                            receive_type != NULL ||
1412                            receive_interface != NULL ||
1413                            receive_member != NULL ||
1414                            receive_error != NULL ||
1415                            receive_requested_reply != NULL ||
1416                            /* <allow eavesdrop="true"/> means the same as
1417                             * <allow receive_sender="*" eavesdrop="true"/>,
1418                             * but <allow send_anything="anything"/> can also
1419                             * take the eavesdrop attribute and still counts
1420                             * as a send rule. */
1421                            (!any_send_attribute && eavesdrop != NULL));
1422   any_message_attribute = (any_send_attribute ||
1423                            any_receive_attribute ||
1424                            eavesdrop != NULL ||
1425                            max_fds_attr != NULL ||
1426                            min_fds_attr != NULL);
1427
1428   if (!(any_send_attribute ||
1429         any_receive_attribute ||
1430         privilege ||
1431         own || own_prefix || user || group))
1432     {
1433       dbus_set_error (error, DBUS_ERROR_FAILED,
1434                       "Element <%s> must have one or more attributes",
1435                       element_name);
1436       return FALSE;
1437     }
1438
1439   if ((send_member && (send_interface == NULL && send_path == NULL)) ||
1440       (receive_member && (receive_interface == NULL && receive_path == NULL)))
1441     {
1442       dbus_set_error (error, DBUS_ERROR_FAILED,
1443                       "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.",
1444                       element_name);
1445       return FALSE;
1446     }
1447
1448   if (access == BUS_POLICY_RULE_ACCESS_CHECK)
1449     {
1450       if (privilege == NULL || !*privilege)
1451         {
1452           dbus_set_error (error, DBUS_ERROR_FAILED,
1453                           "On element <%s>, you must specify the privilege to be checked.",
1454                           element_name);
1455           return FALSE;
1456         }
1457     }
1458   else
1459     {
1460       if (privilege != NULL && *privilege)
1461         {
1462           dbus_set_error (error, DBUS_ERROR_FAILED,
1463                           "On element <%s>, privilege %s is used outside of a check rule.",
1464                           element_name, privilege);
1465           return FALSE;
1466         }
1467       else
1468         privilege = NULL; /* replace (potentially) empty string with NULL pointer, it wouldn't be used anyway */
1469     }
1470
1471   /* Allowed combinations of elements are:
1472    *
1473    *   base, must be all send or all receive:
1474    *     nothing
1475    *     interface
1476    *     interface + member
1477    *     error
1478    * 
1479    *   base send_ can combine with send_destination, send_destination_prefix, send_path, send_type, send_requested_reply, send_broadcast, eavesdrop
1480    *   send_destination must not occur with send_destination_prefix
1481    *   base receive_ with receive_sender, receive_path, receive_type, receive_requested_reply, eavesdrop
1482    *
1483    *   user, group, own, own_prefix must occur alone
1484    */
1485
1486   if (any_message_attribute +
1487       ((own != NULL) +
1488        (own_prefix != NULL) +
1489        (user != NULL) +
1490        (group != NULL)) > 1)
1491     {
1492       dbus_set_error (error, DBUS_ERROR_FAILED,
1493                       "Invalid combination of attributes on element <%s>: "
1494                       "own, own_prefix, user, group and the message-related "
1495                       "attributes cannot be combined",
1496                       element_name);
1497       return FALSE;
1498     }
1499
1500   if (any_send_attribute && any_receive_attribute)
1501     {
1502       dbus_set_error (error, DBUS_ERROR_FAILED,
1503                       "Invalid combination of attributes on element <%s>: "
1504                       "send and receive attributes cannot be combined",
1505                       element_name);
1506       return FALSE;
1507     }
1508
1509   if ((send_member != NULL || send_interface != NULL) && send_error != NULL)
1510     {
1511       dbus_set_error (error, DBUS_ERROR_FAILED,
1512                       "Invalid combination of attributes on element <%s>: "
1513                       "send_error cannot be combined with send_member or "
1514                       "send_interface",
1515                       element_name);
1516       return FALSE;
1517     }
1518
1519   if ((receive_member != NULL || receive_interface != NULL) &&
1520       receive_error != NULL)
1521     {
1522       dbus_set_error (error, DBUS_ERROR_FAILED,
1523                       "Invalid combination of attributes on element <%s>: "
1524                       "receive_error cannot be combined with receive_member "
1525                       "or receive_interface",
1526                       element_name);
1527       return FALSE;
1528     }
1529
1530   rule = NULL;
1531
1532   /* In BusPolicyRule, NULL represents wildcard.
1533    * In the config file, '*' represents it.
1534    */
1535 #define IS_WILDCARD(str) ((str) && ((str)[0]) == '*' && ((str)[1]) == '\0')
1536
1537   if (any_send_attribute)
1538     {
1539       int message_type;
1540       
1541       if (IS_WILDCARD (send_interface))
1542         send_interface = NULL;
1543       if (IS_WILDCARD (send_member))
1544         send_member = NULL;
1545       if (IS_WILDCARD (send_error))
1546         send_error = NULL;
1547       if (IS_WILDCARD (send_destination))
1548         send_destination = NULL;
1549       if (IS_WILDCARD (send_path))
1550         send_path = NULL;
1551       if (IS_WILDCARD (send_type))
1552         send_type = NULL;
1553
1554       message_type = DBUS_MESSAGE_TYPE_INVALID;
1555       if (send_type != NULL)
1556         {
1557           message_type = dbus_message_type_from_string (send_type);
1558           if (message_type == DBUS_MESSAGE_TYPE_INVALID)
1559             {
1560               dbus_set_error (error, DBUS_ERROR_FAILED,
1561                               "Bad message type \"%s\"",
1562                               send_type);
1563               return FALSE;
1564             }
1565         }
1566
1567       if (eavesdrop &&
1568           !(strcmp (eavesdrop, "true") == 0 ||
1569             strcmp (eavesdrop, "false") == 0))
1570         {
1571           dbus_set_error (error, DBUS_ERROR_FAILED,
1572                           "Bad value \"%s\" for %s attribute, must be true or false",
1573                           "eavesdrop", eavesdrop);
1574           return FALSE;
1575         }
1576
1577       if (send_broadcast &&
1578           !(strcmp (send_broadcast, "true") == 0 ||
1579             strcmp (send_broadcast, "false") == 0))
1580         {
1581           dbus_set_error (error, DBUS_ERROR_FAILED,
1582                           "Bad value \"%s\" for %s attribute, must be true or false",
1583                           send_broadcast, "send_broadcast");
1584           return FALSE;
1585         }
1586
1587       if (send_destination != NULL &&
1588           send_broadcast != NULL &&
1589           strcmp (send_broadcast, "true") == 0)
1590         {
1591           /* Broadcast messages have no destination, so this cannot
1592            * possibly match */
1593           dbus_set_error (error, DBUS_ERROR_FAILED,
1594                           "Rule with send_broadcast=\"true\" and "
1595                           "send_destination=\"%s\" cannot match anything",
1596                           send_destination);
1597           return FALSE;
1598         }
1599
1600       if (send_requested_reply &&
1601           !(strcmp (send_requested_reply, "true") == 0 ||
1602             strcmp (send_requested_reply, "false") == 0))
1603         {
1604           dbus_set_error (error, DBUS_ERROR_FAILED,
1605                           "Bad value \"%s\" for %s attribute, must be true or false",
1606                           "send_requested_reply", send_requested_reply);
1607           return FALSE;
1608         }
1609
1610       /* Matching only messages with DBUS_MAXIMUM_MESSAGE_UNIX_FDS or fewer
1611        * fds is the same as matching all messages, so we always set a maximum,
1612        * but perhaps an unrealistically high one. */
1613       if (!parse_int_attribute ("max_fds", max_fds_attr,
1614                                 0, DBUS_MAXIMUM_MESSAGE_UNIX_FDS,
1615                                 DBUS_MAXIMUM_MESSAGE_UNIX_FDS, &max_fds,
1616                                 error) ||
1617           !parse_int_attribute ("min_fds", min_fds_attr,
1618                                 0, DBUS_MAXIMUM_MESSAGE_UNIX_FDS, 0, &min_fds,
1619                                 error))
1620         return FALSE;
1621
1622       rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, access);
1623       if (rule == NULL)
1624         goto nomem;
1625       
1626       if (eavesdrop)
1627         rule->d.send.eavesdrop = (strcmp (eavesdrop, "true") == 0);
1628
1629       if (log)
1630         rule->d.send.log = (strcmp (log, "true") == 0);
1631
1632       if (send_requested_reply)
1633         rule->d.send.requested_reply = (strcmp (send_requested_reply, "true") == 0);
1634
1635       if (send_broadcast)
1636         {
1637           if (strcmp (send_broadcast, "true") == 0)
1638             rule->d.send.broadcast = BUS_POLICY_TRISTATE_TRUE;
1639           else
1640             rule->d.send.broadcast = BUS_POLICY_TRISTATE_FALSE;
1641         }
1642       else
1643         {
1644           rule->d.send.broadcast = BUS_POLICY_TRISTATE_ANY;
1645         }
1646
1647       rule->d.send.message_type = message_type;
1648       rule->d.send.path = _dbus_strdup (send_path);
1649       rule->d.send.interface = _dbus_strdup (send_interface);
1650       rule->d.send.member = _dbus_strdup (send_member);
1651       rule->d.send.error = _dbus_strdup (send_error);
1652       if (send_destination)
1653         {
1654           rule->d.send.destination = _dbus_strdup (send_destination);
1655           rule->d.send.destination_prefix = 0;
1656         }
1657       else if (send_destination_prefix)
1658         {
1659           rule->d.send.destination = _dbus_strdup (send_destination_prefix);
1660           rule->d.send.destination_prefix = 1;
1661         }
1662       rule->d.send.max_fds = max_fds;
1663       rule->d.send.min_fds = min_fds;
1664
1665       if (send_path && rule->d.send.path == NULL)
1666         goto nomem;
1667       if (send_interface && rule->d.send.interface == NULL)
1668         goto nomem;
1669       if (send_member && rule->d.send.member == NULL)
1670         goto nomem;
1671       if (send_error && rule->d.send.error == NULL)
1672         goto nomem;
1673       if ((send_destination || send_destination_prefix) && rule->d.send.destination == NULL)
1674         goto nomem;
1675     }
1676   else if (any_receive_attribute)
1677     {
1678       int message_type;
1679       
1680       if (IS_WILDCARD (receive_interface))
1681         receive_interface = NULL;
1682       if (IS_WILDCARD (receive_member))
1683         receive_member = NULL;
1684       if (IS_WILDCARD (receive_error))
1685         receive_error = NULL;
1686       if (IS_WILDCARD (receive_sender))
1687         receive_sender = NULL;
1688       if (IS_WILDCARD (receive_path))
1689         receive_path = NULL;
1690       if (IS_WILDCARD (receive_type))
1691         receive_type = NULL;
1692
1693       message_type = DBUS_MESSAGE_TYPE_INVALID;
1694       if (receive_type != NULL)
1695         {
1696           message_type = dbus_message_type_from_string (receive_type);
1697           if (message_type == DBUS_MESSAGE_TYPE_INVALID)
1698             {
1699               dbus_set_error (error, DBUS_ERROR_FAILED,
1700                               "Bad message type \"%s\"",
1701                               receive_type);
1702               return FALSE;
1703             }
1704         }
1705
1706
1707       if (eavesdrop &&
1708           !(strcmp (eavesdrop, "true") == 0 ||
1709             strcmp (eavesdrop, "false") == 0))
1710         {
1711           dbus_set_error (error, DBUS_ERROR_FAILED,
1712                           "Bad value \"%s\" for %s attribute, must be true or false",
1713                           "eavesdrop", eavesdrop);
1714           return FALSE;
1715         }
1716
1717       if (receive_requested_reply &&
1718           !(strcmp (receive_requested_reply, "true") == 0 ||
1719             strcmp (receive_requested_reply, "false") == 0))
1720         {
1721           dbus_set_error (error, DBUS_ERROR_FAILED,
1722                           "Bad value \"%s\" for %s attribute, must be true or false",
1723                           "receive_requested_reply", receive_requested_reply);
1724           return FALSE;
1725         }
1726
1727       if (!parse_int_attribute ("max_fds", max_fds_attr,
1728                                 0, DBUS_MAXIMUM_MESSAGE_UNIX_FDS,
1729                                 DBUS_MAXIMUM_MESSAGE_UNIX_FDS, &max_fds,
1730                                 error) ||
1731           !parse_int_attribute ("min_fds", min_fds_attr,
1732                                 0, DBUS_MAXIMUM_MESSAGE_UNIX_FDS, 0, &min_fds,
1733                                 error))
1734         return FALSE;
1735
1736       rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, access);
1737       if (rule == NULL)
1738         goto nomem;
1739
1740       if (eavesdrop)
1741         rule->d.receive.eavesdrop = (strcmp (eavesdrop, "true") == 0);
1742
1743       if (receive_requested_reply)
1744         rule->d.receive.requested_reply = (strcmp (receive_requested_reply, "true") == 0);
1745       
1746       rule->d.receive.message_type = message_type;
1747       rule->d.receive.path = _dbus_strdup (receive_path);
1748       rule->d.receive.interface = _dbus_strdup (receive_interface);
1749       rule->d.receive.member = _dbus_strdup (receive_member);
1750       rule->d.receive.error = _dbus_strdup (receive_error);
1751       rule->d.receive.origin = _dbus_strdup (receive_sender);
1752       rule->d.receive.max_fds = max_fds;
1753       rule->d.receive.min_fds = min_fds;
1754
1755       if (receive_path && rule->d.receive.path == NULL)
1756         goto nomem;
1757       if (receive_interface && rule->d.receive.interface == NULL)
1758         goto nomem;
1759       if (receive_member && rule->d.receive.member == NULL)
1760         goto nomem;
1761       if (receive_error && rule->d.receive.error == NULL)
1762         goto nomem;
1763       if (receive_sender && rule->d.receive.origin == NULL)
1764         goto nomem;
1765     }
1766   else if (own || own_prefix)
1767     {
1768       rule = bus_policy_rule_new (BUS_POLICY_RULE_OWN, access);
1769       if (rule == NULL)
1770         goto nomem;
1771
1772       if (own)
1773         {
1774           if (IS_WILDCARD (own))
1775             own = NULL;
1776       
1777           rule->d.own.prefix = 0;
1778           rule->d.own.service_name = _dbus_strdup (own);
1779           if (own && rule->d.own.service_name == NULL)
1780             goto nomem;
1781         }
1782       else
1783         {
1784           rule->d.own.prefix = 1;
1785           rule->d.own.service_name = _dbus_strdup (own_prefix);
1786           if (rule->d.own.service_name == NULL)
1787             goto nomem;
1788         }
1789     }
1790   else if (user)
1791     {      
1792       if (IS_WILDCARD (user))
1793         {
1794           rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, access);
1795           if (rule == NULL)
1796             goto nomem;
1797
1798           rule->d.user.uid = DBUS_UID_UNSET;
1799         }
1800       else
1801         {
1802           DBusString username;
1803           dbus_uid_t uid;
1804           
1805           _dbus_string_init_const (&username, user);
1806       
1807           if (_dbus_parse_unix_user_from_config (&username, &uid))
1808             {
1809               rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, access);
1810               if (rule == NULL)
1811                 goto nomem;
1812
1813               rule->d.user.uid = uid;
1814             }
1815           else
1816             {
1817               _dbus_warn ("Unknown username \"%s\" on element <%s>",
1818                           user, element_name);
1819             }
1820         }
1821     }
1822   else if (group)
1823     {
1824       if (IS_WILDCARD (group))
1825         {
1826           rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, access);
1827           if (rule == NULL)
1828             goto nomem;
1829
1830           rule->d.group.gid = DBUS_GID_UNSET;
1831         }
1832       else
1833         {
1834           DBusString groupname;
1835           dbus_gid_t gid;
1836           
1837           _dbus_string_init_const (&groupname, group);
1838           
1839           if (_dbus_parse_unix_group_from_config (&groupname, &gid))
1840             {
1841               rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, access);
1842               if (rule == NULL)
1843                 goto nomem;
1844
1845               rule->d.group.gid = gid;
1846             }
1847           else
1848             {
1849               _dbus_warn ("Unknown group \"%s\" on element <%s>",
1850                           group, element_name);
1851             }
1852         }
1853     }
1854   else
1855     _dbus_assert_not_reached ("Did not handle some combination of attributes on <allow> or <deny>");
1856
1857   if (rule != NULL)
1858     {
1859       Element *pe;
1860       
1861       pe = peek_element (parser);      
1862       _dbus_assert (pe != NULL);
1863       _dbus_assert (pe->type == ELEMENT_POLICY);
1864
1865       rule->privilege = _dbus_strdup (privilege);
1866       if (privilege && !rule->privilege)
1867         goto nomem;
1868
1869       switch (pe->d.policy.type)
1870         {
1871         case POLICY_IGNORED:
1872         default:
1873           /* drop the rule on the floor */
1874           break;
1875           
1876         case POLICY_DEFAULT:
1877           if (!bus_policy_append_default_rule (parser->policy, rule))
1878             goto nomem;
1879           break;
1880         case POLICY_MANDATORY:
1881           if (!bus_policy_append_mandatory_rule (parser->policy, rule))
1882             goto nomem;
1883           break;
1884         case POLICY_USER:
1885           if (!BUS_POLICY_RULE_IS_PER_CLIENT (rule))
1886             {
1887               dbus_set_error (error, DBUS_ERROR_FAILED,
1888                               "<%s> rule cannot be per-user because it has bus-global semantics",
1889                               element_name);
1890               goto failed;
1891             }
1892           
1893           if (!bus_policy_append_user_rule (parser->policy, pe->d.policy.gid_uid_or_at_console,
1894                                             rule))
1895             goto nomem;
1896           break;
1897         case POLICY_GROUP:
1898           if (!BUS_POLICY_RULE_IS_PER_CLIENT (rule))
1899             {
1900               dbus_set_error (error, DBUS_ERROR_FAILED,
1901                               "<%s> rule cannot be per-group because it has bus-global semantics",
1902                               element_name);
1903               goto failed;
1904             }
1905           
1906           if (!bus_policy_append_group_rule (parser->policy, pe->d.policy.gid_uid_or_at_console,
1907                                              rule))
1908             goto nomem;
1909           break;
1910         case POLICY_CONSOLE:
1911           if (!bus_policy_append_console_rule (parser->policy, pe->d.policy.gid_uid_or_at_console,
1912                                                rule))
1913             goto nomem;
1914           break;
1915         }
1916  
1917       bus_policy_rule_unref (rule);
1918       rule = NULL;
1919     }
1920   
1921   return TRUE;
1922
1923  nomem:
1924   BUS_SET_OOM (error);
1925  failed:
1926   if (rule)
1927     bus_policy_rule_unref (rule);
1928   return FALSE;
1929 }
1930
1931 static dbus_bool_t
1932 start_policy_child (BusConfigParser   *parser,
1933                     const char        *element_name,
1934                     const char       **attribute_names,
1935                     const char       **attribute_values,
1936                     DBusError         *error)
1937 {
1938   if (strcmp (element_name, "allow") == 0)
1939     {
1940       if (!append_rule_from_element (parser, element_name,
1941                                      attribute_names, attribute_values,
1942                                      BUS_POLICY_RULE_ACCESS_ALLOW, error))
1943         return FALSE;
1944       
1945       if (push_element (parser, ELEMENT_ALLOW) == NULL)
1946         {
1947           BUS_SET_OOM (error);
1948           return FALSE;
1949         }
1950       
1951       return TRUE;
1952     }
1953   else if (strcmp (element_name, "deny") == 0)
1954     {
1955       if (!append_rule_from_element (parser, element_name,
1956                                      attribute_names, attribute_values,
1957                                      BUS_POLICY_RULE_ACCESS_DENY, error))
1958         return FALSE;
1959       
1960       if (push_element (parser, ELEMENT_DENY) == NULL)
1961         {
1962           BUS_SET_OOM (error);
1963           return FALSE;
1964         }
1965       
1966       return TRUE;
1967     }
1968   else if (strcmp (element_name, "check") == 0)
1969     {
1970       if (!append_rule_from_element (parser, element_name,
1971                                      attribute_names, attribute_values,
1972                                      BUS_POLICY_RULE_ACCESS_CHECK, error))
1973         return FALSE;
1974
1975       if (push_element (parser, ELEMENT_CHECK) == NULL)
1976         {
1977           BUS_SET_OOM (error);
1978           return FALSE;
1979         }
1980
1981       return TRUE;
1982     }
1983   else
1984     {
1985       dbus_set_error (error, DBUS_ERROR_FAILED,
1986                       "Element <%s> not allowed inside <%s> in configuration file",
1987                       element_name, "policy");
1988       return FALSE;
1989     }
1990 }
1991
1992 static dbus_bool_t
1993 start_selinux_child (BusConfigParser   *parser,
1994                      const char        *element_name,
1995                      const char       **attribute_names,
1996                      const char       **attribute_values,
1997                      DBusError         *error)
1998 {
1999   char *own_copy;
2000   char *context_copy;
2001
2002   own_copy = NULL;
2003   context_copy = NULL;
2004
2005   if (strcmp (element_name, "associate") == 0)
2006     {
2007       const char *own;
2008       const char *context;
2009       
2010       if (!locate_attributes (parser, "associate",
2011                               attribute_names,
2012                               attribute_values,
2013                               error,
2014                               "own", &own,
2015                               "context", &context,
2016                               NULL))
2017         return FALSE;
2018       
2019       if (push_element (parser, ELEMENT_ASSOCIATE) == NULL)
2020         {
2021           BUS_SET_OOM (error);
2022           return FALSE;
2023         }
2024
2025       if (own == NULL || context == NULL)
2026         {
2027           dbus_set_error (error, DBUS_ERROR_FAILED,
2028                           "Element <associate> must have attributes own=\"<servicename>\" and context=\"<selinux context>\"");
2029           return FALSE;
2030         }
2031
2032       own_copy = _dbus_strdup (own);
2033       if (own_copy == NULL)
2034         goto oom;
2035       context_copy = _dbus_strdup (context);
2036       if (context_copy == NULL)
2037         goto oom;
2038
2039       if (!_dbus_hash_table_insert_string (parser->service_context_table,
2040                                            own_copy, context_copy))
2041         goto oom;
2042
2043       return TRUE;
2044     }
2045   else
2046     {
2047       dbus_set_error (error, DBUS_ERROR_FAILED,
2048                       "Element <%s> not allowed inside <%s> in configuration file",
2049                       element_name, "selinux");
2050       return FALSE;
2051     }
2052
2053  oom:
2054   if (own_copy)
2055     dbus_free (own_copy);
2056
2057   if (context_copy)  
2058     dbus_free (context_copy);
2059
2060   BUS_SET_OOM (error);
2061   return FALSE;
2062 }
2063
2064 dbus_bool_t
2065 bus_config_parser_start_element (BusConfigParser   *parser,
2066                                  const char        *element_name,
2067                                  const char       **attribute_names,
2068                                  const char       **attribute_values,
2069                                  DBusError         *error)
2070 {
2071   ElementType t;
2072
2073   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2074
2075   /* printf ("START: %s\n", element_name); */
2076   
2077   t = top_element_type (parser);
2078
2079   if (t == ELEMENT_NONE)
2080     {
2081       if (strcmp (element_name, "busconfig") == 0)
2082         {
2083           if (!check_no_attributes (parser, "busconfig", attribute_names, attribute_values, error))
2084             return FALSE;
2085           
2086           if (push_element (parser, ELEMENT_BUSCONFIG) == NULL)
2087             {
2088               BUS_SET_OOM (error);
2089               return FALSE;
2090             }
2091
2092           return TRUE;
2093         }
2094       else
2095         {
2096           dbus_set_error (error, DBUS_ERROR_FAILED,
2097                           "Unknown element <%s> at root of configuration file",
2098                           element_name);
2099           return FALSE;
2100         }
2101     }
2102   else if (t == ELEMENT_BUSCONFIG)
2103     {
2104       return start_busconfig_child (parser, element_name,
2105                                     attribute_names, attribute_values,
2106                                     error);
2107     }
2108   else if (t == ELEMENT_POLICY)
2109     {
2110       return start_policy_child (parser, element_name,
2111                                  attribute_names, attribute_values,
2112                                  error);
2113     }
2114   else if (t == ELEMENT_SELINUX)
2115     {
2116       return start_selinux_child (parser, element_name,
2117                                   attribute_names, attribute_values,
2118                                   error);
2119     }
2120   else
2121     {
2122       dbus_set_error (error, DBUS_ERROR_FAILED,
2123                       "Element <%s> is not allowed in this context",
2124                       element_name);
2125       return FALSE;
2126     }  
2127 }
2128
2129 static dbus_bool_t
2130 set_limit (BusConfigParser *parser,
2131            const char      *name,
2132            long             value,
2133            DBusError       *error)
2134 {
2135   dbus_bool_t must_be_positive;
2136   dbus_bool_t must_be_int;
2137
2138   must_be_int = FALSE;
2139   must_be_positive = FALSE;
2140   
2141   if (strcmp (name, "max_incoming_bytes") == 0)
2142     {
2143       must_be_positive = TRUE;
2144       parser->limits.max_incoming_bytes = value;
2145     }
2146   else if (strcmp (name, "max_incoming_unix_fds") == 0)
2147     {
2148       must_be_positive = TRUE;
2149       parser->limits.max_incoming_unix_fds = value;
2150     }
2151   else if (strcmp (name, "max_outgoing_bytes") == 0)
2152     {
2153       must_be_positive = TRUE;
2154       parser->limits.max_outgoing_bytes = value;
2155     }
2156   else if (strcmp (name, "max_outgoing_unix_fds") == 0)
2157     {
2158       must_be_positive = TRUE;
2159       parser->limits.max_outgoing_unix_fds = value;
2160     }
2161   else if (strcmp (name, "max_message_size") == 0)
2162     {
2163       must_be_positive = TRUE;
2164       parser->limits.max_message_size = value;
2165     }
2166   else if (strcmp (name, "max_message_unix_fds") == 0)
2167     {
2168       must_be_positive = TRUE;
2169       parser->limits.max_message_unix_fds = value;
2170     }
2171   else if (strcmp (name, "service_start_timeout") == 0)
2172     {
2173       must_be_positive = TRUE;
2174       must_be_int = TRUE;
2175       parser->limits.activation_timeout = value;
2176     }
2177   else if (strcmp (name, "auth_timeout") == 0)
2178     {
2179       must_be_positive = TRUE;
2180       must_be_int = TRUE;
2181       parser->limits.auth_timeout = value;
2182     }
2183   else if (strcmp (name, "pending_fd_timeout") == 0)
2184     {
2185       must_be_positive = TRUE;
2186       must_be_int = TRUE;
2187       parser->limits.pending_fd_timeout = value;
2188     }
2189   else if (strcmp (name, "reply_timeout") == 0)
2190     {
2191       must_be_positive = TRUE;
2192       must_be_int = TRUE;
2193       parser->limits.reply_timeout = value;
2194     }
2195   else if (strcmp (name, "max_completed_connections") == 0)
2196     {
2197       must_be_positive = TRUE;
2198       must_be_int = TRUE;
2199       parser->limits.max_completed_connections = value;
2200     }
2201   else if (strcmp (name, "max_incomplete_connections") == 0)
2202     {
2203       must_be_positive = TRUE;
2204       must_be_int = TRUE;
2205       parser->limits.max_incomplete_connections = value;
2206     }
2207   else if (strcmp (name, "max_connections_per_user") == 0)
2208     {
2209       must_be_positive = TRUE;
2210       must_be_int = TRUE;
2211       parser->limits.max_connections_per_user = value;
2212     }
2213   else if (strcmp (name, "max_pending_service_starts") == 0)
2214     {
2215       must_be_positive = TRUE;
2216       must_be_int = TRUE;
2217       parser->limits.max_pending_activations = value;
2218     }
2219   else if (strcmp (name, "max_names_per_connection") == 0)
2220     {
2221       must_be_positive = TRUE;
2222       must_be_int = TRUE;
2223       parser->limits.max_services_per_connection = value;
2224     }
2225   else if (strcmp (name, "max_match_rules_per_connection") == 0)
2226     {
2227       must_be_positive = TRUE;
2228       must_be_int = TRUE;
2229       parser->limits.max_match_rules_per_connection = value;
2230     }
2231   else if (strcmp (name, "max_replies_per_connection") == 0)
2232     {
2233       must_be_positive = TRUE;
2234       must_be_int = TRUE;
2235       parser->limits.max_replies_per_connection = value;
2236     }
2237   else
2238     {
2239       dbus_set_error (error, DBUS_ERROR_FAILED,
2240                       "There is no limit called \"%s\"\n",
2241                       name);
2242       return FALSE;
2243     }
2244   
2245   if (must_be_positive && value < 0)
2246     {
2247       dbus_set_error (error, DBUS_ERROR_FAILED,
2248                       "<limit name=\"%s\"> must be a positive number\n",
2249                       name);
2250       return FALSE;
2251     }
2252
2253   if (must_be_int &&
2254       (value < _DBUS_INT_MIN || value > _DBUS_INT_MAX))
2255     {
2256       dbus_set_error (error, DBUS_ERROR_FAILED,
2257                       "<limit name=\"%s\"> value is too large\n",
2258                       name);
2259       return FALSE;
2260     }
2261
2262   return TRUE;  
2263 }
2264
2265 dbus_bool_t
2266 bus_config_parser_end_element (BusConfigParser   *parser,
2267                                const char        *element_name,
2268                                DBusError         *error)
2269 {
2270   ElementType t;
2271   const char *n;
2272   Element *e;
2273
2274   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2275
2276   /* printf ("END: %s\n", element_name); */
2277   
2278   t = top_element_type (parser);
2279
2280   if (t == ELEMENT_NONE)
2281     {
2282       /* should probably be an assertion failure but
2283        * being paranoid about XML parsers
2284        */
2285       dbus_set_error (error, DBUS_ERROR_FAILED,
2286                       "XML parser ended element with no element on the stack");
2287       return FALSE;
2288     }
2289
2290   n = bus_config_parser_element_type_to_name (t);
2291   _dbus_assert (n != NULL);
2292   if (strcmp (n, element_name) != 0)
2293     {
2294       /* should probably be an assertion failure but
2295        * being paranoid about XML parsers
2296        */
2297       dbus_set_error (error, DBUS_ERROR_FAILED,
2298                       "XML element <%s> ended but topmost element on the stack was <%s>",
2299                       element_name, n);
2300       return FALSE;
2301     }
2302
2303   e = peek_element (parser);
2304   _dbus_assert (e != NULL);
2305
2306   switch (e->type)
2307     {
2308     case ELEMENT_NONE:
2309     default:
2310       _dbus_assert_not_reached ("element in stack has no type");
2311       break;
2312
2313     case ELEMENT_INCLUDE:
2314     case ELEMENT_USER:
2315     case ELEMENT_CONFIGTYPE:
2316     case ELEMENT_LISTEN:
2317     case ELEMENT_PIDFILE:
2318     case ELEMENT_AUTH:
2319     case ELEMENT_SERVICEDIR:
2320     case ELEMENT_SERVICEHELPER:
2321     case ELEMENT_INCLUDEDIR:
2322     case ELEMENT_LIMIT:
2323       if (!e->had_content)
2324         {
2325           dbus_set_error (error, DBUS_ERROR_FAILED,
2326                           "XML element <%s> was expected to have content inside it",
2327                           bus_config_parser_element_type_to_name (e->type));
2328           return FALSE;
2329         }
2330
2331       if (e->type == ELEMENT_LIMIT)
2332         {
2333           if (!set_limit (parser, e->d.limit.name, e->d.limit.value,
2334                           error))
2335             return FALSE;
2336         }
2337       break;
2338
2339     case ELEMENT_BUSCONFIG:
2340     case ELEMENT_POLICY:
2341     case ELEMENT_ALLOW:
2342     case ELEMENT_DENY:
2343     case ELEMENT_CHECK:
2344     case ELEMENT_FORK:
2345     case ELEMENT_SYSLOG:
2346     case ELEMENT_KEEP_UMASK:
2347     case ELEMENT_SELINUX:
2348     case ELEMENT_ASSOCIATE:
2349     case ELEMENT_STANDARD_SESSION_SERVICEDIRS:
2350     case ELEMENT_STANDARD_SYSTEM_SERVICEDIRS:
2351     case ELEMENT_ALLOW_ANONYMOUS:
2352     case ELEMENT_APPARMOR:
2353       break;
2354     }
2355
2356   pop_element (parser);
2357
2358   return TRUE;
2359 }
2360
2361 static dbus_bool_t
2362 all_whitespace (const DBusString *str)
2363 {
2364   int i;
2365
2366   _dbus_string_skip_white (str, 0, &i);
2367
2368   return i == _dbus_string_get_length (str);
2369 }
2370
2371 static dbus_bool_t
2372 make_full_path (const DBusString *basedir,
2373                 const DBusString *filename,
2374                 DBusString       *full_path)
2375 {
2376   if (_dbus_path_is_absolute (filename))
2377     {
2378       if (!_dbus_string_copy (filename, 0, full_path, 0))
2379         return FALSE;
2380     }
2381   else
2382     {
2383       if (!_dbus_string_copy (basedir, 0, full_path, 0))
2384         return FALSE;
2385       
2386       if (!_dbus_concat_dir_and_file (full_path, filename))
2387         return FALSE;
2388     }
2389
2390   if (!_dbus_replace_install_prefix (full_path))
2391     return FALSE;
2392
2393   return TRUE;
2394 }
2395
2396 static dbus_bool_t
2397 include_file (BusConfigParser   *parser,
2398               const DBusString  *filename,
2399               dbus_bool_t        ignore_missing,
2400               DBusError         *error)
2401 {
2402   /* FIXME good test case for this would load each config file in the
2403    * test suite both alone, and as an include, and check
2404    * that the result is the same
2405    */
2406   BusConfigParser *included;
2407   const char *filename_str;
2408   DBusError tmp_error;
2409         
2410   dbus_error_init (&tmp_error);
2411
2412   filename_str = _dbus_string_get_const_data (filename);
2413
2414   /* Check to make sure this file hasn't already been included. */
2415   if (seen_include (parser, filename))
2416     {
2417       dbus_set_error (error, DBUS_ERROR_FAILED,
2418                       "Circular inclusion of file '%s'",
2419                       filename_str);
2420       return FALSE;
2421     }
2422   
2423   if (! _dbus_list_append (&parser->included_files, (void *) filename_str))
2424     {
2425       BUS_SET_OOM (error);
2426       return FALSE;
2427     }
2428
2429   /* Since parser is passed in as the parent, included
2430      inherits parser's limits. */
2431   included = bus_config_load (filename, FALSE, parser, &tmp_error);
2432
2433   _dbus_list_pop_last (&parser->included_files);
2434
2435   if (included == NULL)
2436     {
2437       _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
2438
2439       if (dbus_error_has_name (&tmp_error, DBUS_ERROR_FILE_NOT_FOUND) &&
2440           ignore_missing)
2441         {
2442           dbus_error_free (&tmp_error);
2443           return TRUE;
2444         }
2445       else
2446         {
2447           dbus_move_error (&tmp_error, error);
2448           return FALSE;
2449         }
2450     }
2451   else
2452     {
2453       _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
2454
2455       if (!merge_included (parser, included, error))
2456         {
2457           bus_config_parser_unref (included);
2458           return FALSE;
2459         }
2460
2461       /* Copy included's limits back to parser. */
2462       parser->limits = included->limits;
2463
2464       bus_config_parser_unref (included);
2465       return TRUE;
2466     }
2467 }
2468
2469 static dbus_bool_t
2470 servicehelper_path (BusConfigParser   *parser,
2471                     const DBusString  *filename,
2472                     DBusError         *error)
2473 {
2474   const char *filename_str;
2475   char *servicehelper;
2476
2477   filename_str = _dbus_string_get_const_data (filename);
2478
2479   /* copy to avoid overwriting with NULL on OOM */
2480   servicehelper = _dbus_strdup (filename_str);
2481
2482   /* check for OOM */
2483   if (servicehelper == NULL)
2484     {
2485       BUS_SET_OOM (error);
2486       return FALSE;
2487     }
2488
2489   /* save the latest servicehelper only if not OOM */
2490   dbus_free (parser->servicehelper);
2491   parser->servicehelper = servicehelper;
2492
2493   /* We don't check whether the helper exists; instead we
2494    * would just fail to ever activate anything if it doesn't.
2495    * This allows an admin to fix the problem if it doesn't exist.
2496    * It also allows the parser test suite to successfully parse
2497    * test cases without installing the helper. ;-)
2498    */
2499   
2500   return TRUE;
2501 }
2502
2503 static dbus_bool_t
2504 include_dir (BusConfigParser   *parser,
2505              const DBusString  *dirname,
2506              DBusError         *error)
2507 {
2508   DBusString filename;
2509   dbus_bool_t retval;
2510   DBusError tmp_error;
2511   DBusDirIter *dir;
2512   char *s;
2513   
2514   if (!_dbus_string_init (&filename))
2515     {
2516       BUS_SET_OOM (error);
2517       return FALSE;
2518     }
2519
2520   retval = FALSE;
2521   
2522   dir = _dbus_directory_open (dirname, error);
2523
2524   if (dir == NULL)
2525     {
2526       if (dbus_error_has_name (error, DBUS_ERROR_FILE_NOT_FOUND))
2527         {
2528           dbus_error_free (error);
2529           goto success;
2530         }
2531       else
2532         goto failed;
2533     }
2534
2535   dbus_error_init (&tmp_error);
2536   while (_dbus_directory_get_next_file (dir, &filename, &tmp_error))
2537     {
2538       DBusString full_path;
2539
2540       if (!_dbus_string_init (&full_path))
2541         {
2542           BUS_SET_OOM (error);
2543           goto failed;
2544         }
2545
2546       if (!_dbus_string_copy (dirname, 0, &full_path, 0))
2547         {
2548           BUS_SET_OOM (error);
2549           _dbus_string_free (&full_path);
2550           goto failed;
2551         }      
2552
2553       if (!_dbus_concat_dir_and_file (&full_path, &filename))
2554         {
2555           BUS_SET_OOM (error);
2556           _dbus_string_free (&full_path);
2557           goto failed;
2558         }
2559       
2560       if (_dbus_string_ends_with_c_str (&full_path, ".conf"))
2561         {
2562           if (!include_file (parser, &full_path, TRUE, error))
2563             {
2564               if (dbus_error_is_set (error))
2565                 {
2566                   /* We use both syslog and stderr here, because this is
2567                    * the configuration parser, so we don't yet know whether
2568                    * this bus is going to want to write to syslog! Err on
2569                    * the side of making sure the message gets to the sysadmin
2570                    * somehow. */
2571                   _dbus_init_system_log ("dbus-daemon",
2572                       DBUS_LOG_FLAGS_STDERR | DBUS_LOG_FLAGS_SYSTEM_LOG);
2573                   _dbus_log (DBUS_SYSTEM_LOG_INFO,
2574                              "Encountered error '%s' while parsing '%s'",
2575                              error->message,
2576                              _dbus_string_get_const_data (&full_path));
2577                   dbus_error_free (error);
2578                 }
2579             }
2580         }
2581
2582       _dbus_string_free (&full_path);
2583     }
2584
2585   if (dbus_error_is_set (&tmp_error))
2586     {
2587       dbus_move_error (&tmp_error, error);
2588       goto failed;
2589     }
2590
2591
2592   if (!_dbus_string_copy_data (dirname, &s))
2593     {
2594       BUS_SET_OOM (error);
2595       goto failed;
2596     }
2597
2598   if (!_dbus_list_append (&parser->conf_dirs, s))
2599     {
2600       dbus_free (s);
2601       BUS_SET_OOM (error);
2602       goto failed;
2603     }
2604
2605  success:
2606   retval = TRUE;
2607   
2608  failed:
2609   _dbus_string_free (&filename);
2610   
2611   if (dir)
2612     _dbus_directory_close (dir);
2613
2614   return retval;
2615 }
2616
2617 dbus_bool_t
2618 bus_config_parser_content (BusConfigParser   *parser,
2619                            const DBusString  *content,
2620                            DBusError         *error)
2621 {
2622   Element *e;
2623
2624   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2625
2626 #if 0
2627   {
2628     const char *c_str;
2629     
2630     _dbus_string_get_const_data (content, &c_str);
2631
2632     printf ("CONTENT %d bytes: %s\n", _dbus_string_get_length (content), c_str);
2633   }
2634 #endif
2635   
2636   e = peek_element (parser);
2637   if (e == NULL)
2638     {
2639       dbus_set_error (error, DBUS_ERROR_FAILED,
2640                       "Text content outside of any XML element in configuration file");
2641       return FALSE;
2642     }
2643   else if (e->had_content)
2644     {
2645       _dbus_assert_not_reached ("Element had multiple content blocks");
2646       return FALSE;
2647     }
2648
2649   switch (top_element_type (parser))
2650     {
2651     case ELEMENT_NONE:
2652     default:
2653       _dbus_assert_not_reached ("element at top of stack has no type");
2654       return FALSE;
2655
2656     case ELEMENT_BUSCONFIG:
2657     case ELEMENT_POLICY:
2658     case ELEMENT_ALLOW:
2659     case ELEMENT_DENY:
2660     case ELEMENT_CHECK:
2661     case ELEMENT_FORK:
2662     case ELEMENT_SYSLOG:
2663     case ELEMENT_KEEP_UMASK:
2664     case ELEMENT_STANDARD_SESSION_SERVICEDIRS:    
2665     case ELEMENT_STANDARD_SYSTEM_SERVICEDIRS:    
2666     case ELEMENT_ALLOW_ANONYMOUS:
2667     case ELEMENT_SELINUX:
2668     case ELEMENT_ASSOCIATE:
2669     case ELEMENT_APPARMOR:
2670       if (all_whitespace (content))
2671         return TRUE;
2672       else
2673         {
2674           dbus_set_error (error, DBUS_ERROR_FAILED,
2675                           "No text content expected inside XML element %s in configuration file",
2676                           bus_config_parser_element_type_to_name (top_element_type (parser)));
2677           return FALSE;
2678         }
2679
2680     case ELEMENT_PIDFILE:
2681       {
2682         char *s;
2683
2684         e->had_content = TRUE;
2685         
2686         if (!_dbus_string_copy_data (content, &s))
2687           goto nomem;
2688           
2689         dbus_free (parser->pidfile);
2690         parser->pidfile = s;
2691       }
2692       break;
2693
2694     case ELEMENT_INCLUDE:
2695       {
2696         DBusString full_path, selinux_policy_root;
2697
2698         e->had_content = TRUE;
2699
2700         if (e->d.include.if_selinux_enabled
2701             && !bus_selinux_enabled ())
2702           break;
2703
2704         if (!_dbus_string_init (&full_path))
2705           goto nomem;
2706
2707         if (e->d.include.selinux_root_relative)
2708           {
2709             if (!bus_selinux_get_policy_root ())
2710               {
2711                 dbus_set_error (error, DBUS_ERROR_FAILED,
2712                                 "Could not determine SELinux policy root for relative inclusion");
2713                 _dbus_string_free (&full_path);
2714                 return FALSE;
2715               }
2716             _dbus_string_init_const (&selinux_policy_root,
2717                                      bus_selinux_get_policy_root ());
2718             if (!make_full_path (&selinux_policy_root, content, &full_path))
2719               {
2720                 _dbus_string_free (&full_path);
2721                 goto nomem;
2722               }
2723           }
2724         else if (!make_full_path (&parser->basedir, content, &full_path))
2725           {
2726             _dbus_string_free (&full_path);
2727             goto nomem;
2728           }
2729
2730         if (!include_file (parser, &full_path,
2731                            e->d.include.ignore_missing, error))
2732           {
2733             _dbus_string_free (&full_path);
2734             return FALSE;
2735           }
2736
2737         _dbus_string_free (&full_path);
2738       }
2739       break;
2740
2741     case ELEMENT_SERVICEHELPER:
2742       {
2743         DBusString full_path;
2744         
2745         e->had_content = TRUE;
2746
2747         if (!_dbus_string_init (&full_path))
2748           goto nomem;
2749         
2750         if (!make_full_path (&parser->basedir, content, &full_path))
2751           {
2752             _dbus_string_free (&full_path);
2753             goto nomem;
2754           }
2755
2756         if (!servicehelper_path (parser, &full_path, error))
2757           {
2758             _dbus_string_free (&full_path);
2759             return FALSE;
2760           }
2761
2762         _dbus_string_free (&full_path);
2763       }
2764       break;
2765       
2766     case ELEMENT_INCLUDEDIR:
2767       {
2768         DBusString full_path;
2769         
2770         e->had_content = TRUE;
2771
2772         if (!_dbus_string_init (&full_path))
2773           goto nomem;
2774         
2775         if (!make_full_path (&parser->basedir, content, &full_path))
2776           {
2777             _dbus_string_free (&full_path);
2778             goto nomem;
2779           }
2780         
2781         if (!include_dir (parser, &full_path, error))
2782           {
2783             _dbus_string_free (&full_path);
2784             return FALSE;
2785           }
2786
2787         _dbus_string_free (&full_path);
2788       }
2789       break;
2790       
2791     case ELEMENT_USER:
2792       {
2793         char *s;
2794
2795         e->had_content = TRUE;
2796         
2797         if (!_dbus_string_copy_data (content, &s))
2798           goto nomem;
2799           
2800         dbus_free (parser->user);
2801         parser->user = s;
2802       }
2803       break;
2804
2805     case ELEMENT_CONFIGTYPE:
2806       {
2807         char *s;
2808
2809         e->had_content = TRUE;
2810
2811         if (!_dbus_string_copy_data (content, &s))
2812           goto nomem;
2813         
2814         dbus_free (parser->bus_type);
2815         parser->bus_type = s;
2816       }
2817       break;
2818       
2819     case ELEMENT_LISTEN:
2820       {
2821         char *s;
2822
2823         e->had_content = TRUE;
2824         
2825         if (!_dbus_string_copy_data (content, &s))
2826           goto nomem;
2827
2828         if (!_dbus_list_append (&parser->listen_on,
2829                                 s))
2830           {
2831             dbus_free (s);
2832             goto nomem;
2833           }
2834       }
2835       break;
2836
2837     case ELEMENT_AUTH:
2838       {
2839         char *s;
2840         
2841         e->had_content = TRUE;
2842
2843         if (!_dbus_string_copy_data (content, &s))
2844           goto nomem;
2845
2846         if (!_dbus_list_append (&parser->mechanisms,
2847                                 s))
2848           {
2849             dbus_free (s);
2850             goto nomem;
2851           }
2852       }
2853       break;
2854
2855     case ELEMENT_SERVICEDIR:
2856       {
2857         char *s;
2858         BusConfigServiceDir *dir;
2859         DBusString full_path;
2860         DBusList *link;
2861
2862         e->had_content = TRUE;
2863
2864         if (!_dbus_string_init (&full_path))
2865           goto nomem;
2866         
2867         if (!make_full_path (&parser->basedir, content, &full_path))
2868           {
2869             _dbus_string_free (&full_path);
2870             goto nomem;
2871           }
2872         
2873         if (!_dbus_string_copy_data (&full_path, &s))
2874           {
2875             _dbus_string_free (&full_path);
2876             goto nomem;
2877           }
2878
2879         /* <servicedir/> has traditionally implied that we watch the
2880          * directory with inotify, and allow service files whose names do not
2881          * match the bus name */
2882         dir = bus_config_service_dir_new_take (s, BUS_SERVICE_DIR_FLAGS_NONE);
2883
2884         if (dir == NULL)
2885           {
2886             _dbus_string_free (&full_path);
2887             dbus_free (s);
2888             goto nomem;
2889           }
2890
2891         link = _dbus_list_alloc_link (dir);
2892
2893         if (link == NULL)
2894           {
2895             _dbus_string_free (&full_path);
2896             bus_config_service_dir_free (dir);
2897             goto nomem;
2898           }
2899
2900         /* cannot fail */
2901         service_dirs_append_link_unique_or_free (&parser->service_dirs, link);
2902         _dbus_string_free (&full_path);
2903       }
2904       break;
2905
2906     case ELEMENT_LIMIT:
2907       {
2908         long val;
2909
2910         e->had_content = TRUE;
2911
2912         val = 0;
2913         if (!_dbus_string_parse_int (content, 0, &val, NULL))
2914           {
2915             dbus_set_error (error, DBUS_ERROR_FAILED,
2916                             "<limit name=\"%s\"> element has invalid value (could not parse as integer)",
2917                             e->d.limit.name);
2918             return FALSE;
2919           }
2920
2921         e->d.limit.value = val;
2922
2923         _dbus_verbose ("Loaded value %ld for limit %s\n",
2924                        e->d.limit.value,
2925                        e->d.limit.name);
2926       }
2927       break;
2928     }
2929
2930   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2931   return TRUE;
2932
2933  nomem:
2934   BUS_SET_OOM (error);
2935   return FALSE;
2936 }
2937
2938 dbus_bool_t
2939 bus_config_parser_finished (BusConfigParser   *parser,
2940                             DBusError         *error)
2941 {
2942   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2943
2944   if (parser->stack != NULL)
2945     {
2946       dbus_set_error (error, DBUS_ERROR_FAILED,
2947                       "Element <%s> was not closed in configuration file",
2948                       bus_config_parser_element_type_to_name (top_element_type (parser)));
2949
2950       return FALSE;
2951     }
2952
2953   if (parser->is_toplevel && parser->listen_on == NULL)
2954     {
2955       dbus_set_error (error, DBUS_ERROR_FAILED,
2956                       "Configuration file needs one or more <listen> elements giving addresses"); 
2957       return FALSE;
2958     }
2959   
2960   return TRUE;
2961 }
2962
2963 const char*
2964 bus_config_parser_get_user (BusConfigParser *parser)
2965 {
2966   return parser->user;
2967 }
2968
2969 const char*
2970 bus_config_parser_get_type (BusConfigParser *parser)
2971 {
2972   return parser->bus_type;
2973 }
2974
2975 DBusList**
2976 bus_config_parser_get_addresses (BusConfigParser *parser)
2977 {
2978   return &parser->listen_on;
2979 }
2980
2981 DBusList**
2982 bus_config_parser_get_mechanisms (BusConfigParser *parser)
2983 {
2984   return &parser->mechanisms;
2985 }
2986
2987 DBusList**
2988 bus_config_parser_get_service_dirs (BusConfigParser *parser)
2989 {
2990   return &parser->service_dirs;
2991 }
2992
2993 DBusList**
2994 bus_config_parser_get_conf_dirs (BusConfigParser *parser)
2995 {
2996   return &parser->conf_dirs;
2997 }
2998
2999 dbus_bool_t
3000 bus_config_parser_get_fork (BusConfigParser   *parser)
3001 {
3002   return parser->fork;
3003 }
3004
3005 dbus_bool_t
3006 bus_config_parser_get_syslog (BusConfigParser   *parser)
3007 {
3008   return parser->syslog;
3009 }
3010
3011 dbus_bool_t
3012 bus_config_parser_get_keep_umask (BusConfigParser   *parser)
3013 {
3014   return parser->keep_umask;
3015 }
3016
3017 dbus_bool_t
3018 bus_config_parser_get_allow_anonymous (BusConfigParser   *parser)
3019 {
3020   return parser->allow_anonymous;
3021 }
3022
3023 const char *
3024 bus_config_parser_get_pidfile (BusConfigParser   *parser)
3025 {
3026   return parser->pidfile;
3027 }
3028
3029 const char *
3030 bus_config_parser_get_servicehelper (BusConfigParser   *parser)
3031 {
3032   return parser->servicehelper;
3033 }
3034
3035 BusPolicy*
3036 bus_config_parser_steal_policy (BusConfigParser *parser)
3037 {
3038   BusPolicy *policy;
3039
3040   _dbus_assert (parser->policy != NULL); /* can only steal the policy 1 time */
3041   
3042   policy = parser->policy;
3043
3044   parser->policy = NULL;
3045
3046   return policy;
3047 }
3048
3049 /* Overwrite any limits that were set in the configuration file */
3050 void
3051 bus_config_parser_get_limits (BusConfigParser *parser,
3052                               BusLimits       *limits)
3053 {
3054   *limits = parser->limits;
3055 }
3056
3057 DBusHashTable*
3058 bus_config_parser_steal_service_context_table (BusConfigParser *parser)
3059 {
3060   DBusHashTable *table;
3061
3062   _dbus_assert (parser->service_context_table != NULL); /* can only steal once */
3063
3064   table = parser->service_context_table;
3065
3066   parser->service_context_table = NULL;
3067
3068   return table;
3069 }
3070
3071 /*
3072  * Return a list of the directories that should be watched with inotify,
3073  * as strings. The list might be empty and is in arbitrary order.
3074  *
3075  * The list must be empty on entry. On success, the links are owned by the
3076  * caller and must be freed, but the data in each link remains owned by
3077  * the BusConfigParser and must not be freed: in GObject-Introspection
3078  * notation, it is (transfer container).
3079  */
3080 dbus_bool_t
3081 bus_config_parser_get_watched_dirs (BusConfigParser *parser,
3082                                     DBusList **watched_dirs)
3083 {
3084   DBusList *link;
3085
3086   _dbus_assert (*watched_dirs == NULL);
3087
3088   for (link = _dbus_list_get_first_link (&parser->conf_dirs);
3089        link != NULL;
3090        link = _dbus_list_get_next_link (&parser->conf_dirs, link))
3091     {
3092       if (!_dbus_list_append (watched_dirs, link->data))
3093         goto oom;
3094     }
3095
3096   for (link = _dbus_list_get_first_link (&parser->service_dirs);
3097        link != NULL;
3098        link = _dbus_list_get_next_link (&parser->service_dirs, link))
3099     {
3100       BusConfigServiceDir *dir = link->data;
3101
3102       if (dir->flags & BUS_SERVICE_DIR_FLAGS_NO_WATCH)
3103         continue;
3104
3105       if (!_dbus_list_append (watched_dirs, dir->path))
3106         goto oom;
3107     }
3108
3109   return TRUE;
3110
3111 oom:
3112   _dbus_list_clear (watched_dirs);
3113   return FALSE;
3114 }
3115
3116 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
3117 #include <stdio.h>
3118
3119 typedef enum
3120 {
3121   VALID,
3122   INVALID,
3123   UNKNOWN
3124 } Validity;
3125
3126 static dbus_bool_t
3127 do_check_own_rules (BusPolicy  *policy)
3128 {
3129   const struct {
3130     const char *name;
3131     dbus_bool_t allowed;
3132   } checks[] = {
3133     {"org.freedesktop", FALSE},
3134     {"org.freedesktop.ManySystem", FALSE},
3135     {"org.freedesktop.ManySystems", TRUE},
3136     {"org.freedesktop.ManySystems.foo", TRUE},
3137     {"org.freedesktop.ManySystems.foo.bar", TRUE},
3138     {"org.freedesktop.ManySystems2", FALSE},
3139     {"org.freedesktop.ManySystems2.foo", FALSE},
3140     {"org.freedesktop.ManySystems2.foo.bar", FALSE},
3141     {NULL, FALSE}
3142   };
3143   int i = 0;
3144
3145   while (checks[i].name)
3146     {
3147       DBusString service_name;
3148       dbus_bool_t ret;
3149
3150       if (!_dbus_string_init (&service_name))
3151         _dbus_assert_not_reached ("couldn't init string");
3152       if (!_dbus_string_append (&service_name, checks[i].name))
3153         _dbus_assert_not_reached ("couldn't append string");
3154
3155       ret = bus_policy_check_can_own (policy, &service_name);
3156       printf ("        Check name %s: %s\n", checks[i].name,
3157               ret ? "allowed" : "not allowed");
3158       if (checks[i].allowed && !ret)
3159         {
3160           _dbus_warn ("Cannot own %s", checks[i].name);
3161           return FALSE;
3162         }
3163       if (!checks[i].allowed && ret)
3164         {
3165           _dbus_warn ("Can own %s", checks[i].name);
3166           return FALSE;
3167         }
3168       _dbus_string_free (&service_name);
3169
3170       i++;
3171     }
3172
3173   return TRUE;
3174 }
3175
3176 static dbus_bool_t
3177 do_load (const DBusString *full_path,
3178          Validity          validity,
3179          dbus_bool_t       oom_possible,
3180          dbus_bool_t       check_own_rules)
3181 {
3182   BusConfigParser *parser;
3183   DBusError error;
3184
3185   dbus_error_init (&error);
3186
3187   parser = bus_config_load (full_path, TRUE, NULL, &error);
3188   if (dbus_error_is_set (&error))
3189     _dbus_verbose ("Failed to load file: %s\n", error.message);
3190   if (parser == NULL)
3191     {
3192       _DBUS_ASSERT_ERROR_IS_SET (&error);
3193
3194       if (oom_possible &&
3195           dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
3196         {
3197           _dbus_verbose ("Failed to load valid file due to OOM\n");
3198           dbus_error_free (&error);
3199           return TRUE;
3200         }
3201       else if (validity == VALID)
3202         {
3203           _dbus_warn ("Failed to load valid file but still had memory: %s",
3204                       error.message);
3205
3206           dbus_error_free (&error);
3207           return FALSE;
3208         }
3209       else
3210         {
3211           dbus_error_free (&error);
3212           return TRUE;
3213         }
3214     }
3215   else
3216     {
3217       _DBUS_ASSERT_ERROR_IS_CLEAR (&error);
3218
3219       if (check_own_rules && do_check_own_rules (parser->policy) == FALSE)
3220         {
3221           return FALSE;
3222         }
3223
3224       bus_config_parser_unref (parser);
3225
3226       if (validity == INVALID)
3227         {
3228           _dbus_warn ("Accepted invalid file");
3229           return FALSE;
3230         }
3231
3232       return TRUE;
3233     }
3234 }
3235
3236 typedef struct
3237 {
3238   const DBusString *full_path;
3239   Validity          validity;
3240   dbus_bool_t       check_own_rules;
3241 } LoaderOomData;
3242
3243 static dbus_bool_t
3244 check_loader_oom_func (void *data)
3245 {
3246   LoaderOomData *d = data;
3247
3248   return do_load (d->full_path, d->validity, TRUE, d->check_own_rules);
3249 }
3250
3251 static dbus_bool_t
3252 process_test_valid_subdir (const DBusString *test_base_dir,
3253                            const char       *subdir,
3254                            Validity          validity)
3255 {
3256   DBusString test_directory;
3257   DBusString filename;
3258   DBusDirIter *dir;
3259   dbus_bool_t retval;
3260   DBusError error;
3261
3262   retval = FALSE;
3263   dir = NULL;
3264
3265   if (!_dbus_string_init (&test_directory))
3266     _dbus_assert_not_reached ("didn't allocate test_directory");
3267
3268   _dbus_string_init_const (&filename, subdir);
3269
3270   if (!_dbus_string_copy (test_base_dir, 0,
3271                           &test_directory, 0))
3272     _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
3273
3274   if (!_dbus_concat_dir_and_file (&test_directory, &filename))
3275     _dbus_assert_not_reached ("couldn't allocate full path");
3276
3277   _dbus_string_free (&filename);
3278   if (!_dbus_string_init (&filename))
3279     _dbus_assert_not_reached ("didn't allocate filename string");
3280
3281   dbus_error_init (&error);
3282   dir = _dbus_directory_open (&test_directory, &error);
3283   if (dir == NULL)
3284     {
3285       _dbus_warn ("Could not open %s: %s",
3286                   _dbus_string_get_const_data (&test_directory),
3287                   error.message);
3288       dbus_error_free (&error);
3289       goto failed;
3290     }
3291
3292   if (validity == VALID)
3293     printf ("Testing valid files:\n");
3294   else if (validity == INVALID)
3295     printf ("Testing invalid files:\n");
3296   else
3297     printf ("Testing unknown files:\n");
3298
3299  next:
3300   while (_dbus_directory_get_next_file (dir, &filename, &error))
3301     {
3302       DBusString full_path;
3303       LoaderOomData d;
3304
3305       if (!_dbus_string_init (&full_path))
3306         _dbus_assert_not_reached ("couldn't init string");
3307
3308       if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
3309         _dbus_assert_not_reached ("couldn't copy dir to full_path");
3310
3311       if (!_dbus_concat_dir_and_file (&full_path, &filename))
3312         _dbus_assert_not_reached ("couldn't concat file to dir");
3313
3314       if (!_dbus_string_ends_with_c_str (&full_path, ".conf"))
3315         {
3316           _dbus_verbose ("Skipping non-.conf file %s\n",
3317                          _dbus_string_get_const_data (&filename));
3318           _dbus_string_free (&full_path);
3319           goto next;
3320         }
3321
3322       printf ("    %s\n", _dbus_string_get_const_data (&filename));
3323
3324       _dbus_verbose (" expecting %s\n",
3325                      validity == VALID ? "valid" :
3326                      (validity == INVALID ? "invalid" :
3327                       (validity == UNKNOWN ? "unknown" : "???")));
3328
3329       d.full_path = &full_path;
3330       d.validity = validity;
3331       d.check_own_rules = _dbus_string_ends_with_c_str (&full_path,
3332           "check-own-rules.conf");
3333
3334       /* FIXME hackaround for an expat problem, see
3335        * https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=124747
3336        * http://freedesktop.org/pipermail/dbus/2004-May/001153.html
3337        */
3338       /* if (!_dbus_test_oom_handling ("config-loader", check_loader_oom_func, &d)) */
3339       if (!check_loader_oom_func (&d))
3340         _dbus_assert_not_reached ("test failed");
3341       
3342       _dbus_string_free (&full_path);
3343     }
3344
3345   if (dbus_error_is_set (&error))
3346     {
3347       _dbus_warn ("Could not get next file in %s: %s",
3348                   _dbus_string_get_const_data (&test_directory),
3349                   error.message);
3350       dbus_error_free (&error);
3351       goto failed;
3352     }
3353
3354   retval = TRUE;
3355
3356  failed:
3357
3358   if (dir)
3359     _dbus_directory_close (dir);
3360   _dbus_string_free (&test_directory);
3361   _dbus_string_free (&filename);
3362
3363   return retval;
3364 }
3365
3366 static dbus_bool_t
3367 bools_equal (dbus_bool_t a,
3368              dbus_bool_t b)
3369 {
3370   return a ? b : !b;
3371 }
3372
3373 static dbus_bool_t
3374 strings_equal_or_both_null (const char *a,
3375                             const char *b)
3376 {
3377   if (a == NULL || b == NULL)
3378     return a == b;
3379   else
3380     return !strcmp (a, b);
3381 }
3382
3383 static dbus_bool_t
3384 elements_equal (const Element *a,
3385                 const Element *b)
3386 {
3387   if (a->type != b->type)
3388     return FALSE;
3389
3390   if (!bools_equal (a->had_content, b->had_content))
3391     return FALSE;
3392
3393   switch (a->type)
3394     {
3395
3396     case ELEMENT_INCLUDE:
3397       if (!bools_equal (a->d.include.ignore_missing,
3398                         b->d.include.ignore_missing))
3399         return FALSE;
3400       break;
3401
3402     case ELEMENT_POLICY:
3403       if (a->d.policy.type != b->d.policy.type)
3404         return FALSE;
3405       if (a->d.policy.gid_uid_or_at_console != b->d.policy.gid_uid_or_at_console)
3406         return FALSE;
3407       break;
3408
3409     case ELEMENT_LIMIT:
3410       if (strcmp (a->d.limit.name, b->d.limit.name))
3411         return FALSE;
3412       if (a->d.limit.value != b->d.limit.value)
3413         return FALSE;
3414       break;
3415
3416     case ELEMENT_NONE:
3417     case ELEMENT_BUSCONFIG:
3418     case ELEMENT_USER:
3419     case ELEMENT_LISTEN:
3420     case ELEMENT_AUTH:
3421     case ELEMENT_ALLOW:
3422     case ELEMENT_DENY:
3423     case ELEMENT_FORK:
3424     case ELEMENT_PIDFILE:
3425     case ELEMENT_SERVICEDIR:
3426     case ELEMENT_SERVICEHELPER:
3427     case ELEMENT_INCLUDEDIR:
3428     case ELEMENT_CONFIGTYPE:
3429     case ELEMENT_SELINUX:
3430     case ELEMENT_ASSOCIATE:
3431     case ELEMENT_STANDARD_SESSION_SERVICEDIRS:
3432     case ELEMENT_STANDARD_SYSTEM_SERVICEDIRS:
3433     case ELEMENT_KEEP_UMASK:
3434     case ELEMENT_SYSLOG:
3435     case ELEMENT_ALLOW_ANONYMOUS:
3436     case ELEMENT_APPARMOR:
3437     default:
3438       /* do nothing: nothing in the Element struct for these types */
3439       break;
3440     }
3441
3442   return TRUE;
3443
3444 }
3445
3446 static dbus_bool_t
3447 lists_of_elements_equal (DBusList *a,
3448                          DBusList *b)
3449 {
3450   DBusList *ia;
3451   DBusList *ib;
3452
3453   ia = a;
3454   ib = b;
3455   
3456   while (ia != NULL && ib != NULL)
3457     {
3458       if (elements_equal (ia->data, ib->data))
3459         return FALSE;
3460       ia = _dbus_list_get_next_link (&a, ia);
3461       ib = _dbus_list_get_next_link (&b, ib);
3462     }
3463
3464   return ia == NULL && ib == NULL;
3465 }
3466
3467 static dbus_bool_t
3468 lists_of_c_strings_equal (DBusList *a,
3469                           DBusList *b)
3470 {
3471   DBusList *ia;
3472   DBusList *ib;
3473
3474   ia = a;
3475   ib = b;
3476   
3477   while (ia != NULL && ib != NULL)
3478     {
3479       if (strcmp (ia->data, ib->data))
3480         return FALSE;
3481       ia = _dbus_list_get_next_link (&a, ia);
3482       ib = _dbus_list_get_next_link (&b, ib);
3483     }
3484
3485   return ia == NULL && ib == NULL;
3486 }
3487
3488 static dbus_bool_t
3489 lists_of_service_dirs_equal (DBusList *a,
3490                              DBusList *b)
3491 {
3492   DBusList *ia;
3493   DBusList *ib;
3494
3495   ia = a;
3496   ib = b;
3497
3498   while (ia != NULL && ib != NULL)
3499     {
3500       BusConfigServiceDir *da = ia->data;
3501       BusConfigServiceDir *db = ib->data;
3502
3503       if (strcmp (da->path, db->path))
3504         return FALSE;
3505
3506       if (da->flags != db->flags)
3507         return FALSE;
3508
3509       ia = _dbus_list_get_next_link (&a, ia);
3510       ib = _dbus_list_get_next_link (&b, ib);
3511     }
3512
3513   return ia == NULL && ib == NULL;
3514 }
3515
3516 static dbus_bool_t
3517 limits_equal (const BusLimits *a,
3518               const BusLimits *b)
3519 {
3520   return
3521     (a->max_incoming_bytes == b->max_incoming_bytes
3522      || a->max_incoming_unix_fds == b->max_incoming_unix_fds
3523      || a->max_outgoing_bytes == b->max_outgoing_bytes
3524      || a->max_outgoing_unix_fds == b->max_outgoing_unix_fds
3525      || a->max_message_size == b->max_message_size
3526      || a->max_message_unix_fds == b->max_message_unix_fds
3527      || a->activation_timeout == b->activation_timeout
3528      || a->auth_timeout == b->auth_timeout
3529      || a->pending_fd_timeout == b->pending_fd_timeout
3530      || a->max_completed_connections == b->max_completed_connections
3531      || a->max_incomplete_connections == b->max_incomplete_connections
3532      || a->max_connections_per_user == b->max_connections_per_user
3533      || a->max_pending_activations == b->max_pending_activations
3534      || a->max_services_per_connection == b->max_services_per_connection
3535      || a->max_match_rules_per_connection == b->max_match_rules_per_connection
3536      || a->max_replies_per_connection == b->max_replies_per_connection
3537      || a->reply_timeout == b->reply_timeout);
3538 }
3539
3540 static dbus_bool_t
3541 config_parsers_equal (const BusConfigParser *a,
3542                       const BusConfigParser *b)
3543 {
3544   if (!_dbus_string_equal (&a->basedir, &b->basedir))
3545     return FALSE;
3546
3547   if (!lists_of_elements_equal (a->stack, b->stack))
3548     return FALSE;
3549
3550   if (!strings_equal_or_both_null (a->user, b->user))
3551     return FALSE;
3552
3553   if (!lists_of_c_strings_equal (a->listen_on, b->listen_on))
3554     return FALSE;
3555
3556   if (!lists_of_c_strings_equal (a->mechanisms, b->mechanisms))
3557     return FALSE;
3558
3559   if (!lists_of_service_dirs_equal (a->service_dirs, b->service_dirs))
3560     return FALSE;
3561   
3562   /* FIXME: compare policy */
3563
3564   /* FIXME: compare service selinux ID table */
3565
3566   if (! limits_equal (&a->limits, &b->limits))
3567     return FALSE;
3568
3569   if (!strings_equal_or_both_null (a->pidfile, b->pidfile))
3570     return FALSE;
3571
3572   if (! bools_equal (a->fork, b->fork))
3573     return FALSE;
3574
3575   if (! bools_equal (a->keep_umask, b->keep_umask))
3576     return FALSE;
3577
3578   if (! bools_equal (a->is_toplevel, b->is_toplevel))
3579     return FALSE;
3580
3581   return TRUE;
3582 }
3583
3584 static dbus_bool_t
3585 all_are_equiv (const DBusString *target_directory)
3586 {
3587   DBusString filename;
3588   DBusDirIter *dir;
3589   BusConfigParser *first_parser;
3590   BusConfigParser *parser;
3591   DBusError error;
3592   dbus_bool_t equal;
3593   dbus_bool_t retval;
3594
3595   dir = NULL;
3596   first_parser = NULL;
3597   parser = NULL;
3598   retval = FALSE;
3599
3600   if (!_dbus_string_init (&filename))
3601     _dbus_assert_not_reached ("didn't allocate filename string");
3602
3603   dbus_error_init (&error);
3604   dir = _dbus_directory_open (target_directory, &error);
3605   if (dir == NULL)
3606     {
3607       _dbus_warn ("Could not open %s: %s",
3608                   _dbus_string_get_const_data (target_directory),
3609                   error.message);
3610       dbus_error_free (&error);
3611       goto finished;
3612     }
3613
3614   printf ("Comparing equivalent files:\n");
3615
3616  next:
3617   while (_dbus_directory_get_next_file (dir, &filename, &error))
3618     {
3619       DBusString full_path;
3620
3621       if (!_dbus_string_init (&full_path))
3622         _dbus_assert_not_reached ("couldn't init string");
3623
3624       if (!_dbus_string_copy (target_directory, 0, &full_path, 0))
3625         _dbus_assert_not_reached ("couldn't copy dir to full_path");
3626
3627       if (!_dbus_concat_dir_and_file (&full_path, &filename))
3628         _dbus_assert_not_reached ("couldn't concat file to dir");
3629
3630       if (!_dbus_string_ends_with_c_str (&full_path, ".conf"))
3631         {
3632           _dbus_verbose ("Skipping non-.conf file %s\n",
3633                          _dbus_string_get_const_data (&filename));
3634           _dbus_string_free (&full_path);
3635           goto next;
3636         }
3637
3638       printf ("    %s\n", _dbus_string_get_const_data (&filename));
3639
3640       parser = bus_config_load (&full_path, TRUE, NULL, &error);
3641
3642       if (parser == NULL)
3643         {
3644           _dbus_warn ("Could not load file %s: %s",
3645                       _dbus_string_get_const_data (&full_path),
3646                       error.message);
3647           _dbus_string_free (&full_path);
3648           dbus_error_free (&error);
3649           goto finished;
3650         }
3651       else if (first_parser == NULL)
3652         {
3653           _dbus_string_free (&full_path);
3654           first_parser = parser;
3655         }
3656       else
3657         {
3658           _dbus_string_free (&full_path);
3659           equal = config_parsers_equal (first_parser, parser);
3660           bus_config_parser_unref (parser);
3661           if (! equal)
3662             goto finished;
3663         }
3664     }
3665
3666   retval = TRUE;
3667
3668  finished:
3669   _dbus_string_free (&filename);
3670   if (first_parser)
3671     bus_config_parser_unref (first_parser);
3672   if (dir)
3673     _dbus_directory_close (dir);
3674
3675   return retval;
3676   
3677 }
3678
3679 static dbus_bool_t
3680 process_test_equiv_subdir (const DBusString *test_base_dir,
3681                            const char       *subdir)
3682 {
3683   DBusString test_directory;
3684   DBusString filename;
3685   DBusDirIter *dir;
3686   DBusError error;
3687   dbus_bool_t equal;
3688   dbus_bool_t retval;
3689
3690   dir = NULL;
3691   retval = FALSE;
3692
3693   if (!_dbus_string_init (&test_directory))
3694     _dbus_assert_not_reached ("didn't allocate test_directory");
3695
3696   _dbus_string_init_const (&filename, subdir);
3697
3698   if (!_dbus_string_copy (test_base_dir, 0,
3699                           &test_directory, 0))
3700     _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
3701
3702   if (!_dbus_concat_dir_and_file (&test_directory, &filename))
3703     _dbus_assert_not_reached ("couldn't allocate full path");
3704
3705   _dbus_string_free (&filename);
3706   if (!_dbus_string_init (&filename))
3707     _dbus_assert_not_reached ("didn't allocate filename string");
3708
3709   dbus_error_init (&error);
3710   dir = _dbus_directory_open (&test_directory, &error);
3711   if (dir == NULL)
3712     {
3713       _dbus_warn ("Could not open %s: %s",
3714                   _dbus_string_get_const_data (&test_directory),
3715                   error.message);
3716       dbus_error_free (&error);
3717       goto finished;
3718     }
3719
3720   while (_dbus_directory_get_next_file (dir, &filename, &error))
3721     {
3722       DBusString full_path;
3723
3724       /* Skip CVS's magic directories! */
3725       if (_dbus_string_equal_c_str (&filename, "CVS"))
3726         continue;
3727
3728       if (!_dbus_string_init (&full_path))
3729         _dbus_assert_not_reached ("couldn't init string");
3730
3731       if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
3732         _dbus_assert_not_reached ("couldn't copy dir to full_path");
3733
3734       if (!_dbus_concat_dir_and_file (&full_path, &filename))
3735         _dbus_assert_not_reached ("couldn't concat file to dir");
3736       
3737       equal = all_are_equiv (&full_path);
3738       _dbus_string_free (&full_path);
3739
3740       if (!equal)
3741         goto finished;
3742     }
3743
3744   retval = TRUE;
3745
3746  finished:
3747   _dbus_string_free (&test_directory);
3748   _dbus_string_free (&filename);
3749   if (dir)
3750     _dbus_directory_close (dir);
3751
3752   return retval;
3753   
3754 }
3755
3756 static const char *test_session_service_dir_matches[] = 
3757         {
3758 /* will be filled in test_default_session_servicedirs() */
3759 #ifdef DBUS_WIN
3760          NULL, /* install root-based */
3761          NULL, /* CommonProgramFiles-based */
3762 #else
3763          NULL, /* XDG_RUNTIME_DIR-based */
3764          NULL, /* XDG_DATA_HOME-based */
3765          NULL, /* XDG_DATA_DIRS-based */
3766          NULL, /* XDG_DATA_DIRS-based */
3767          DBUS_DATADIR "/dbus-1/services",
3768 #endif
3769          NULL
3770         };
3771
3772 static dbus_bool_t
3773 test_default_session_servicedirs (const DBusString *test_base_dir)
3774 {
3775   BusConfigParser *parser = NULL;
3776   DBusError error = DBUS_ERROR_INIT;
3777   DBusList **dirs;
3778   DBusList *watched_dirs = NULL;
3779   DBusList *link;
3780   DBusString tmp;
3781   DBusString full_path;
3782   DBusString progs;
3783   DBusString install_root_based;
3784   DBusString runtime_dir_based;
3785   DBusString data_home_based;
3786   DBusString data_dirs_based;
3787   DBusString data_dirs_based2;
3788   int i;
3789   dbus_bool_t ret = FALSE;
3790 #ifdef DBUS_WIN
3791   const char *common_progs;
3792 #else
3793   const char *dbus_test_builddir;
3794   const char *xdg_data_home;
3795   const char *xdg_runtime_dir;
3796 #endif
3797
3798   /* On each platform we don't actually use all of these, but it's easier to
3799    * handle the deallocation if we always allocate them, whether needed or
3800    * not */
3801   if (!_dbus_string_init (&full_path) ||
3802       !_dbus_string_init (&progs) ||
3803       !_dbus_string_init (&install_root_based) ||
3804       !_dbus_string_init (&runtime_dir_based) ||
3805       !_dbus_string_init (&data_home_based) ||
3806       !_dbus_string_init (&data_dirs_based) ||
3807       !_dbus_string_init (&data_dirs_based2))
3808     _dbus_assert_not_reached ("OOM allocating strings");
3809
3810   if (!_dbus_string_copy (test_base_dir, 0,
3811                           &full_path, 0))
3812     _dbus_assert_not_reached ("couldn't copy test_base_dir to full_path");
3813
3814   _dbus_string_init_const (&tmp, "valid-config-files");
3815
3816   if (!_dbus_concat_dir_and_file (&full_path, &tmp))
3817     _dbus_assert_not_reached ("couldn't allocate full path");
3818
3819   _dbus_string_init_const (&tmp, "standard-session-dirs.conf");
3820
3821   if (!_dbus_concat_dir_and_file (&full_path, &tmp))
3822     _dbus_assert_not_reached ("couldn't allocate full path");
3823
3824 #ifdef DBUS_WIN
3825   if (!_dbus_string_append (&install_root_based, DBUS_DATADIR) ||
3826       !_dbus_string_append (&install_root_based, "/dbus-1/services") ||
3827       !_dbus_replace_install_prefix (&install_root_based))
3828     goto out;
3829
3830   _dbus_assert (_dbus_path_is_absolute (&install_root_based));
3831
3832   test_session_service_dir_matches[0] = _dbus_string_get_const_data (
3833       &install_root_based);
3834
3835   common_progs = _dbus_getenv ("CommonProgramFiles");
3836
3837   if (common_progs) 
3838     {
3839       if (!_dbus_string_append (&progs, common_progs)) 
3840         goto out;
3841
3842       if (!_dbus_string_append (&progs, "/dbus-1/services")) 
3843         goto out;
3844
3845       test_session_service_dir_matches[1] = _dbus_string_get_const_data(&progs);
3846     }
3847 #else
3848   dbus_test_builddir = _dbus_getenv ("DBUS_TEST_BUILDDIR");
3849   xdg_data_home = _dbus_getenv ("XDG_DATA_HOME");
3850   xdg_runtime_dir = _dbus_getenv ("XDG_RUNTIME_DIR");
3851
3852   if (dbus_test_builddir == NULL || xdg_data_home == NULL ||
3853       xdg_runtime_dir == NULL)
3854     {
3855       printf ("Not testing default session service directories because a "
3856               "build-time testing environment variable is not set: "
3857               "see AM_TESTS_ENVIRONMENT in tests/Makefile.am\n");
3858       ret = TRUE;
3859       goto out;
3860     }
3861
3862   if (!_dbus_string_append (&data_dirs_based, dbus_test_builddir) ||
3863       !_dbus_string_append (&data_dirs_based, "/XDG_DATA_DIRS/dbus-1/services") ||
3864       !_dbus_string_append (&data_dirs_based2, dbus_test_builddir) ||
3865       !_dbus_string_append (&data_dirs_based2, "/XDG_DATA_DIRS2/dbus-1/services") ||
3866       !_dbus_string_append (&runtime_dir_based, xdg_runtime_dir) ||
3867       !_dbus_string_append (&data_home_based, xdg_data_home) ||
3868       !_dbus_string_append (&data_home_based, "/dbus-1/services"))
3869     _dbus_assert_not_reached ("out of memory");
3870
3871   if (!_dbus_ensure_directory (&runtime_dir_based, NULL))
3872     _dbus_assert_not_reached ("Unable to create fake XDG_RUNTIME_DIR");
3873
3874   if (!_dbus_string_append (&runtime_dir_based, "/dbus-1/services"))
3875     _dbus_assert_not_reached ("out of memory");
3876
3877   /* Sanity check: the Makefile sets this up. We assume that if this is
3878    * right, the XDG_DATA_DIRS will be too. */
3879   if (!_dbus_string_starts_with_c_str (&data_home_based, dbus_test_builddir))
3880     _dbus_assert_not_reached ("$XDG_DATA_HOME should start with $DBUS_TEST_BUILDDIR");
3881
3882   if (!_dbus_string_starts_with_c_str (&runtime_dir_based, dbus_test_builddir))
3883     _dbus_assert_not_reached ("$XDG_RUNTIME_DIR should start with $DBUS_TEST_BUILDDIR");
3884
3885   test_session_service_dir_matches[0] = _dbus_string_get_const_data (
3886       &runtime_dir_based);
3887   test_session_service_dir_matches[1] = _dbus_string_get_const_data (
3888       &data_home_based);
3889   test_session_service_dir_matches[2] = _dbus_string_get_const_data (
3890       &data_dirs_based);
3891   test_session_service_dir_matches[3] = _dbus_string_get_const_data (
3892       &data_dirs_based2);
3893 #endif
3894
3895   parser = bus_config_load (&full_path, TRUE, NULL, &error);
3896
3897   if (parser == NULL)
3898     _dbus_assert_not_reached (error.message);
3899
3900   dirs = bus_config_parser_get_service_dirs (parser);
3901
3902   for (link = _dbus_list_get_first_link (dirs), i = 0;
3903        link != NULL;
3904        link = _dbus_list_get_next_link (dirs, link), i++)
3905     {
3906       BusConfigServiceDir *dir = link->data;
3907       BusServiceDirFlags expected = BUS_SERVICE_DIR_FLAGS_NONE;
3908
3909       printf ("    test service dir: '%s'\n", dir->path);
3910       printf ("    current standard service dir: '%s'\n", test_session_service_dir_matches[i]);
3911       if (test_session_service_dir_matches[i] == NULL)
3912         {
3913           printf ("more directories parsed than in match set\n");
3914           goto out;
3915         }
3916  
3917       if (strcmp (test_session_service_dir_matches[i], dir->path) != 0)
3918         {
3919           printf ("'%s' directory does not match '%s' in the match set\n",
3920                   dir->path, test_session_service_dir_matches[i]);
3921           goto out;
3922         }
3923
3924 #ifndef DBUS_WIN
3925       /* On Unix we expect the first directory in the search path to be
3926        * in the XDG_RUNTIME_DIR, and we expect it to have special flags */
3927       if (i == 0)
3928         expected = (BUS_SERVICE_DIR_FLAGS_NO_WATCH |
3929                     BUS_SERVICE_DIR_FLAGS_STRICT_NAMING);
3930 #endif
3931
3932       if (dir->flags != expected)
3933         {
3934           printf ("'%s' directory has flags 0x%x, should be 0x%x\n",
3935                   dir->path, dir->flags, expected);
3936           goto out;
3937         }
3938     }
3939   
3940   if (test_session_service_dir_matches[i] != NULL)
3941     {
3942       printf ("extra data %s in the match set was not matched\n",
3943               test_session_service_dir_matches[i]);
3944       goto out;
3945     }
3946
3947   if (!bus_config_parser_get_watched_dirs (parser, &watched_dirs))
3948     _dbus_assert_not_reached ("out of memory");
3949
3950 #ifdef DBUS_WIN
3951   /* We expect all directories to be watched (not that it matters on Windows,
3952    * because we don't know how) */
3953   i = 0;
3954 #else
3955   /* We expect all directories except the first to be watched, because
3956    * the first one is transient */
3957   i = 1;
3958 #endif
3959
3960   for (link = _dbus_list_get_first_link (&watched_dirs);
3961        link != NULL;
3962        link = _dbus_list_get_next_link (&watched_dirs, link), i++)
3963     {
3964       printf ("    watched service dir: '%s'\n", (const char *) link->data);
3965       printf ("    current standard service dir: '%s'\n",
3966               test_session_service_dir_matches[i]);
3967
3968       if (test_session_service_dir_matches[i] == NULL)
3969         {
3970           printf ("more directories parsed than in match set\n");
3971           goto out;
3972         }
3973
3974       if (strcmp (test_session_service_dir_matches[i],
3975                   (const char *) link->data) != 0)
3976         {
3977           printf ("'%s' directory does not match '%s' in the match set\n",
3978                   (const char *) link->data,
3979                   test_session_service_dir_matches[i]);
3980           goto out;
3981         }
3982     }
3983
3984   if (test_session_service_dir_matches[i] != NULL)
3985     {
3986       printf ("extra data %s in the match set was not matched\n",
3987               test_session_service_dir_matches[i]);
3988       goto out;
3989     }
3990
3991   ret = TRUE;
3992
3993 out:
3994   if (parser != NULL)
3995     bus_config_parser_unref (parser);
3996
3997   _dbus_list_clear (&watched_dirs);
3998   _dbus_string_free (&full_path);
3999   _dbus_string_free (&install_root_based);
4000   _dbus_string_free (&progs);
4001   _dbus_string_free (&runtime_dir_based);
4002   _dbus_string_free (&data_home_based);
4003   _dbus_string_free (&data_dirs_based);
4004   _dbus_string_free (&data_dirs_based2);
4005   return ret;
4006 }
4007
4008 #ifndef DBUS_WIN
4009 static const char *test_system_service_dir_matches[] = 
4010         {
4011          "/usr/local/share/dbus-1/system-services",
4012          "/usr/share/dbus-1/system-services",
4013          DBUS_DATADIR"/dbus-1/system-services",
4014          "/lib/dbus-1/system-services",
4015          NULL
4016         };
4017
4018 static dbus_bool_t
4019 test_default_system_servicedirs (void)
4020 {
4021   DBusList *dirs;
4022   DBusList *link;
4023   int i;
4024
4025   dirs = NULL;
4026
4027   if (!_dbus_get_standard_system_servicedirs (&dirs))
4028     _dbus_assert_not_reached ("couldn't get stardard dirs");
4029
4030   /* make sure we read and parse the env variable correctly */
4031   i = 0;
4032   while ((link = _dbus_list_pop_first_link (&dirs)))
4033     {
4034       printf ("    test service dir: %s\n", (char *)link->data);
4035       if (test_system_service_dir_matches[i] == NULL)
4036         {
4037           printf ("more directories parsed than in match set\n");
4038           dbus_free (link->data);
4039           _dbus_list_free_link (link);
4040           return FALSE;
4041         }
4042  
4043       if (strcmp (test_system_service_dir_matches[i], 
4044                   (char *)link->data) != 0)
4045         {
4046           printf ("%s directory does not match %s in the match set\n", 
4047                   (char *)link->data,
4048                   test_system_service_dir_matches[i]);
4049           dbus_free (link->data);
4050           _dbus_list_free_link (link);
4051           return FALSE;
4052         }
4053
4054       ++i;
4055
4056       dbus_free (link->data);
4057       _dbus_list_free_link (link);
4058     }
4059   
4060   if (test_system_service_dir_matches[i] != NULL)
4061     {
4062       printf ("extra data %s in the match set was not matched\n",
4063               test_system_service_dir_matches[i]);
4064
4065       return FALSE;
4066     }
4067     
4068   return TRUE;
4069 }
4070 #endif
4071                    
4072 dbus_bool_t
4073 bus_config_parser_test (const DBusString *test_data_dir)
4074 {
4075   if (test_data_dir == NULL ||
4076       _dbus_string_get_length (test_data_dir) == 0)
4077     {
4078       printf ("No test data\n");
4079       return TRUE;
4080     }
4081
4082   if (!test_default_session_servicedirs (test_data_dir))
4083     return FALSE;
4084
4085 #ifdef DBUS_WIN
4086   printf("default system service dir skipped\n");
4087 #else
4088   if (!test_default_system_servicedirs())
4089     return FALSE;
4090 #endif
4091
4092   if (!process_test_valid_subdir (test_data_dir, "valid-config-files", VALID))
4093     return FALSE;
4094
4095 #ifndef DBUS_WIN
4096   if (!process_test_valid_subdir (test_data_dir, "valid-config-files-system", VALID))
4097     return FALSE;
4098 #endif
4099
4100   if (!process_test_valid_subdir (test_data_dir, "invalid-config-files", INVALID))
4101     return FALSE;
4102
4103   if (!process_test_equiv_subdir (test_data_dir, "equiv-config-files"))
4104     return FALSE;
4105
4106   return TRUE;
4107 }
4108
4109 #endif /* DBUS_ENABLE_EMBEDDED_TESTS */
4110