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