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