Merge branch 'arg0namespace-24317'
[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_CONFIGTYPE)
694     {
695       if (!check_no_attributes (parser, "type", attribute_names, attribute_values, error))
696         return FALSE;
697
698       if (push_element (parser, ELEMENT_CONFIGTYPE) == 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                           receive_interface ||
1228                           receive_member ||
1229                           receive_error ||
1230                           receive_sender ||
1231                           receive_requested_reply ||
1232                           own ||
1233                           user ||
1234                           group)) ||
1235
1236       (send_member && (send_error ||
1237                        receive_interface ||
1238                        receive_member ||
1239                        receive_error ||
1240                        receive_sender ||
1241                        receive_requested_reply ||
1242                        own ||
1243                        user ||
1244                        group)) ||
1245
1246       (send_error && (receive_interface ||
1247                       receive_member ||
1248                       receive_error ||
1249                       receive_sender ||
1250                       receive_requested_reply ||
1251                       own ||
1252                       user ||
1253                       group)) ||
1254
1255       (send_destination && (receive_interface ||
1256                             receive_member ||
1257                             receive_error ||
1258                             receive_sender ||
1259                             receive_requested_reply ||
1260                             own ||
1261                             user ||
1262                             group)) ||
1263
1264       (send_type && (receive_interface ||
1265                      receive_member ||
1266                      receive_error ||
1267                      receive_sender ||
1268                      receive_requested_reply ||
1269                      own ||
1270                      user ||
1271                      group)) ||
1272
1273       (send_path && (receive_interface ||
1274                      receive_member ||
1275                      receive_error ||
1276                      receive_sender ||
1277                      receive_requested_reply ||
1278                      own ||
1279                      user ||
1280                      group)) ||
1281
1282       (send_requested_reply && (receive_interface ||
1283                                 receive_member ||
1284                                 receive_error ||
1285                                 receive_sender ||
1286                                 receive_requested_reply ||
1287                                 own ||
1288                                 user ||
1289                                 group)) ||
1290
1291       (receive_interface && (receive_error ||
1292                              own ||
1293                              user ||
1294                              group)) ||
1295
1296       (receive_member && (receive_error ||
1297                           own ||
1298                           user ||
1299                           group)) ||
1300
1301       (receive_error && (own ||
1302                          user ||
1303                          group)) ||
1304
1305       (eavesdrop && (own ||
1306                      user ||
1307                      group)) ||
1308
1309       (receive_requested_reply && (own ||
1310                                    user ||
1311                                    group)) ||
1312
1313       (own && (user || group)) ||
1314
1315       (user && group))
1316     {
1317       dbus_set_error (error, DBUS_ERROR_FAILED,
1318                       "Invalid combination of attributes on element <%s>",
1319                       element_name);
1320       return FALSE;
1321     }
1322   
1323   rule = NULL;
1324
1325   /* In BusPolicyRule, NULL represents wildcard.
1326    * In the config file, '*' represents it.
1327    */
1328 #define IS_WILDCARD(str) ((str) && ((str)[0]) == '*' && ((str)[1]) == '\0')
1329
1330   if (send_interface || send_member || send_error || send_destination ||
1331       send_path || send_type || send_requested_reply)
1332     {
1333       int message_type;
1334       
1335       if (IS_WILDCARD (send_interface))
1336         send_interface = NULL;
1337       if (IS_WILDCARD (send_member))
1338         send_member = NULL;
1339       if (IS_WILDCARD (send_error))
1340         send_error = NULL;
1341       if (IS_WILDCARD (send_destination))
1342         send_destination = NULL;
1343       if (IS_WILDCARD (send_path))
1344         send_path = NULL;
1345       if (IS_WILDCARD (send_type))
1346         send_type = NULL;
1347
1348       message_type = DBUS_MESSAGE_TYPE_INVALID;
1349       if (send_type != NULL)
1350         {
1351           message_type = dbus_message_type_from_string (send_type);
1352           if (message_type == DBUS_MESSAGE_TYPE_INVALID)
1353             {
1354               dbus_set_error (error, DBUS_ERROR_FAILED,
1355                               "Bad message type \"%s\"",
1356                               send_type);
1357               return FALSE;
1358             }
1359         }
1360
1361       if (eavesdrop &&
1362           !(strcmp (eavesdrop, "true") == 0 ||
1363             strcmp (eavesdrop, "false") == 0))
1364         {
1365           dbus_set_error (error, DBUS_ERROR_FAILED,
1366                           "Bad value \"%s\" for %s attribute, must be true or false",
1367                           "eavesdrop", eavesdrop);
1368           return FALSE;
1369         }
1370
1371       if (send_requested_reply &&
1372           !(strcmp (send_requested_reply, "true") == 0 ||
1373             strcmp (send_requested_reply, "false") == 0))
1374         {
1375           dbus_set_error (error, DBUS_ERROR_FAILED,
1376                           "Bad value \"%s\" for %s attribute, must be true or false",
1377                           "send_requested_reply", send_requested_reply);
1378           return FALSE;
1379         }
1380       
1381       rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow); 
1382       if (rule == NULL)
1383         goto nomem;
1384       
1385       if (eavesdrop)
1386         rule->d.send.eavesdrop = (strcmp (eavesdrop, "true") == 0);
1387
1388       if (log)
1389         rule->d.send.log = (strcmp (log, "true") == 0);
1390
1391       if (send_requested_reply)
1392         rule->d.send.requested_reply = (strcmp (send_requested_reply, "true") == 0);
1393
1394       rule->d.send.message_type = message_type;
1395       rule->d.send.path = _dbus_strdup (send_path);
1396       rule->d.send.interface = _dbus_strdup (send_interface);
1397       rule->d.send.member = _dbus_strdup (send_member);
1398       rule->d.send.error = _dbus_strdup (send_error);
1399       rule->d.send.destination = _dbus_strdup (send_destination);
1400       if (send_path && rule->d.send.path == NULL)
1401         goto nomem;
1402       if (send_interface && rule->d.send.interface == NULL)
1403         goto nomem;
1404       if (send_member && rule->d.send.member == NULL)
1405         goto nomem;
1406       if (send_error && rule->d.send.error == NULL)
1407         goto nomem;
1408       if (send_destination && rule->d.send.destination == NULL)
1409         goto nomem;
1410     }
1411   else if (receive_interface || receive_member || receive_error || receive_sender ||
1412            receive_path || receive_type || eavesdrop || receive_requested_reply)
1413     {
1414       int message_type;
1415       
1416       if (IS_WILDCARD (receive_interface))
1417         receive_interface = NULL;
1418       if (IS_WILDCARD (receive_member))
1419         receive_member = NULL;
1420       if (IS_WILDCARD (receive_error))
1421         receive_error = NULL;
1422       if (IS_WILDCARD (receive_sender))
1423         receive_sender = NULL;
1424       if (IS_WILDCARD (receive_path))
1425         receive_path = NULL;
1426       if (IS_WILDCARD (receive_type))
1427         receive_type = NULL;
1428
1429       message_type = DBUS_MESSAGE_TYPE_INVALID;
1430       if (receive_type != NULL)
1431         {
1432           message_type = dbus_message_type_from_string (receive_type);
1433           if (message_type == DBUS_MESSAGE_TYPE_INVALID)
1434             {
1435               dbus_set_error (error, DBUS_ERROR_FAILED,
1436                               "Bad message type \"%s\"",
1437                               receive_type);
1438               return FALSE;
1439             }
1440         }
1441
1442
1443       if (eavesdrop &&
1444           !(strcmp (eavesdrop, "true") == 0 ||
1445             strcmp (eavesdrop, "false") == 0))
1446         {
1447           dbus_set_error (error, DBUS_ERROR_FAILED,
1448                           "Bad value \"%s\" for %s attribute, must be true or false",
1449                           "eavesdrop", eavesdrop);
1450           return FALSE;
1451         }
1452
1453       if (receive_requested_reply &&
1454           !(strcmp (receive_requested_reply, "true") == 0 ||
1455             strcmp (receive_requested_reply, "false") == 0))
1456         {
1457           dbus_set_error (error, DBUS_ERROR_FAILED,
1458                           "Bad value \"%s\" for %s attribute, must be true or false",
1459                           "receive_requested_reply", receive_requested_reply);
1460           return FALSE;
1461         }
1462       
1463       rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow); 
1464       if (rule == NULL)
1465         goto nomem;
1466
1467       if (eavesdrop)
1468         rule->d.receive.eavesdrop = (strcmp (eavesdrop, "true") == 0);
1469
1470       if (receive_requested_reply)
1471         rule->d.receive.requested_reply = (strcmp (receive_requested_reply, "true") == 0);
1472       
1473       rule->d.receive.message_type = message_type;
1474       rule->d.receive.path = _dbus_strdup (receive_path);
1475       rule->d.receive.interface = _dbus_strdup (receive_interface);
1476       rule->d.receive.member = _dbus_strdup (receive_member);
1477       rule->d.receive.error = _dbus_strdup (receive_error);
1478       rule->d.receive.origin = _dbus_strdup (receive_sender);
1479
1480       if (receive_path && rule->d.receive.path == NULL)
1481         goto nomem;
1482       if (receive_interface && rule->d.receive.interface == NULL)
1483         goto nomem;
1484       if (receive_member && rule->d.receive.member == NULL)
1485         goto nomem;
1486       if (receive_error && rule->d.receive.error == NULL)
1487         goto nomem;
1488       if (receive_sender && rule->d.receive.origin == NULL)
1489         goto nomem;
1490     }
1491   else if (own)
1492     {
1493       rule = bus_policy_rule_new (BUS_POLICY_RULE_OWN, allow); 
1494       if (rule == NULL)
1495         goto nomem;
1496
1497       if (IS_WILDCARD (own))
1498         own = NULL;
1499       
1500       rule->d.own.service_name = _dbus_strdup (own);
1501       if (own && rule->d.own.service_name == NULL)
1502         goto nomem;
1503     }
1504   else if (user)
1505     {      
1506       if (IS_WILDCARD (user))
1507         {
1508           rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow); 
1509           if (rule == NULL)
1510             goto nomem;
1511
1512           rule->d.user.uid = DBUS_UID_UNSET;
1513         }
1514       else
1515         {
1516           DBusString username;
1517           dbus_uid_t uid;
1518           
1519           _dbus_string_init_const (&username, user);
1520       
1521           if (_dbus_parse_unix_user_from_config (&username, &uid))
1522             {
1523               rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow); 
1524               if (rule == NULL)
1525                 goto nomem;
1526
1527               rule->d.user.uid = uid;
1528             }
1529           else
1530             {
1531               _dbus_warn ("Unknown username \"%s\" on element <%s>\n",
1532                           user, element_name);
1533             }
1534         }
1535     }
1536   else if (group)
1537     {
1538       if (IS_WILDCARD (group))
1539         {
1540           rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow); 
1541           if (rule == NULL)
1542             goto nomem;
1543
1544           rule->d.group.gid = DBUS_GID_UNSET;
1545         }
1546       else
1547         {
1548           DBusString groupname;
1549           dbus_gid_t gid;
1550           
1551           _dbus_string_init_const (&groupname, group);
1552           
1553           if (_dbus_parse_unix_group_from_config (&groupname, &gid))
1554             {
1555               rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow); 
1556               if (rule == NULL)
1557                 goto nomem;
1558
1559               rule->d.group.gid = gid;
1560             }
1561           else
1562             {
1563               _dbus_warn ("Unknown group \"%s\" on element <%s>\n",
1564                           group, element_name);
1565             }
1566         }
1567     }
1568   else
1569     _dbus_assert_not_reached ("Did not handle some combination of attributes on <allow> or <deny>");
1570
1571   if (rule != NULL)
1572     {
1573       Element *pe;
1574       
1575       pe = peek_element (parser);      
1576       _dbus_assert (pe != NULL);
1577       _dbus_assert (pe->type == ELEMENT_POLICY);
1578
1579       switch (pe->d.policy.type)
1580         {
1581         case POLICY_IGNORED:
1582           /* drop the rule on the floor */
1583           break;
1584           
1585         case POLICY_DEFAULT:
1586           if (!bus_policy_append_default_rule (parser->policy, rule))
1587             goto nomem;
1588           break;
1589         case POLICY_MANDATORY:
1590           if (!bus_policy_append_mandatory_rule (parser->policy, rule))
1591             goto nomem;
1592           break;
1593         case POLICY_USER:
1594           if (!BUS_POLICY_RULE_IS_PER_CLIENT (rule))
1595             {
1596               dbus_set_error (error, DBUS_ERROR_FAILED,
1597                               "<%s> rule cannot be per-user because it has bus-global semantics",
1598                               element_name);
1599               goto failed;
1600             }
1601           
1602           if (!bus_policy_append_user_rule (parser->policy, pe->d.policy.gid_uid_or_at_console,
1603                                             rule))
1604             goto nomem;
1605           break;
1606         case POLICY_GROUP:
1607           if (!BUS_POLICY_RULE_IS_PER_CLIENT (rule))
1608             {
1609               dbus_set_error (error, DBUS_ERROR_FAILED,
1610                               "<%s> rule cannot be per-group because it has bus-global semantics",
1611                               element_name);
1612               goto failed;
1613             }
1614           
1615           if (!bus_policy_append_group_rule (parser->policy, pe->d.policy.gid_uid_or_at_console,
1616                                              rule))
1617             goto nomem;
1618           break;
1619         
1620
1621         case POLICY_CONSOLE:
1622           if (!bus_policy_append_console_rule (parser->policy, pe->d.policy.gid_uid_or_at_console,
1623                                                rule))
1624             goto nomem;
1625           break;
1626         }
1627  
1628       bus_policy_rule_unref (rule);
1629       rule = NULL;
1630     }
1631   
1632   return TRUE;
1633
1634  nomem:
1635   BUS_SET_OOM (error);
1636  failed:
1637   if (rule)
1638     bus_policy_rule_unref (rule);
1639   return FALSE;
1640 }
1641
1642 static dbus_bool_t
1643 start_policy_child (BusConfigParser   *parser,
1644                     const char        *element_name,
1645                     const char       **attribute_names,
1646                     const char       **attribute_values,
1647                     DBusError         *error)
1648 {
1649   if (strcmp (element_name, "allow") == 0)
1650     {
1651       if (!append_rule_from_element (parser, element_name,
1652                                      attribute_names, attribute_values,
1653                                      TRUE, error))
1654         return FALSE;
1655       
1656       if (push_element (parser, ELEMENT_ALLOW) == NULL)
1657         {
1658           BUS_SET_OOM (error);
1659           return FALSE;
1660         }
1661       
1662       return TRUE;
1663     }
1664   else if (strcmp (element_name, "deny") == 0)
1665     {
1666       if (!append_rule_from_element (parser, element_name,
1667                                      attribute_names, attribute_values,
1668                                      FALSE, error))
1669         return FALSE;
1670       
1671       if (push_element (parser, ELEMENT_DENY) == NULL)
1672         {
1673           BUS_SET_OOM (error);
1674           return FALSE;
1675         }
1676       
1677       return TRUE;
1678     }
1679   else
1680     {
1681       dbus_set_error (error, DBUS_ERROR_FAILED,
1682                       "Element <%s> not allowed inside <%s> in configuration file",
1683                       element_name, "policy");
1684       return FALSE;
1685     }
1686 }
1687
1688 static dbus_bool_t
1689 start_selinux_child (BusConfigParser   *parser,
1690                      const char        *element_name,
1691                      const char       **attribute_names,
1692                      const char       **attribute_values,
1693                      DBusError         *error)
1694 {
1695   char *own_copy;
1696   char *context_copy;
1697
1698   own_copy = NULL;
1699   context_copy = NULL;
1700
1701   if (strcmp (element_name, "associate") == 0)
1702     {
1703       const char *own;
1704       const char *context;
1705       
1706       if (!locate_attributes (parser, "associate",
1707                               attribute_names,
1708                               attribute_values,
1709                               error,
1710                               "own", &own,
1711                               "context", &context,
1712                               NULL))
1713         return FALSE;
1714       
1715       if (push_element (parser, ELEMENT_ASSOCIATE) == NULL)
1716         {
1717           BUS_SET_OOM (error);
1718           return FALSE;
1719         }
1720
1721       if (own == NULL || context == NULL)
1722         {
1723           dbus_set_error (error, DBUS_ERROR_FAILED,
1724                           "Element <associate> must have attributes own=\"<servicename>\" and context=\"<selinux context>\"");
1725           return FALSE;
1726         }
1727
1728       own_copy = _dbus_strdup (own);
1729       if (own_copy == NULL)
1730         goto oom;
1731       context_copy = _dbus_strdup (context);
1732       if (context_copy == NULL)
1733         goto oom;
1734
1735       if (!_dbus_hash_table_insert_string (parser->service_context_table,
1736                                            own_copy, context_copy))
1737         goto oom;
1738
1739       return TRUE;
1740     }
1741   else
1742     {
1743       dbus_set_error (error, DBUS_ERROR_FAILED,
1744                       "Element <%s> not allowed inside <%s> in configuration file",
1745                       element_name, "selinux");
1746       return FALSE;
1747     }
1748
1749  oom:
1750   if (own_copy)
1751     dbus_free (own_copy);
1752
1753   if (context_copy)  
1754     dbus_free (context_copy);
1755
1756   BUS_SET_OOM (error);
1757   return FALSE;
1758 }
1759
1760 dbus_bool_t
1761 bus_config_parser_start_element (BusConfigParser   *parser,
1762                                  const char        *element_name,
1763                                  const char       **attribute_names,
1764                                  const char       **attribute_values,
1765                                  DBusError         *error)
1766 {
1767   ElementType t;
1768
1769   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1770
1771   /* printf ("START: %s\n", element_name); */
1772   
1773   t = top_element_type (parser);
1774
1775   if (t == ELEMENT_NONE)
1776     {
1777       if (strcmp (element_name, "busconfig") == 0)
1778         {
1779           if (!check_no_attributes (parser, "busconfig", attribute_names, attribute_values, error))
1780             return FALSE;
1781           
1782           if (push_element (parser, ELEMENT_BUSCONFIG) == NULL)
1783             {
1784               BUS_SET_OOM (error);
1785               return FALSE;
1786             }
1787
1788           return TRUE;
1789         }
1790       else
1791         {
1792           dbus_set_error (error, DBUS_ERROR_FAILED,
1793                           "Unknown element <%s> at root of configuration file",
1794                           element_name);
1795           return FALSE;
1796         }
1797     }
1798   else if (t == ELEMENT_BUSCONFIG)
1799     {
1800       return start_busconfig_child (parser, element_name,
1801                                     attribute_names, attribute_values,
1802                                     error);
1803     }
1804   else if (t == ELEMENT_POLICY)
1805     {
1806       return start_policy_child (parser, element_name,
1807                                  attribute_names, attribute_values,
1808                                  error);
1809     }
1810   else if (t == ELEMENT_SELINUX)
1811     {
1812       return start_selinux_child (parser, element_name,
1813                                   attribute_names, attribute_values,
1814                                   error);
1815     }
1816   else
1817     {
1818       dbus_set_error (error, DBUS_ERROR_FAILED,
1819                       "Element <%s> is not allowed in this context",
1820                       element_name);
1821       return FALSE;
1822     }  
1823 }
1824
1825 static dbus_bool_t
1826 set_limit (BusConfigParser *parser,
1827            const char      *name,
1828            long             value,
1829            DBusError       *error)
1830 {
1831   dbus_bool_t must_be_positive;
1832   dbus_bool_t must_be_int;
1833
1834   must_be_int = FALSE;
1835   must_be_positive = FALSE;
1836   
1837   if (strcmp (name, "max_incoming_bytes") == 0)
1838     {
1839       must_be_positive = TRUE;
1840       parser->limits.max_incoming_bytes = value;
1841     }
1842   else if (strcmp (name, "max_incoming_unix_fds") == 0)
1843     {
1844       must_be_positive = TRUE;
1845       parser->limits.max_incoming_unix_fds = value;
1846     }
1847   else if (strcmp (name, "max_outgoing_bytes") == 0)
1848     {
1849       must_be_positive = TRUE;
1850       parser->limits.max_outgoing_bytes = value;
1851     }
1852   else if (strcmp (name, "max_outgoing_unix_fds") == 0)
1853     {
1854       must_be_positive = TRUE;
1855       parser->limits.max_outgoing_unix_fds = value;
1856     }
1857   else if (strcmp (name, "max_message_size") == 0)
1858     {
1859       must_be_positive = TRUE;
1860       parser->limits.max_message_size = value;
1861     }
1862   else if (strcmp (name, "max_message_unix_fds") == 0)
1863     {
1864       must_be_positive = TRUE;
1865       parser->limits.max_message_unix_fds = value;
1866     }
1867   else if (strcmp (name, "service_start_timeout") == 0)
1868     {
1869       must_be_positive = TRUE;
1870       must_be_int = TRUE;
1871       parser->limits.activation_timeout = value;
1872     }
1873   else if (strcmp (name, "auth_timeout") == 0)
1874     {
1875       must_be_positive = TRUE;
1876       must_be_int = TRUE;
1877       parser->limits.auth_timeout = value;
1878     }
1879   else if (strcmp (name, "reply_timeout") == 0)
1880     {
1881       must_be_positive = TRUE;
1882       must_be_int = TRUE;
1883       parser->limits.reply_timeout = value;
1884     }
1885   else if (strcmp (name, "max_completed_connections") == 0)
1886     {
1887       must_be_positive = TRUE;
1888       must_be_int = TRUE;
1889       parser->limits.max_completed_connections = value;
1890     }
1891   else if (strcmp (name, "max_incomplete_connections") == 0)
1892     {
1893       must_be_positive = TRUE;
1894       must_be_int = TRUE;
1895       parser->limits.max_incomplete_connections = value;
1896     }
1897   else if (strcmp (name, "max_connections_per_user") == 0)
1898     {
1899       must_be_positive = TRUE;
1900       must_be_int = TRUE;
1901       parser->limits.max_connections_per_user = value;
1902     }
1903   else if (strcmp (name, "max_pending_service_starts") == 0)
1904     {
1905       must_be_positive = TRUE;
1906       must_be_int = TRUE;
1907       parser->limits.max_pending_activations = value;
1908     }
1909   else if (strcmp (name, "max_names_per_connection") == 0)
1910     {
1911       must_be_positive = TRUE;
1912       must_be_int = TRUE;
1913       parser->limits.max_services_per_connection = value;
1914     }
1915   else if (strcmp (name, "max_match_rules_per_connection") == 0)
1916     {
1917       must_be_positive = TRUE;
1918       must_be_int = TRUE;
1919       parser->limits.max_match_rules_per_connection = value;
1920     }
1921   else if (strcmp (name, "max_replies_per_connection") == 0)
1922     {
1923       must_be_positive = TRUE;
1924       must_be_int = TRUE;
1925       parser->limits.max_replies_per_connection = value;
1926     }
1927   else
1928     {
1929       dbus_set_error (error, DBUS_ERROR_FAILED,
1930                       "There is no limit called \"%s\"\n",
1931                       name);
1932       return FALSE;
1933     }
1934   
1935   if (must_be_positive && value < 0)
1936     {
1937       dbus_set_error (error, DBUS_ERROR_FAILED,
1938                       "<limit name=\"%s\"> must be a positive number\n",
1939                       name);
1940       return FALSE;
1941     }
1942
1943   if (must_be_int &&
1944       (value < _DBUS_INT_MIN || value > _DBUS_INT_MAX))
1945     {
1946       dbus_set_error (error, DBUS_ERROR_FAILED,
1947                       "<limit name=\"%s\"> value is too large\n",
1948                       name);
1949       return FALSE;
1950     }
1951
1952   return TRUE;  
1953 }
1954
1955 dbus_bool_t
1956 bus_config_parser_end_element (BusConfigParser   *parser,
1957                                const char        *element_name,
1958                                DBusError         *error)
1959 {
1960   ElementType t;
1961   const char *n;
1962   Element *e;
1963
1964   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1965
1966   /* printf ("END: %s\n", element_name); */
1967   
1968   t = top_element_type (parser);
1969
1970   if (t == ELEMENT_NONE)
1971     {
1972       /* should probably be an assertion failure but
1973        * being paranoid about XML parsers
1974        */
1975       dbus_set_error (error, DBUS_ERROR_FAILED,
1976                       "XML parser ended element with no element on the stack");
1977       return FALSE;
1978     }
1979
1980   n = bus_config_parser_element_type_to_name (t);
1981   _dbus_assert (n != NULL);
1982   if (strcmp (n, element_name) != 0)
1983     {
1984       /* should probably be an assertion failure but
1985        * being paranoid about XML parsers
1986        */
1987       dbus_set_error (error, DBUS_ERROR_FAILED,
1988                       "XML element <%s> ended but topmost element on the stack was <%s>",
1989                       element_name, n);
1990       return FALSE;
1991     }
1992
1993   e = peek_element (parser);
1994   _dbus_assert (e != NULL);
1995
1996   switch (e->type)
1997     {
1998     case ELEMENT_NONE:
1999       _dbus_assert_not_reached ("element in stack has no type");
2000       break;
2001
2002     case ELEMENT_INCLUDE:
2003     case ELEMENT_USER:
2004     case ELEMENT_CONFIGTYPE:
2005     case ELEMENT_LISTEN:
2006     case ELEMENT_PIDFILE:
2007     case ELEMENT_AUTH:
2008     case ELEMENT_SERVICEDIR:
2009     case ELEMENT_SERVICEHELPER:
2010     case ELEMENT_INCLUDEDIR:
2011     case ELEMENT_LIMIT:
2012       if (!e->had_content)
2013         {
2014           dbus_set_error (error, DBUS_ERROR_FAILED,
2015                           "XML element <%s> was expected to have content inside it",
2016                           bus_config_parser_element_type_to_name (e->type));
2017           return FALSE;
2018         }
2019
2020       if (e->type == ELEMENT_LIMIT)
2021         {
2022           if (!set_limit (parser, e->d.limit.name, e->d.limit.value,
2023                           error))
2024             return FALSE;
2025         }
2026       break;
2027
2028     case ELEMENT_BUSCONFIG:
2029     case ELEMENT_POLICY:
2030     case ELEMENT_ALLOW:
2031     case ELEMENT_DENY:
2032     case ELEMENT_FORK:
2033     case ELEMENT_SYSLOG:
2034     case ELEMENT_KEEP_UMASK:
2035     case ELEMENT_SELINUX:
2036     case ELEMENT_ASSOCIATE:
2037     case ELEMENT_STANDARD_SESSION_SERVICEDIRS:
2038     case ELEMENT_STANDARD_SYSTEM_SERVICEDIRS:
2039     case ELEMENT_ALLOW_ANONYMOUS:
2040       break;
2041     }
2042
2043   pop_element (parser);
2044
2045   return TRUE;
2046 }
2047
2048 static dbus_bool_t
2049 all_whitespace (const DBusString *str)
2050 {
2051   int i;
2052
2053   _dbus_string_skip_white (str, 0, &i);
2054
2055   return i == _dbus_string_get_length (str);
2056 }
2057
2058 static dbus_bool_t
2059 make_full_path (const DBusString *basedir,
2060                 const DBusString *filename,
2061                 DBusString       *full_path)
2062 {
2063   if (_dbus_path_is_absolute (filename))
2064     {
2065       return _dbus_string_copy (filename, 0, full_path, 0);
2066     }
2067   else
2068     {
2069       if (!_dbus_string_copy (basedir, 0, full_path, 0))
2070         return FALSE;
2071       
2072       if (!_dbus_concat_dir_and_file (full_path, filename))
2073         return FALSE;
2074
2075       return TRUE;
2076     }
2077 }
2078
2079 static dbus_bool_t
2080 include_file (BusConfigParser   *parser,
2081               const DBusString  *filename,
2082               dbus_bool_t        ignore_missing,
2083               DBusError         *error)
2084 {
2085   /* FIXME good test case for this would load each config file in the
2086    * test suite both alone, and as an include, and check
2087    * that the result is the same
2088    */
2089   BusConfigParser *included;
2090   const char *filename_str;
2091   DBusError tmp_error;
2092         
2093   dbus_error_init (&tmp_error);
2094
2095   filename_str = _dbus_string_get_const_data (filename);
2096
2097   /* Check to make sure this file hasn't already been included. */
2098   if (seen_include (parser, filename))
2099     {
2100       dbus_set_error (error, DBUS_ERROR_FAILED,
2101                       "Circular inclusion of file '%s'",
2102                       filename_str);
2103       return FALSE;
2104     }
2105   
2106   if (! _dbus_list_append (&parser->included_files, (void *) filename_str))
2107     {
2108       BUS_SET_OOM (error);
2109       return FALSE;
2110     }
2111
2112   /* Since parser is passed in as the parent, included
2113      inherits parser's limits. */
2114   included = bus_config_load (filename, FALSE, parser, &tmp_error);
2115
2116   _dbus_list_pop_last (&parser->included_files);
2117
2118   if (included == NULL)
2119     {
2120       _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
2121
2122       if (dbus_error_has_name (&tmp_error, DBUS_ERROR_FILE_NOT_FOUND) &&
2123           ignore_missing)
2124         {
2125           dbus_error_free (&tmp_error);
2126           return TRUE;
2127         }
2128       else
2129         {
2130           dbus_move_error (&tmp_error, error);
2131           return FALSE;
2132         }
2133     }
2134   else
2135     {
2136       _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
2137
2138       if (!merge_included (parser, included, error))
2139         {
2140           bus_config_parser_unref (included);
2141           return FALSE;
2142         }
2143
2144       /* Copy included's limits back to parser. */
2145       parser->limits = included->limits;
2146
2147       bus_config_parser_unref (included);
2148       return TRUE;
2149     }
2150 }
2151
2152 static dbus_bool_t
2153 servicehelper_path (BusConfigParser   *parser,
2154                     const DBusString  *filename,
2155                     DBusError         *error)
2156 {
2157   const char *filename_str;
2158   char *servicehelper;
2159
2160   filename_str = _dbus_string_get_const_data (filename);
2161
2162   /* copy to avoid overwriting with NULL on OOM */
2163   servicehelper = _dbus_strdup (filename_str);
2164
2165   /* check for OOM */
2166   if (servicehelper == NULL)
2167     {
2168       BUS_SET_OOM (error);
2169       return FALSE;
2170     }
2171
2172   /* save the latest servicehelper only if not OOM */
2173   dbus_free (parser->servicehelper);
2174   parser->servicehelper = servicehelper;
2175
2176   /* We don't check whether the helper exists; instead we
2177    * would just fail to ever activate anything if it doesn't.
2178    * This allows an admin to fix the problem if it doesn't exist.
2179    * It also allows the parser test suite to successfully parse
2180    * test cases without installing the helper. ;-)
2181    */
2182   
2183   return TRUE;
2184 }
2185
2186 static dbus_bool_t
2187 include_dir (BusConfigParser   *parser,
2188              const DBusString  *dirname,
2189              DBusError         *error)
2190 {
2191   DBusString filename;
2192   dbus_bool_t retval;
2193   DBusError tmp_error;
2194   DBusDirIter *dir;
2195   char *s;
2196   
2197   if (!_dbus_string_init (&filename))
2198     {
2199       BUS_SET_OOM (error);
2200       return FALSE;
2201     }
2202
2203   retval = FALSE;
2204   
2205   dir = _dbus_directory_open (dirname, error);
2206
2207   if (dir == NULL)
2208     goto failed;
2209
2210   dbus_error_init (&tmp_error);
2211   while (_dbus_directory_get_next_file (dir, &filename, &tmp_error))
2212     {
2213       DBusString full_path;
2214
2215       if (!_dbus_string_init (&full_path))
2216         {
2217           BUS_SET_OOM (error);
2218           goto failed;
2219         }
2220
2221       if (!_dbus_string_copy (dirname, 0, &full_path, 0))
2222         {
2223           BUS_SET_OOM (error);
2224           _dbus_string_free (&full_path);
2225           goto failed;
2226         }      
2227
2228       if (!_dbus_concat_dir_and_file (&full_path, &filename))
2229         {
2230           BUS_SET_OOM (error);
2231           _dbus_string_free (&full_path);
2232           goto failed;
2233         }
2234       
2235       if (_dbus_string_ends_with_c_str (&full_path, ".conf"))
2236         {
2237           if (!include_file (parser, &full_path, TRUE, error))
2238             {
2239               if (dbus_error_is_set (error))
2240                 {
2241                   /* We log to syslog unconditionally here, because this is
2242                    * the configuration parser, so we don't yet know whether
2243                    * this bus is going to want to write to syslog! (There's
2244                    * also some layer inversion going on, if we want to use
2245                    * the bus context.) */
2246                   _dbus_system_log (DBUS_SYSTEM_LOG_INFO,
2247                                     "Encountered error '%s' while parsing '%s'\n",
2248                                     error->message,
2249                                     _dbus_string_get_const_data (&full_path));
2250                   dbus_error_free (error);
2251                 }
2252             }
2253         }
2254
2255       _dbus_string_free (&full_path);
2256     }
2257
2258   if (dbus_error_is_set (&tmp_error))
2259     {
2260       dbus_move_error (&tmp_error, error);
2261       goto failed;
2262     }
2263
2264
2265   if (!_dbus_string_copy_data (dirname, &s))
2266     {
2267       BUS_SET_OOM (error);
2268       goto failed;
2269     }
2270
2271   if (!_dbus_list_append (&parser->conf_dirs, s))
2272     {
2273       dbus_free (s);
2274       BUS_SET_OOM (error);
2275       goto failed;
2276     }
2277
2278   retval = TRUE;
2279   
2280  failed:
2281   _dbus_string_free (&filename);
2282   
2283   if (dir)
2284     _dbus_directory_close (dir);
2285
2286   return retval;
2287 }
2288
2289 dbus_bool_t
2290 bus_config_parser_content (BusConfigParser   *parser,
2291                            const DBusString  *content,
2292                            DBusError         *error)
2293 {
2294   Element *e;
2295
2296   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2297
2298 #if 0
2299   {
2300     const char *c_str;
2301     
2302     _dbus_string_get_const_data (content, &c_str);
2303
2304     printf ("CONTENT %d bytes: %s\n", _dbus_string_get_length (content), c_str);
2305   }
2306 #endif
2307   
2308   e = peek_element (parser);
2309   if (e == NULL)
2310     {
2311       dbus_set_error (error, DBUS_ERROR_FAILED,
2312                       "Text content outside of any XML element in configuration file");
2313       return FALSE;
2314     }
2315   else if (e->had_content)
2316     {
2317       _dbus_assert_not_reached ("Element had multiple content blocks");
2318       return FALSE;
2319     }
2320
2321   switch (top_element_type (parser))
2322     {
2323     case ELEMENT_NONE:
2324       _dbus_assert_not_reached ("element at top of stack has no type");
2325       return FALSE;
2326
2327     case ELEMENT_BUSCONFIG:
2328     case ELEMENT_POLICY:
2329     case ELEMENT_ALLOW:
2330     case ELEMENT_DENY:
2331     case ELEMENT_FORK:
2332     case ELEMENT_SYSLOG:
2333     case ELEMENT_KEEP_UMASK:
2334     case ELEMENT_STANDARD_SESSION_SERVICEDIRS:    
2335     case ELEMENT_STANDARD_SYSTEM_SERVICEDIRS:    
2336     case ELEMENT_ALLOW_ANONYMOUS:
2337     case ELEMENT_SELINUX:
2338     case ELEMENT_ASSOCIATE:
2339       if (all_whitespace (content))
2340         return TRUE;
2341       else
2342         {
2343           dbus_set_error (error, DBUS_ERROR_FAILED,
2344                           "No text content expected inside XML element %s in configuration file",
2345                           bus_config_parser_element_type_to_name (top_element_type (parser)));
2346           return FALSE;
2347         }
2348
2349     case ELEMENT_PIDFILE:
2350       {
2351         char *s;
2352
2353         e->had_content = TRUE;
2354         
2355         if (!_dbus_string_copy_data (content, &s))
2356           goto nomem;
2357           
2358         dbus_free (parser->pidfile);
2359         parser->pidfile = s;
2360       }
2361       break;
2362
2363     case ELEMENT_INCLUDE:
2364       {
2365         DBusString full_path, selinux_policy_root;
2366
2367         e->had_content = TRUE;
2368
2369         if (e->d.include.if_selinux_enabled
2370             && !bus_selinux_enabled ())
2371           break;
2372
2373         if (!_dbus_string_init (&full_path))
2374           goto nomem;
2375
2376         if (e->d.include.selinux_root_relative)
2377           {
2378             if (!bus_selinux_get_policy_root ())
2379               {
2380                 dbus_set_error (error, DBUS_ERROR_FAILED,
2381                                 "Could not determine SELinux policy root for relative inclusion");
2382                 _dbus_string_free (&full_path);
2383                 return FALSE;
2384               }
2385             _dbus_string_init_const (&selinux_policy_root,
2386                                      bus_selinux_get_policy_root ());
2387             if (!make_full_path (&selinux_policy_root, content, &full_path))
2388               {
2389                 _dbus_string_free (&full_path);
2390                 goto nomem;
2391               }
2392           }
2393         else if (!make_full_path (&parser->basedir, content, &full_path))
2394           {
2395             _dbus_string_free (&full_path);
2396             goto nomem;
2397           }
2398
2399         if (!include_file (parser, &full_path,
2400                            e->d.include.ignore_missing, error))
2401           {
2402             _dbus_string_free (&full_path);
2403             return FALSE;
2404           }
2405
2406         _dbus_string_free (&full_path);
2407       }
2408       break;
2409
2410     case ELEMENT_SERVICEHELPER:
2411       {
2412         DBusString full_path;
2413         
2414         e->had_content = TRUE;
2415
2416         if (!_dbus_string_init (&full_path))
2417           goto nomem;
2418         
2419         if (!make_full_path (&parser->basedir, content, &full_path))
2420           {
2421             _dbus_string_free (&full_path);
2422             goto nomem;
2423           }
2424
2425         if (!servicehelper_path (parser, &full_path, error))
2426           {
2427             _dbus_string_free (&full_path);
2428             return FALSE;
2429           }
2430
2431         _dbus_string_free (&full_path);
2432       }
2433       break;
2434       
2435     case ELEMENT_INCLUDEDIR:
2436       {
2437         DBusString full_path;
2438         
2439         e->had_content = TRUE;
2440
2441         if (!_dbus_string_init (&full_path))
2442           goto nomem;
2443         
2444         if (!make_full_path (&parser->basedir, content, &full_path))
2445           {
2446             _dbus_string_free (&full_path);
2447             goto nomem;
2448           }
2449         
2450         if (!include_dir (parser, &full_path, error))
2451           {
2452             _dbus_string_free (&full_path);
2453             return FALSE;
2454           }
2455
2456         _dbus_string_free (&full_path);
2457       }
2458       break;
2459       
2460     case ELEMENT_USER:
2461       {
2462         char *s;
2463
2464         e->had_content = TRUE;
2465         
2466         if (!_dbus_string_copy_data (content, &s))
2467           goto nomem;
2468           
2469         dbus_free (parser->user);
2470         parser->user = s;
2471       }
2472       break;
2473
2474     case ELEMENT_CONFIGTYPE:
2475       {
2476         char *s;
2477
2478         e->had_content = TRUE;
2479
2480         if (!_dbus_string_copy_data (content, &s))
2481           goto nomem;
2482         
2483         dbus_free (parser->bus_type);
2484         parser->bus_type = s;
2485       }
2486       break;
2487       
2488     case ELEMENT_LISTEN:
2489       {
2490         char *s;
2491
2492         e->had_content = TRUE;
2493         
2494         if (!_dbus_string_copy_data (content, &s))
2495           goto nomem;
2496
2497         if (!_dbus_list_append (&parser->listen_on,
2498                                 s))
2499           {
2500             dbus_free (s);
2501             goto nomem;
2502           }
2503       }
2504       break;
2505
2506     case ELEMENT_AUTH:
2507       {
2508         char *s;
2509         
2510         e->had_content = TRUE;
2511
2512         if (!_dbus_string_copy_data (content, &s))
2513           goto nomem;
2514
2515         if (!_dbus_list_append (&parser->mechanisms,
2516                                 s))
2517           {
2518             dbus_free (s);
2519             goto nomem;
2520           }
2521       }
2522       break;
2523
2524     case ELEMENT_SERVICEDIR:
2525       {
2526         char *s;
2527         DBusString full_path;
2528         
2529         e->had_content = TRUE;
2530
2531         if (!_dbus_string_init (&full_path))
2532           goto nomem;
2533         
2534         if (!make_full_path (&parser->basedir, content, &full_path))
2535           {
2536             _dbus_string_free (&full_path);
2537             goto nomem;
2538           }
2539         
2540         if (!_dbus_string_copy_data (&full_path, &s))
2541           {
2542             _dbus_string_free (&full_path);
2543             goto nomem;
2544           }
2545
2546         /* _only_ extra session directories can be specified */
2547         if (!service_dirs_append_unique_or_free (&parser->service_dirs, s))
2548           {
2549             _dbus_string_free (&full_path);
2550             dbus_free (s);
2551             goto nomem;
2552           }
2553
2554         _dbus_string_free (&full_path);
2555       }
2556       break;
2557
2558     case ELEMENT_LIMIT:
2559       {
2560         long val;
2561
2562         e->had_content = TRUE;
2563
2564         val = 0;
2565         if (!_dbus_string_parse_int (content, 0, &val, NULL))
2566           {
2567             dbus_set_error (error, DBUS_ERROR_FAILED,
2568                             "<limit name=\"%s\"> element has invalid value (could not parse as integer)",
2569                             e->d.limit.name);
2570             return FALSE;
2571           }
2572
2573         e->d.limit.value = val;
2574
2575         _dbus_verbose ("Loaded value %ld for limit %s\n",
2576                        e->d.limit.value,
2577                        e->d.limit.name);
2578       }
2579       break;
2580     }
2581
2582   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2583   return TRUE;
2584
2585  nomem:
2586   BUS_SET_OOM (error);
2587   return FALSE;
2588 }
2589
2590 dbus_bool_t
2591 bus_config_parser_finished (BusConfigParser   *parser,
2592                             DBusError         *error)
2593 {
2594   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2595
2596   if (parser->stack != NULL)
2597     {
2598       dbus_set_error (error, DBUS_ERROR_FAILED,
2599                       "Element <%s> was not closed in configuration file",
2600                       bus_config_parser_element_type_to_name (top_element_type (parser)));
2601
2602       return FALSE;
2603     }
2604
2605   if (parser->is_toplevel && parser->listen_on == NULL)
2606     {
2607       dbus_set_error (error, DBUS_ERROR_FAILED,
2608                       "Configuration file needs one or more <listen> elements giving addresses"); 
2609       return FALSE;
2610     }
2611   
2612   return TRUE;
2613 }
2614
2615 const char*
2616 bus_config_parser_get_user (BusConfigParser *parser)
2617 {
2618   return parser->user;
2619 }
2620
2621 const char*
2622 bus_config_parser_get_type (BusConfigParser *parser)
2623 {
2624   return parser->bus_type;
2625 }
2626
2627 DBusList**
2628 bus_config_parser_get_addresses (BusConfigParser *parser)
2629 {
2630   return &parser->listen_on;
2631 }
2632
2633 DBusList**
2634 bus_config_parser_get_mechanisms (BusConfigParser *parser)
2635 {
2636   return &parser->mechanisms;
2637 }
2638
2639 DBusList**
2640 bus_config_parser_get_service_dirs (BusConfigParser *parser)
2641 {
2642   return &parser->service_dirs;
2643 }
2644
2645 DBusList**
2646 bus_config_parser_get_conf_dirs (BusConfigParser *parser)
2647 {
2648   return &parser->conf_dirs;
2649 }
2650
2651 dbus_bool_t
2652 bus_config_parser_get_fork (BusConfigParser   *parser)
2653 {
2654   return parser->fork;
2655 }
2656
2657 dbus_bool_t
2658 bus_config_parser_get_syslog (BusConfigParser   *parser)
2659 {
2660   return parser->syslog;
2661 }
2662
2663 dbus_bool_t
2664 bus_config_parser_get_keep_umask (BusConfigParser   *parser)
2665 {
2666   return parser->keep_umask;
2667 }
2668
2669 dbus_bool_t
2670 bus_config_parser_get_allow_anonymous (BusConfigParser   *parser)
2671 {
2672   return parser->allow_anonymous;
2673 }
2674
2675 const char *
2676 bus_config_parser_get_pidfile (BusConfigParser   *parser)
2677 {
2678   return parser->pidfile;
2679 }
2680
2681 const char *
2682 bus_config_parser_get_servicehelper (BusConfigParser   *parser)
2683 {
2684   return parser->servicehelper;
2685 }
2686
2687 BusPolicy*
2688 bus_config_parser_steal_policy (BusConfigParser *parser)
2689 {
2690   BusPolicy *policy;
2691
2692   _dbus_assert (parser->policy != NULL); /* can only steal the policy 1 time */
2693   
2694   policy = parser->policy;
2695
2696   parser->policy = NULL;
2697
2698   return policy;
2699 }
2700
2701 /* Overwrite any limits that were set in the configuration file */
2702 void
2703 bus_config_parser_get_limits (BusConfigParser *parser,
2704                               BusLimits       *limits)
2705 {
2706   *limits = parser->limits;
2707 }
2708
2709 DBusHashTable*
2710 bus_config_parser_steal_service_context_table (BusConfigParser *parser)
2711 {
2712   DBusHashTable *table;
2713
2714   _dbus_assert (parser->service_context_table != NULL); /* can only steal once */
2715
2716   table = parser->service_context_table;
2717
2718   parser->service_context_table = NULL;
2719
2720   return table;
2721 }
2722
2723 #ifdef DBUS_BUILD_TESTS
2724 #include <stdio.h>
2725
2726 typedef enum
2727 {
2728   VALID,
2729   INVALID,
2730   UNKNOWN
2731 } Validity;
2732
2733 static dbus_bool_t
2734 do_load (const DBusString *full_path,
2735          Validity          validity,
2736          dbus_bool_t       oom_possible)
2737 {
2738   BusConfigParser *parser;
2739   DBusError error;
2740
2741   dbus_error_init (&error);
2742
2743   parser = bus_config_load (full_path, TRUE, NULL, &error);
2744   if (parser == NULL)
2745     {
2746       _DBUS_ASSERT_ERROR_IS_SET (&error);
2747
2748       if (oom_possible &&
2749           dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
2750         {
2751           _dbus_verbose ("Failed to load valid file due to OOM\n");
2752           dbus_error_free (&error);
2753           return TRUE;
2754         }
2755       else if (validity == VALID)
2756         {
2757           _dbus_warn ("Failed to load valid file but still had memory: %s\n",
2758                       error.message);
2759
2760           dbus_error_free (&error);
2761           return FALSE;
2762         }
2763       else
2764         {
2765           dbus_error_free (&error);
2766           return TRUE;
2767         }
2768     }
2769   else
2770     {
2771       _DBUS_ASSERT_ERROR_IS_CLEAR (&error);
2772
2773       bus_config_parser_unref (parser);
2774
2775       if (validity == INVALID)
2776         {
2777           _dbus_warn ("Accepted invalid file\n");
2778           return FALSE;
2779         }
2780
2781       return TRUE;
2782     }
2783 }
2784
2785 typedef struct
2786 {
2787   const DBusString *full_path;
2788   Validity          validity;
2789 } LoaderOomData;
2790
2791 static dbus_bool_t
2792 check_loader_oom_func (void *data)
2793 {
2794   LoaderOomData *d = data;
2795
2796   return do_load (d->full_path, d->validity, TRUE);
2797 }
2798
2799 static dbus_bool_t
2800 process_test_valid_subdir (const DBusString *test_base_dir,
2801                            const char       *subdir,
2802                            Validity          validity)
2803 {
2804   DBusString test_directory;
2805   DBusString filename;
2806   DBusDirIter *dir;
2807   dbus_bool_t retval;
2808   DBusError error;
2809
2810   retval = FALSE;
2811   dir = NULL;
2812
2813   if (!_dbus_string_init (&test_directory))
2814     _dbus_assert_not_reached ("didn't allocate test_directory\n");
2815
2816   _dbus_string_init_const (&filename, subdir);
2817
2818   if (!_dbus_string_copy (test_base_dir, 0,
2819                           &test_directory, 0))
2820     _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
2821
2822   if (!_dbus_concat_dir_and_file (&test_directory, &filename))
2823     _dbus_assert_not_reached ("couldn't allocate full path");
2824
2825   _dbus_string_free (&filename);
2826   if (!_dbus_string_init (&filename))
2827     _dbus_assert_not_reached ("didn't allocate filename string\n");
2828
2829   dbus_error_init (&error);
2830   dir = _dbus_directory_open (&test_directory, &error);
2831   if (dir == NULL)
2832     {
2833       _dbus_warn ("Could not open %s: %s\n",
2834                   _dbus_string_get_const_data (&test_directory),
2835                   error.message);
2836       dbus_error_free (&error);
2837       goto failed;
2838     }
2839
2840   if (validity == VALID)
2841     printf ("Testing valid files:\n");
2842   else if (validity == INVALID)
2843     printf ("Testing invalid files:\n");
2844   else
2845     printf ("Testing unknown files:\n");
2846
2847  next:
2848   while (_dbus_directory_get_next_file (dir, &filename, &error))
2849     {
2850       DBusString full_path;
2851       LoaderOomData d;
2852
2853       if (!_dbus_string_init (&full_path))
2854         _dbus_assert_not_reached ("couldn't init string");
2855
2856       if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
2857         _dbus_assert_not_reached ("couldn't copy dir to full_path");
2858
2859       if (!_dbus_concat_dir_and_file (&full_path, &filename))
2860         _dbus_assert_not_reached ("couldn't concat file to dir");
2861
2862       if (!_dbus_string_ends_with_c_str (&full_path, ".conf"))
2863         {
2864           _dbus_verbose ("Skipping non-.conf file %s\n",
2865                          _dbus_string_get_const_data (&filename));
2866           _dbus_string_free (&full_path);
2867           goto next;
2868         }
2869
2870       printf ("    %s\n", _dbus_string_get_const_data (&filename));
2871
2872       _dbus_verbose (" expecting %s\n",
2873                      validity == VALID ? "valid" :
2874                      (validity == INVALID ? "invalid" :
2875                       (validity == UNKNOWN ? "unknown" : "???")));
2876
2877       d.full_path = &full_path;
2878       d.validity = validity;
2879
2880       /* FIXME hackaround for an expat problem, see
2881        * https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=124747
2882        * http://freedesktop.org/pipermail/dbus/2004-May/001153.html
2883        */
2884       /* if (!_dbus_test_oom_handling ("config-loader", check_loader_oom_func, &d)) */
2885       if (!check_loader_oom_func (&d))
2886         _dbus_assert_not_reached ("test failed");
2887       
2888       _dbus_string_free (&full_path);
2889     }
2890
2891   if (dbus_error_is_set (&error))
2892     {
2893       _dbus_warn ("Could not get next file in %s: %s\n",
2894                   _dbus_string_get_const_data (&test_directory),
2895                   error.message);
2896       dbus_error_free (&error);
2897       goto failed;
2898     }
2899
2900   retval = TRUE;
2901
2902  failed:
2903
2904   if (dir)
2905     _dbus_directory_close (dir);
2906   _dbus_string_free (&test_directory);
2907   _dbus_string_free (&filename);
2908
2909   return retval;
2910 }
2911
2912 static dbus_bool_t
2913 bools_equal (dbus_bool_t a,
2914              dbus_bool_t b)
2915 {
2916   return a ? b : !b;
2917 }
2918
2919 static dbus_bool_t
2920 strings_equal_or_both_null (const char *a,
2921                             const char *b)
2922 {
2923   if (a == NULL || b == NULL)
2924     return a == b;
2925   else
2926     return !strcmp (a, b);
2927 }
2928
2929 static dbus_bool_t
2930 elements_equal (const Element *a,
2931                 const Element *b)
2932 {
2933   if (a->type != b->type)
2934     return FALSE;
2935
2936   if (!bools_equal (a->had_content, b->had_content))
2937     return FALSE;
2938
2939   switch (a->type)
2940     {
2941
2942     case ELEMENT_INCLUDE:
2943       if (!bools_equal (a->d.include.ignore_missing,
2944                         b->d.include.ignore_missing))
2945         return FALSE;
2946       break;
2947
2948     case ELEMENT_POLICY:
2949       if (a->d.policy.type != b->d.policy.type)
2950         return FALSE;
2951       if (a->d.policy.gid_uid_or_at_console != b->d.policy.gid_uid_or_at_console)
2952         return FALSE;
2953       break;
2954
2955     case ELEMENT_LIMIT:
2956       if (strcmp (a->d.limit.name, b->d.limit.name))
2957         return FALSE;
2958       if (a->d.limit.value != b->d.limit.value)
2959         return FALSE;
2960       break;
2961
2962     default:
2963       /* do nothing */
2964       break;
2965     }
2966
2967   return TRUE;
2968
2969 }
2970
2971 static dbus_bool_t
2972 lists_of_elements_equal (DBusList *a,
2973                          DBusList *b)
2974 {
2975   DBusList *ia;
2976   DBusList *ib;
2977
2978   ia = a;
2979   ib = b;
2980   
2981   while (ia != NULL && ib != NULL)
2982     {
2983       if (elements_equal (ia->data, ib->data))
2984         return FALSE;
2985       ia = _dbus_list_get_next_link (&a, ia);
2986       ib = _dbus_list_get_next_link (&b, ib);
2987     }
2988
2989   return ia == NULL && ib == NULL;
2990 }
2991
2992 static dbus_bool_t
2993 lists_of_c_strings_equal (DBusList *a,
2994                           DBusList *b)
2995 {
2996   DBusList *ia;
2997   DBusList *ib;
2998
2999   ia = a;
3000   ib = b;
3001   
3002   while (ia != NULL && ib != NULL)
3003     {
3004       if (strcmp (ia->data, ib->data))
3005         return FALSE;
3006       ia = _dbus_list_get_next_link (&a, ia);
3007       ib = _dbus_list_get_next_link (&b, ib);
3008     }
3009
3010   return ia == NULL && ib == NULL;
3011 }
3012
3013 static dbus_bool_t
3014 limits_equal (const BusLimits *a,
3015               const BusLimits *b)
3016 {
3017   return
3018     (a->max_incoming_bytes == b->max_incoming_bytes
3019      || a->max_incoming_unix_fds == b->max_incoming_unix_fds
3020      || a->max_outgoing_bytes == b->max_outgoing_bytes
3021      || a->max_outgoing_unix_fds == b->max_outgoing_unix_fds
3022      || a->max_message_size == b->max_message_size
3023      || a->max_message_unix_fds == b->max_message_unix_fds
3024      || a->activation_timeout == b->activation_timeout
3025      || a->auth_timeout == b->auth_timeout
3026      || a->max_completed_connections == b->max_completed_connections
3027      || a->max_incomplete_connections == b->max_incomplete_connections
3028      || a->max_connections_per_user == b->max_connections_per_user
3029      || a->max_pending_activations == b->max_pending_activations
3030      || a->max_services_per_connection == b->max_services_per_connection
3031      || a->max_match_rules_per_connection == b->max_match_rules_per_connection
3032      || a->max_replies_per_connection == b->max_replies_per_connection
3033      || a->reply_timeout == b->reply_timeout);
3034 }
3035
3036 static dbus_bool_t
3037 config_parsers_equal (const BusConfigParser *a,
3038                       const BusConfigParser *b)
3039 {
3040   if (!_dbus_string_equal (&a->basedir, &b->basedir))
3041     return FALSE;
3042
3043   if (!lists_of_elements_equal (a->stack, b->stack))
3044     return FALSE;
3045
3046   if (!strings_equal_or_both_null (a->user, b->user))
3047     return FALSE;
3048
3049   if (!lists_of_c_strings_equal (a->listen_on, b->listen_on))
3050     return FALSE;
3051
3052   if (!lists_of_c_strings_equal (a->mechanisms, b->mechanisms))
3053     return FALSE;
3054
3055   if (!lists_of_c_strings_equal (a->service_dirs, b->service_dirs))
3056     return FALSE;
3057   
3058   /* FIXME: compare policy */
3059
3060   /* FIXME: compare service selinux ID table */
3061
3062   if (! limits_equal (&a->limits, &b->limits))
3063     return FALSE;
3064
3065   if (!strings_equal_or_both_null (a->pidfile, b->pidfile))
3066     return FALSE;
3067
3068   if (! bools_equal (a->fork, b->fork))
3069     return FALSE;
3070
3071   if (! bools_equal (a->keep_umask, b->keep_umask))
3072     return FALSE;
3073
3074   if (! bools_equal (a->is_toplevel, b->is_toplevel))
3075     return FALSE;
3076
3077   return TRUE;
3078 }
3079
3080 static dbus_bool_t
3081 all_are_equiv (const DBusString *target_directory)
3082 {
3083   DBusString filename;
3084   DBusDirIter *dir;
3085   BusConfigParser *first_parser;
3086   BusConfigParser *parser;
3087   DBusError error;
3088   dbus_bool_t equal;
3089   dbus_bool_t retval;
3090
3091   dir = NULL;
3092   first_parser = NULL;
3093   parser = NULL;
3094   retval = FALSE;
3095
3096   if (!_dbus_string_init (&filename))
3097     _dbus_assert_not_reached ("didn't allocate filename string");
3098
3099   dbus_error_init (&error);
3100   dir = _dbus_directory_open (target_directory, &error);
3101   if (dir == NULL)
3102     {
3103       _dbus_warn ("Could not open %s: %s\n",
3104                   _dbus_string_get_const_data (target_directory),
3105                   error.message);
3106       dbus_error_free (&error);
3107       goto finished;
3108     }
3109
3110   printf ("Comparing equivalent files:\n");
3111
3112  next:
3113   while (_dbus_directory_get_next_file (dir, &filename, &error))
3114     {
3115       DBusString full_path;
3116
3117       if (!_dbus_string_init (&full_path))
3118         _dbus_assert_not_reached ("couldn't init string");
3119
3120       if (!_dbus_string_copy (target_directory, 0, &full_path, 0))
3121         _dbus_assert_not_reached ("couldn't copy dir to full_path");
3122
3123       if (!_dbus_concat_dir_and_file (&full_path, &filename))
3124         _dbus_assert_not_reached ("couldn't concat file to dir");
3125
3126       if (!_dbus_string_ends_with_c_str (&full_path, ".conf"))
3127         {
3128           _dbus_verbose ("Skipping non-.conf file %s\n",
3129                          _dbus_string_get_const_data (&filename));
3130           _dbus_string_free (&full_path);
3131           goto next;
3132         }
3133
3134       printf ("    %s\n", _dbus_string_get_const_data (&filename));
3135
3136       parser = bus_config_load (&full_path, TRUE, NULL, &error);
3137
3138       if (parser == NULL)
3139         {
3140           _dbus_warn ("Could not load file %s: %s\n",
3141                       _dbus_string_get_const_data (&full_path),
3142                       error.message);
3143           _dbus_string_free (&full_path);
3144           dbus_error_free (&error);
3145           goto finished;
3146         }
3147       else if (first_parser == NULL)
3148         {
3149           _dbus_string_free (&full_path);
3150           first_parser = parser;
3151         }
3152       else
3153         {
3154           _dbus_string_free (&full_path);
3155           equal = config_parsers_equal (first_parser, parser);
3156           bus_config_parser_unref (parser);
3157           if (! equal)
3158             goto finished;
3159         }
3160     }
3161
3162   retval = TRUE;
3163
3164  finished:
3165   _dbus_string_free (&filename);
3166   if (first_parser)
3167     bus_config_parser_unref (first_parser);
3168   if (dir)
3169     _dbus_directory_close (dir);
3170
3171   return retval;
3172   
3173 }
3174
3175 static dbus_bool_t
3176 process_test_equiv_subdir (const DBusString *test_base_dir,
3177                            const char       *subdir)
3178 {
3179   DBusString test_directory;
3180   DBusString filename;
3181   DBusDirIter *dir;
3182   DBusError error;
3183   dbus_bool_t equal;
3184   dbus_bool_t retval;
3185
3186   dir = NULL;
3187   retval = FALSE;
3188
3189   if (!_dbus_string_init (&test_directory))
3190     _dbus_assert_not_reached ("didn't allocate test_directory");
3191
3192   _dbus_string_init_const (&filename, subdir);
3193
3194   if (!_dbus_string_copy (test_base_dir, 0,
3195                           &test_directory, 0))
3196     _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
3197
3198   if (!_dbus_concat_dir_and_file (&test_directory, &filename))
3199     _dbus_assert_not_reached ("couldn't allocate full path");
3200
3201   _dbus_string_free (&filename);
3202   if (!_dbus_string_init (&filename))
3203     _dbus_assert_not_reached ("didn't allocate filename string");
3204
3205   dbus_error_init (&error);
3206   dir = _dbus_directory_open (&test_directory, &error);
3207   if (dir == NULL)
3208     {
3209       _dbus_warn ("Could not open %s: %s\n",
3210                   _dbus_string_get_const_data (&test_directory),
3211                   error.message);
3212       dbus_error_free (&error);
3213       goto finished;
3214     }
3215
3216   while (_dbus_directory_get_next_file (dir, &filename, &error))
3217     {
3218       DBusString full_path;
3219
3220       /* Skip CVS's magic directories! */
3221       if (_dbus_string_equal_c_str (&filename, "CVS"))
3222         continue;
3223
3224       if (!_dbus_string_init (&full_path))
3225         _dbus_assert_not_reached ("couldn't init string");
3226
3227       if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
3228         _dbus_assert_not_reached ("couldn't copy dir to full_path");
3229
3230       if (!_dbus_concat_dir_and_file (&full_path, &filename))
3231         _dbus_assert_not_reached ("couldn't concat file to dir");
3232       
3233       equal = all_are_equiv (&full_path);
3234       _dbus_string_free (&full_path);
3235
3236       if (!equal)
3237         goto finished;
3238     }
3239
3240   retval = TRUE;
3241
3242  finished:
3243   _dbus_string_free (&test_directory);
3244   _dbus_string_free (&filename);
3245   if (dir)
3246     _dbus_directory_close (dir);
3247
3248   return retval;
3249   
3250 }
3251
3252 static const char *test_session_service_dir_matches[] = 
3253         {
3254 #ifdef DBUS_UNIX
3255          "/testhome/foo/.testlocal/testshare/dbus-1/services",
3256          "/testusr/testlocal/testshare/dbus-1/services",
3257          "/testusr/testshare/dbus-1/services",
3258          DBUS_DATADIR"/dbus-1/services",
3259 #endif
3260 /* will be filled in test_default_session_servicedirs() */
3261 #ifdef DBUS_WIN
3262          NULL,
3263          NULL,
3264 #endif
3265          NULL
3266         };
3267
3268 static dbus_bool_t
3269 test_default_session_servicedirs (void)
3270 {
3271   DBusList *dirs;
3272   DBusList *link;
3273   DBusString progs;
3274   const char *common_progs;
3275   int i;
3276
3277 #ifdef DBUS_WIN
3278   char buffer[1024];
3279   if (_dbus_get_install_root(buffer, sizeof(buffer)))
3280     {
3281       strcat(buffer,DBUS_DATADIR);
3282       strcat(buffer,"/dbus-1/services");
3283       test_session_service_dir_matches[0] = buffer;
3284     }
3285 #endif
3286
3287   /* On Unix we don't actually use this variable, but it's easier to handle the
3288    * deallocation if we always allocate it, whether needed or not */
3289   if (!_dbus_string_init (&progs))
3290     _dbus_assert_not_reached ("OOM allocating progs");
3291
3292   common_progs = _dbus_getenv ("CommonProgramFiles");
3293 #ifndef DBUS_UNIX
3294   if (common_progs) 
3295     {
3296       if (!_dbus_string_append (&progs, common_progs)) 
3297         {
3298           _dbus_string_free (&progs);
3299           return FALSE;
3300         }
3301
3302       if (!_dbus_string_append (&progs, "/dbus-1/services")) 
3303         {
3304           _dbus_string_free (&progs);
3305           return FALSE;
3306         }
3307       test_session_service_dir_matches[1] = _dbus_string_get_const_data(&progs);
3308     }
3309 #endif
3310   dirs = NULL;
3311
3312   printf ("Testing retrieving the default session service directories\n");
3313   if (!_dbus_get_standard_session_servicedirs (&dirs))
3314     _dbus_assert_not_reached ("couldn't get stardard dirs");
3315
3316   /* make sure our defaults end with share/dbus-1/service */
3317   while ((link = _dbus_list_pop_first_link (&dirs)))
3318     {
3319       DBusString path;
3320       
3321       printf ("    default service dir: %s\n", (char *)link->data);
3322       _dbus_string_init_const (&path, (char *)link->data);
3323       if (!_dbus_string_ends_with_c_str (&path, "dbus-1/services"))
3324         {
3325           printf ("error with default session service directories\n");
3326               dbus_free (link->data);
3327           _dbus_list_free_link (link);
3328           _dbus_string_free (&progs);
3329           return FALSE;
3330         }
3331  
3332       dbus_free (link->data);
3333       _dbus_list_free_link (link);
3334     }
3335
3336 #ifdef DBUS_UNIX
3337   if (!_dbus_setenv ("XDG_DATA_HOME", "/testhome/foo/.testlocal/testshare"))
3338     _dbus_assert_not_reached ("couldn't setenv XDG_DATA_HOME");
3339
3340   if (!_dbus_setenv ("XDG_DATA_DIRS", ":/testusr/testlocal/testshare: :/testusr/testshare:"))
3341     _dbus_assert_not_reached ("couldn't setenv XDG_DATA_DIRS");
3342 #endif
3343   if (!_dbus_get_standard_session_servicedirs (&dirs))
3344     _dbus_assert_not_reached ("couldn't get stardard dirs");
3345
3346   /* make sure we read and parse the env variable correctly */
3347   i = 0;
3348   while ((link = _dbus_list_pop_first_link (&dirs)))
3349     {
3350       printf ("    test service dir: %s\n", (char *)link->data);
3351       if (test_session_service_dir_matches[i] == NULL)
3352         {
3353           printf ("more directories parsed than in match set\n");
3354           dbus_free (link->data);
3355           _dbus_list_free_link (link);
3356           _dbus_string_free (&progs);
3357           return FALSE;
3358         }
3359  
3360       if (strcmp (test_session_service_dir_matches[i], 
3361                   (char *)link->data) != 0)
3362         {
3363           printf ("%s directory does not match %s in the match set\n", 
3364                   (char *)link->data,
3365                   test_session_service_dir_matches[i]);
3366           dbus_free (link->data);
3367           _dbus_list_free_link (link);
3368           _dbus_string_free (&progs);
3369           return FALSE;
3370         }
3371
3372       ++i;
3373
3374       dbus_free (link->data);
3375       _dbus_list_free_link (link);
3376     }
3377   
3378   if (test_session_service_dir_matches[i] != NULL)
3379     {
3380       printf ("extra data %s in the match set was not matched\n",
3381               test_session_service_dir_matches[i]);
3382
3383       _dbus_string_free (&progs);
3384       return FALSE;
3385     }
3386     
3387   _dbus_string_free (&progs);
3388   return TRUE;
3389 }
3390
3391 static const char *test_system_service_dir_matches[] = 
3392         {
3393 #ifdef DBUS_UNIX
3394          "/testusr/testlocal/testshare/dbus-1/system-services",
3395          "/testusr/testshare/dbus-1/system-services",
3396 #endif
3397          DBUS_DATADIR"/dbus-1/system-services",
3398 #ifdef DBUS_WIN
3399          NULL,
3400 #endif
3401          NULL
3402         };
3403
3404 static dbus_bool_t
3405 test_default_system_servicedirs (void)
3406 {
3407   DBusList *dirs;
3408   DBusList *link;
3409   DBusString progs;
3410   const char *common_progs;
3411   int i;
3412
3413   /* On Unix we don't actually use this variable, but it's easier to handle the
3414    * deallocation if we always allocate it, whether needed or not */
3415   if (!_dbus_string_init (&progs))
3416     _dbus_assert_not_reached ("OOM allocating progs");
3417
3418   common_progs = _dbus_getenv ("CommonProgramFiles");
3419 #ifndef DBUS_UNIX
3420   if (common_progs) 
3421     {
3422       if (!_dbus_string_append (&progs, common_progs)) 
3423         {
3424           _dbus_string_free (&progs);
3425           return FALSE;
3426         }
3427
3428       if (!_dbus_string_append (&progs, "/dbus-1/system-services")) 
3429         {
3430           _dbus_string_free (&progs);
3431           return FALSE;
3432         }
3433       test_system_service_dir_matches[1] = _dbus_string_get_const_data(&progs);
3434     }
3435 #endif
3436   dirs = NULL;
3437
3438   printf ("Testing retrieving the default system service directories\n");
3439   if (!_dbus_get_standard_system_servicedirs (&dirs))
3440     _dbus_assert_not_reached ("couldn't get stardard dirs");
3441
3442   /* make sure our defaults end with share/dbus-1/system-service */
3443   while ((link = _dbus_list_pop_first_link (&dirs)))
3444     {
3445       DBusString path;
3446       
3447       printf ("    default service dir: %s\n", (char *)link->data);
3448       _dbus_string_init_const (&path, (char *)link->data);
3449       if (!_dbus_string_ends_with_c_str (&path, "dbus-1/system-services"))
3450         {
3451           printf ("error with default system service directories\n");
3452               dbus_free (link->data);
3453           _dbus_list_free_link (link);
3454           _dbus_string_free (&progs);
3455           return FALSE;
3456         }
3457  
3458       dbus_free (link->data);
3459       _dbus_list_free_link (link);
3460     }
3461
3462 #ifdef DBUS_UNIX
3463   if (!_dbus_setenv ("XDG_DATA_HOME", "/testhome/foo/.testlocal/testshare"))
3464     _dbus_assert_not_reached ("couldn't setenv XDG_DATA_HOME");
3465
3466   if (!_dbus_setenv ("XDG_DATA_DIRS", ":/testusr/testlocal/testshare: :/testusr/testshare:"))
3467     _dbus_assert_not_reached ("couldn't setenv XDG_DATA_DIRS");
3468 #endif
3469   if (!_dbus_get_standard_system_servicedirs (&dirs))
3470     _dbus_assert_not_reached ("couldn't get stardard dirs");
3471
3472   /* make sure we read and parse the env variable correctly */
3473   i = 0;
3474   while ((link = _dbus_list_pop_first_link (&dirs)))
3475     {
3476       printf ("    test service dir: %s\n", (char *)link->data);
3477       if (test_system_service_dir_matches[i] == NULL)
3478         {
3479           printf ("more directories parsed than in match set\n");
3480           dbus_free (link->data);
3481           _dbus_list_free_link (link);
3482           _dbus_string_free (&progs);
3483           return FALSE;
3484         }
3485  
3486       if (strcmp (test_system_service_dir_matches[i], 
3487                   (char *)link->data) != 0)
3488         {
3489           printf ("%s directory does not match %s in the match set\n", 
3490                   (char *)link->data,
3491                   test_system_service_dir_matches[i]);
3492           dbus_free (link->data);
3493           _dbus_list_free_link (link);
3494           _dbus_string_free (&progs);
3495           return FALSE;
3496         }
3497
3498       ++i;
3499
3500       dbus_free (link->data);
3501       _dbus_list_free_link (link);
3502     }
3503   
3504   if (test_system_service_dir_matches[i] != NULL)
3505     {
3506       printf ("extra data %s in the match set was not matched\n",
3507               test_system_service_dir_matches[i]);
3508
3509       _dbus_string_free (&progs);
3510       return FALSE;
3511     }
3512     
3513   _dbus_string_free (&progs);
3514   return TRUE;
3515 }
3516                    
3517 dbus_bool_t
3518 bus_config_parser_test (const DBusString *test_data_dir)
3519 {
3520   if (test_data_dir == NULL ||
3521       _dbus_string_get_length (test_data_dir) == 0)
3522     {
3523       printf ("No test data\n");
3524       return TRUE;
3525     }
3526
3527   if (!test_default_session_servicedirs())
3528     return FALSE;
3529
3530 #ifdef DBUS_WIN
3531   printf("default system service dir skipped\n");
3532 #else
3533   if (!test_default_system_servicedirs())
3534     return FALSE;
3535 #endif
3536
3537   if (!process_test_valid_subdir (test_data_dir, "valid-config-files", VALID))
3538     return FALSE;
3539
3540   if (!process_test_valid_subdir (test_data_dir, "invalid-config-files", INVALID))
3541     return FALSE;
3542
3543   if (!process_test_equiv_subdir (test_data_dir, "equiv-config-files"))
3544     return FALSE;
3545
3546   return TRUE;
3547 }
3548
3549 #endif /* DBUS_BUILD_TESTS */
3550