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