blob: 26f732a7b4c60bac178d8d5b1768e62d170a75d3 [file] [log] [blame]
Emeric Vigier2f625822012-08-06 11:09:52 -04001/* -*- 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 <string.h>
34
35typedef enum
36{
37 /* we ignore policies for unknown groups/users */
38 POLICY_IGNORED,
39
40 /* non-ignored */
41 POLICY_DEFAULT,
42 POLICY_MANDATORY,
43 POLICY_USER,
44 POLICY_GROUP,
45 POLICY_CONSOLE
46} PolicyType;
47
48typedef struct
49{
50 ElementType type;
51
52 unsigned int had_content : 1;
53
54 union
55 {
56 struct
57 {
58 unsigned int ignore_missing : 1;
59 unsigned int if_selinux_enabled : 1;
60 unsigned int selinux_root_relative : 1;
61 } include;
62
63 struct
64 {
65 PolicyType type;
66 unsigned long gid_uid_or_at_console;
67 } policy;
68
69 struct
70 {
71 char *name;
72 long value;
73 } limit;
74
75 } d;
76
77} Element;
78
79/**
80 * Parser for bus configuration file.
81 */
82struct BusConfigParser
83{
84 int refcount; /**< Reference count */
85
86 DBusString basedir; /**< Directory we resolve paths relative to */
87
88 DBusList *stack; /**< stack of Element */
89
90 char *user; /**< user to run as */
91
92 char *servicehelper; /**< location of the setuid helper */
93
94 char *bus_type; /**< Message bus type */
95
96 DBusList *listen_on; /**< List of addresses to listen to */
97
98 DBusList *mechanisms; /**< Auth mechanisms */
99
100 DBusList *service_dirs; /**< Directories to look for session services in */
101
102 DBusList *conf_dirs; /**< Directories to look for policy configuration in */
103
104 BusPolicy *policy; /**< Security policy */
105
106 BusLimits limits; /**< Limits */
107
108 char *pidfile; /**< PID file */
109
110 DBusList *included_files; /**< Included files stack */
111
112 DBusHashTable *service_context_table; /**< Map service names to SELinux contexts */
113
114 unsigned int fork : 1; /**< TRUE to fork into daemon mode */
115
116 unsigned int syslog : 1; /**< TRUE to enable syslog */
117 unsigned int keep_umask : 1; /**< TRUE to keep original umask when forking */
118
119 unsigned int is_toplevel : 1; /**< FALSE if we are a sub-config-file inside another one */
120
121 unsigned int allow_anonymous : 1; /**< TRUE to allow anonymous connections */
122};
123
124static Element*
125push_element (BusConfigParser *parser,
126 ElementType type)
127{
128 Element *e;
129
130 _dbus_assert (type != ELEMENT_NONE);
131
132 e = dbus_new0 (Element, 1);
133 if (e == NULL)
134 return NULL;
135
136 if (!_dbus_list_append (&parser->stack, e))
137 {
138 dbus_free (e);
139 return NULL;
140 }
141
142 e->type = type;
143
144 return e;
145}
146
147static void
148element_free (Element *e)
149{
150 if (e->type == ELEMENT_LIMIT)
151 dbus_free (e->d.limit.name);
152
153 dbus_free (e);
154}
155
156static void
157pop_element (BusConfigParser *parser)
158{
159 Element *e;
160
161 e = _dbus_list_pop_last (&parser->stack);
162
163 element_free (e);
164}
165
166static Element*
167peek_element (BusConfigParser *parser)
168{
169 Element *e;
170
171 e = _dbus_list_get_last (&parser->stack);
172
173 return e;
174}
175
176static ElementType
177top_element_type (BusConfigParser *parser)
178{
179 Element *e;
180
181 e = _dbus_list_get_last (&parser->stack);
182
183 if (e)
184 return e->type;
185 else
186 return ELEMENT_NONE;
187}
188
189static dbus_bool_t
190merge_service_context_hash (DBusHashTable *dest,
191 DBusHashTable *from)
192{
193 DBusHashIter iter;
194 char *service_copy;
195 char *context_copy;
196
197 service_copy = NULL;
198 context_copy = NULL;
199
200 _dbus_hash_iter_init (from, &iter);
201 while (_dbus_hash_iter_next (&iter))
202 {
203 const char *service = _dbus_hash_iter_get_string_key (&iter);
204 const char *context = _dbus_hash_iter_get_value (&iter);
205
206 service_copy = _dbus_strdup (service);
207 if (service_copy == NULL)
208 goto fail;
209 context_copy = _dbus_strdup (context);
210 if (context_copy == NULL)
211 goto fail;
212
213 if (!_dbus_hash_table_insert_string (dest, service_copy, context_copy))
214 goto fail;
215
216 service_copy = NULL;
217 context_copy = NULL;
218 }
219
220 return TRUE;
221
222 fail:
223 if (service_copy)
224 dbus_free (service_copy);
225
226 if (context_copy)
227 dbus_free (context_copy);
228
229 return FALSE;
230}
231
232static dbus_bool_t
233service_dirs_find_dir (DBusList **service_dirs,
234 const char *dir)
235{
236 DBusList *link;
237
238 _dbus_assert (dir != NULL);
239
240 for (link = *service_dirs; link; link = _dbus_list_get_next_link(service_dirs, link))
241 {
242 const char *link_dir;
243
244 link_dir = (const char *)link->data;
245 if (strcmp (dir, link_dir) == 0)
246 return TRUE;
247 }
248
249 return FALSE;
250}
251
252static dbus_bool_t
253service_dirs_append_unique_or_free (DBusList **service_dirs,
254 char *dir)
255{
256 if (!service_dirs_find_dir (service_dirs, dir))
257 return _dbus_list_append (service_dirs, dir);
258
259 dbus_free (dir);
260 return TRUE;
261}
262
263static void
264service_dirs_append_link_unique_or_free (DBusList **service_dirs,
265 DBusList *dir_link)
266{
267 if (!service_dirs_find_dir (service_dirs, dir_link->data))
268 {
269 _dbus_list_append_link (service_dirs, dir_link);
270 }
271 else
272 {
273 dbus_free (dir_link->data);
274 _dbus_list_free_link (dir_link);
275 }
276}
277
278static dbus_bool_t
279merge_included (BusConfigParser *parser,
280 BusConfigParser *included,
281 DBusError *error)
282{
283 DBusList *link;
284
285 if (!bus_policy_merge (parser->policy,
286 included->policy))
287 {
288 BUS_SET_OOM (error);
289 return FALSE;
290 }
291
292 if (!merge_service_context_hash (parser->service_context_table,
293 included->service_context_table))
294 {
295 BUS_SET_OOM (error);
296 return FALSE;
297 }
298
299 if (included->user != NULL)
300 {
301 dbus_free (parser->user);
302 parser->user = included->user;
303 included->user = NULL;
304 }
305
306 if (included->bus_type != NULL)
307 {
308 dbus_free (parser->bus_type);
309 parser->bus_type = included->bus_type;
310 included->bus_type = NULL;
311 }
312
313 if (included->fork)
314 parser->fork = TRUE;
315
316 if (included->keep_umask)
317 parser->keep_umask = TRUE;
318
319 if (included->pidfile != NULL)
320 {
321 dbus_free (parser->pidfile);
322 parser->pidfile = included->pidfile;
323 included->pidfile = NULL;
324 }
325
326 while ((link = _dbus_list_pop_first_link (&included->listen_on)))
327 _dbus_list_append_link (&parser->listen_on, link);
328
329 while ((link = _dbus_list_pop_first_link (&included->mechanisms)))
330 _dbus_list_append_link (&parser->mechanisms, link);
331
332 while ((link = _dbus_list_pop_first_link (&included->service_dirs)))
333 service_dirs_append_link_unique_or_free (&parser->service_dirs, link);
334
335 while ((link = _dbus_list_pop_first_link (&included->conf_dirs)))
336 _dbus_list_append_link (&parser->conf_dirs, link);
337
338 return TRUE;
339}
340
341static dbus_bool_t
342seen_include (BusConfigParser *parser,
343 const DBusString *file)
344{
345 DBusList *iter;
346
347 iter = parser->included_files;
348 while (iter != NULL)
349 {
350 if (! strcmp (_dbus_string_get_const_data (file), iter->data))
351 return TRUE;
352
353 iter = _dbus_list_get_next_link (&parser->included_files, iter);
354 }
355
356 return FALSE;
357}
358
359BusConfigParser*
360bus_config_parser_new (const DBusString *basedir,
361 dbus_bool_t is_toplevel,
362 const BusConfigParser *parent)
363{
364 BusConfigParser *parser;
365
366 parser = dbus_new0 (BusConfigParser, 1);
367 if (parser == NULL)
368 return NULL;
369
370 parser->is_toplevel = !!is_toplevel;
371
372 if (!_dbus_string_init (&parser->basedir))
373 {
374 dbus_free (parser);
375 return NULL;
376 }
377
378 if (((parser->policy = bus_policy_new ()) == NULL) ||
379 !_dbus_string_copy (basedir, 0, &parser->basedir, 0) ||
380 ((parser->service_context_table = _dbus_hash_table_new (DBUS_HASH_STRING,
381 dbus_free,
382 dbus_free)) == NULL))
383 {
384 if (parser->policy)
385 bus_policy_unref (parser->policy);
386
387 _dbus_string_free (&parser->basedir);
388
389 dbus_free (parser);
390 return NULL;
391 }
392
393 if (parent != NULL)
394 {
395 /* Initialize the parser's limits from the parent. */
396 parser->limits = parent->limits;
397
398 /* Use the parent's list of included_files to avoid
399 circular inclusions. */
400 parser->included_files = parent->included_files;
401 }
402 else
403 {
404
405 /* Make up some numbers! woot! */
406 parser->limits.max_incoming_bytes = _DBUS_ONE_MEGABYTE * 127;
407 parser->limits.max_outgoing_bytes = _DBUS_ONE_MEGABYTE * 127;
408 parser->limits.max_message_size = _DBUS_ONE_MEGABYTE * 32;
409
410 /* We set relatively conservative values here since due to the
411 way SCM_RIGHTS works we need to preallocate an array for the
412 maximum number of file descriptors we can receive. Picking a
413 high value here thus translates directly to more memory
414 allocation. */
415 parser->limits.max_incoming_unix_fds = 1024*4;
416 parser->limits.max_outgoing_unix_fds = 1024*4;
417 parser->limits.max_message_unix_fds = 1024;
418
419 /* Making this long means the user has to wait longer for an error
420 * message if something screws up, but making it too short means
421 * they might see a false failure.
422 */
423 parser->limits.activation_timeout = 25000; /* 25 seconds */
424
425 /* Making this long risks making a DOS attack easier, but too short
426 * and legitimate auth will fail. If interactive auth (ask user for
427 * password) is allowed, then potentially it has to be quite long.
428 */
429 parser->limits.auth_timeout = 30000; /* 30 seconds */
430
431 parser->limits.max_incomplete_connections = 64;
432 parser->limits.max_connections_per_user = 256;
433
434 /* Note that max_completed_connections / max_connections_per_user
435 * is the number of users that would have to work together to
436 * DOS all the other users.
437 */
438 parser->limits.max_completed_connections = 2048;
439
440 parser->limits.max_pending_activations = 512;
441 parser->limits.max_services_per_connection = 512;
442
443 /* For this one, keep in mind that it isn't only the memory used
444 * by the match rules, but slowdown from linearly walking a big
445 * list of them. A client adding more than this is almost
446 * certainly a bad idea for that reason, and should change to a
447 * smaller number of wider-net match rules - getting every last
448 * message to the bus is probably better than having a thousand
449 * match rules.
450 */
451 parser->limits.max_match_rules_per_connection = 512;
452
453 parser->limits.reply_timeout = -1; /* never */
454
455 /* this is effectively a limit on message queue size for messages
456 * that require a reply
457 */
458 parser->limits.max_replies_per_connection = 1024*8;
459 }
460
461 parser->refcount = 1;
462
463 return parser;
464}
465
466BusConfigParser *
467bus_config_parser_ref (BusConfigParser *parser)
468{
469 _dbus_assert (parser->refcount > 0);
470
471 parser->refcount += 1;
472
473 return parser;
474}
475
476void
477bus_config_parser_unref (BusConfigParser *parser)
478{
479 _dbus_assert (parser->refcount > 0);
480
481 parser->refcount -= 1;
482
483 if (parser->refcount == 0)
484 {
485 while (parser->stack != NULL)
486 pop_element (parser);
487
488 dbus_free (parser->user);
489 dbus_free (parser->servicehelper);
490 dbus_free (parser->bus_type);
491 dbus_free (parser->pidfile);
492
493 _dbus_list_foreach (&parser->listen_on,
494 (DBusForeachFunction) dbus_free,
495 NULL);
496
497 _dbus_list_clear (&parser->listen_on);
498
499 _dbus_list_foreach (&parser->service_dirs,
500 (DBusForeachFunction) dbus_free,
501 NULL);
502
503 _dbus_list_clear (&parser->service_dirs);
504
505 _dbus_list_foreach (&parser->conf_dirs,
506 (DBusForeachFunction) dbus_free,
507 NULL);
508
509 _dbus_list_clear (&parser->conf_dirs);
510
511 _dbus_list_foreach (&parser->mechanisms,
512 (DBusForeachFunction) dbus_free,
513 NULL);
514
515 _dbus_list_clear (&parser->mechanisms);
516
517 _dbus_string_free (&parser->basedir);
518
519 if (parser->policy)
520 bus_policy_unref (parser->policy);
521
522 if (parser->service_context_table)
523 _dbus_hash_table_unref (parser->service_context_table);
524
525 dbus_free (parser);
526 }
527}
528
529dbus_bool_t
530bus_config_parser_check_doctype (BusConfigParser *parser,
531 const char *doctype,
532 DBusError *error)
533{
534 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
535
536 if (strcmp (doctype, "busconfig") != 0)
537 {
538 dbus_set_error (error,
539 DBUS_ERROR_FAILED,
540 "Configuration file has the wrong document type %s",
541 doctype);
542 return FALSE;
543 }
544 else
545 return TRUE;
546}
547
548typedef struct
549{
550 const char *name;
551 const char **retloc;
552} LocateAttr;
553
554static dbus_bool_t
555locate_attributes (BusConfigParser *parser,
556 const char *element_name,
557 const char **attribute_names,
558 const char **attribute_values,
559 DBusError *error,
560 const char *first_attribute_name,
561 const char **first_attribute_retloc,
562 ...)
563{
564 va_list args;
565 const char *name;
566 const char **retloc;
567 int n_attrs;
568#define MAX_ATTRS 24
569 LocateAttr attrs[MAX_ATTRS];
570 dbus_bool_t retval;
571 int i;
572
573 _dbus_assert (first_attribute_name != NULL);
574 _dbus_assert (first_attribute_retloc != NULL);
575
576 retval = TRUE;
577
578 n_attrs = 1;
579 attrs[0].name = first_attribute_name;
580 attrs[0].retloc = first_attribute_retloc;
581 *first_attribute_retloc = NULL;
582
583 va_start (args, first_attribute_retloc);
584
585 name = va_arg (args, const char*);
586 retloc = va_arg (args, const char**);
587
588 while (name != NULL)
589 {
590 _dbus_assert (retloc != NULL);
591 _dbus_assert (n_attrs < MAX_ATTRS);
592
593 attrs[n_attrs].name = name;
594 attrs[n_attrs].retloc = retloc;
595 n_attrs += 1;
596 *retloc = NULL;
597
598 name = va_arg (args, const char*);
599 retloc = va_arg (args, const char**);
600 }
601
602 va_end (args);
603
604 i = 0;
605 while (attribute_names[i])
606 {
607 int j;
608 dbus_bool_t found;
609
610 found = FALSE;
611 j = 0;
612 while (j < n_attrs)
613 {
614 if (strcmp (attrs[j].name, attribute_names[i]) == 0)
615 {
616 retloc = attrs[j].retloc;
617
618 if (*retloc != NULL)
619 {
620 dbus_set_error (error, DBUS_ERROR_FAILED,
621 "Attribute \"%s\" repeated twice on the same <%s> element",
622 attrs[j].name, element_name);
623 retval = FALSE;
624 goto out;
625 }
626
627 *retloc = attribute_values[i];
628 found = TRUE;
629 }
630
631 ++j;
632 }
633
634 if (!found)
635 {
636 dbus_set_error (error, DBUS_ERROR_FAILED,
637 "Attribute \"%s\" is invalid on <%s> element in this context",
638 attribute_names[i], element_name);
639 retval = FALSE;
640 goto out;
641 }
642
643 ++i;
644 }
645
646 out:
647 return retval;
648}
649
650static dbus_bool_t
651check_no_attributes (BusConfigParser *parser,
652 const char *element_name,
653 const char **attribute_names,
654 const char **attribute_values,
655 DBusError *error)
656{
657 if (attribute_names[0] != NULL)
658 {
659 dbus_set_error (error, DBUS_ERROR_FAILED,
660 "Attribute \"%s\" is invalid on <%s> element in this context",
661 attribute_names[0], element_name);
662 return FALSE;
663 }
664
665 return TRUE;
666}
667
668static dbus_bool_t
669start_busconfig_child (BusConfigParser *parser,
670 const char *element_name,
671 const char **attribute_names,
672 const char **attribute_values,
673 DBusError *error)
674{
675 ElementType element_type;
676
677 element_type = bus_config_parser_element_name_to_type (element_name);
678
679 if (element_type == ELEMENT_USER)
680 {
681 if (!check_no_attributes (parser, "user", attribute_names, attribute_values, error))
682 return FALSE;
683
684 if (push_element (parser, ELEMENT_USER) == NULL)
685 {
686 BUS_SET_OOM (error);
687 return FALSE;
688 }
689
690 return TRUE;
691 }
692 else if (element_type == ELEMENT_TYPE)
693 {
694 if (!check_no_attributes (parser, "type", attribute_names, attribute_values, error))
695 return FALSE;
696
697 if (push_element (parser, ELEMENT_TYPE) == NULL)
698 {
699 BUS_SET_OOM (error);
700 return FALSE;
701 }
702
703 return TRUE;
704 }
705 else if (element_type == ELEMENT_FORK)
706 {
707 if (!check_no_attributes (parser, "fork", attribute_names, attribute_values, error))
708 return FALSE;
709
710 if (push_element (parser, ELEMENT_FORK) == NULL)
711 {
712 BUS_SET_OOM (error);
713 return FALSE;
714 }
715
716 parser->fork = TRUE;
717
718 return TRUE;
719 }
720 else if (element_type == ELEMENT_SYSLOG)
721 {
722 if (!check_no_attributes (parser, "syslog", attribute_names, attribute_values, error))
723 return FALSE;
724
725 if (push_element (parser, ELEMENT_SYSLOG) == NULL)
726 {
727 BUS_SET_OOM (error);
728 return FALSE;
729 }
730
731 parser->syslog = TRUE;
732
733 return TRUE;
734 }
735 else if (element_type == ELEMENT_KEEP_UMASK)
736 {
737 if (!check_no_attributes (parser, "keep_umask", attribute_names, attribute_values, error))
738 return FALSE;
739
740 if (push_element (parser, ELEMENT_KEEP_UMASK) == NULL)
741 {
742 BUS_SET_OOM (error);
743 return FALSE;
744 }
745
746 parser->keep_umask = TRUE;
747
748 return TRUE;
749 }
750 else if (element_type == ELEMENT_PIDFILE)
751 {
752 if (!check_no_attributes (parser, "pidfile", attribute_names, attribute_values, error))
753 return FALSE;
754
755 if (push_element (parser, ELEMENT_PIDFILE) == NULL)
756 {
757 BUS_SET_OOM (error);
758 return FALSE;
759 }
760
761 return TRUE;
762 }
763 else if (element_type == ELEMENT_LISTEN)
764 {
765 if (!check_no_attributes (parser, "listen", attribute_names, attribute_values, error))
766 return FALSE;
767
768 if (push_element (parser, ELEMENT_LISTEN) == NULL)
769 {
770 BUS_SET_OOM (error);
771 return FALSE;
772 }
773
774 return TRUE;
775 }
776 else if (element_type == ELEMENT_AUTH)
777 {
778 if (!check_no_attributes (parser, "auth", attribute_names, attribute_values, error))
779 return FALSE;
780
781 if (push_element (parser, ELEMENT_AUTH) == NULL)
782 {
783 BUS_SET_OOM (error);
784 return FALSE;
785 }
786
787 return TRUE;
788 }
789 else if (element_type == ELEMENT_SERVICEHELPER)
790 {
791 if (!check_no_attributes (parser, "servicehelper", attribute_names, attribute_values, error))
792 return FALSE;
793
794 if (push_element (parser, ELEMENT_SERVICEHELPER) == NULL)
795 {
796 BUS_SET_OOM (error);
797 return FALSE;
798 }
799
800 return TRUE;
801 }
802 else if (element_type == ELEMENT_INCLUDEDIR)
803 {
804 if (!check_no_attributes (parser, "includedir", attribute_names, attribute_values, error))
805 return FALSE;
806
807 if (push_element (parser, ELEMENT_INCLUDEDIR) == NULL)
808 {
809 BUS_SET_OOM (error);
810 return FALSE;
811 }
812
813 return TRUE;
814 }
815 else if (element_type == ELEMENT_STANDARD_SESSION_SERVICEDIRS)
816 {
817 DBusList *link;
818 DBusList *dirs;
819 dirs = NULL;
820
821 if (!check_no_attributes (parser, "standard_session_servicedirs", attribute_names, attribute_values, error))
822 return FALSE;
823
824 if (push_element (parser, ELEMENT_STANDARD_SESSION_SERVICEDIRS) == NULL)
825 {
826 BUS_SET_OOM (error);
827 return FALSE;
828 }
829
830 if (!_dbus_get_standard_session_servicedirs (&dirs))
831 {
832 BUS_SET_OOM (error);
833 return FALSE;
834 }
835
836 while ((link = _dbus_list_pop_first_link (&dirs)))
837 service_dirs_append_link_unique_or_free (&parser->service_dirs, link);
838
839 return TRUE;
840 }
841 else if (element_type == ELEMENT_STANDARD_SYSTEM_SERVICEDIRS)
842 {
843 DBusList *link;
844 DBusList *dirs;
845 dirs = NULL;
846
847 if (!check_no_attributes (parser, "standard_system_servicedirs", attribute_names, attribute_values, error))
848 return FALSE;
849
850 if (push_element (parser, ELEMENT_STANDARD_SYSTEM_SERVICEDIRS) == NULL)
851 {
852 BUS_SET_OOM (error);
853 return FALSE;
854 }
855
856 if (!_dbus_get_standard_system_servicedirs (&dirs))
857 {
858 BUS_SET_OOM (error);
859 return FALSE;
860 }
861
862 while ((link = _dbus_list_pop_first_link (&dirs)))
863 service_dirs_append_link_unique_or_free (&parser->service_dirs, link);
864
865 return TRUE;
866 }
867 else if (element_type == ELEMENT_ALLOW_ANONYMOUS)
868 {
869 if (!check_no_attributes (parser, "allow_anonymous", attribute_names, attribute_values, error))
870 return FALSE;
871
872 if (push_element (parser, ELEMENT_ALLOW_ANONYMOUS) == NULL)
873 {
874 BUS_SET_OOM (error);
875 return FALSE;
876 }
877
878 parser->allow_anonymous = TRUE;
879 return TRUE;
880 }
881 else if (element_type == ELEMENT_SERVICEDIR)
882 {
883 if (!check_no_attributes (parser, "servicedir", attribute_names, attribute_values, error))
884 return FALSE;
885
886 if (push_element (parser, ELEMENT_SERVICEDIR) == NULL)
887 {
888 BUS_SET_OOM (error);
889 return FALSE;
890 }
891
892 return TRUE;
893 }
894 else if (element_type == ELEMENT_INCLUDE)
895 {
896 Element *e;
897 const char *if_selinux_enabled;
898 const char *ignore_missing;
899 const char *selinux_root_relative;
900
901 if ((e = push_element (parser, ELEMENT_INCLUDE)) == NULL)
902 {
903 BUS_SET_OOM (error);
904 return FALSE;
905 }
906
907 e->d.include.ignore_missing = FALSE;
908 e->d.include.if_selinux_enabled = FALSE;
909 e->d.include.selinux_root_relative = FALSE;
910
911 if (!locate_attributes (parser, "include",
912 attribute_names,
913 attribute_values,
914 error,
915 "ignore_missing", &ignore_missing,
916 "if_selinux_enabled", &if_selinux_enabled,
917 "selinux_root_relative", &selinux_root_relative,
918 NULL))
919 return FALSE;
920
921 if (ignore_missing != NULL)
922 {
923 if (strcmp (ignore_missing, "yes") == 0)
924 e->d.include.ignore_missing = TRUE;
925 else if (strcmp (ignore_missing, "no") == 0)
926 e->d.include.ignore_missing = FALSE;
927 else
928 {
929 dbus_set_error (error, DBUS_ERROR_FAILED,
930 "ignore_missing attribute must have value \"yes\" or \"no\"");
931 return FALSE;
932 }
933 }
934
935 if (if_selinux_enabled != NULL)
936 {
937 if (strcmp (if_selinux_enabled, "yes") == 0)
938 e->d.include.if_selinux_enabled = TRUE;
939 else if (strcmp (if_selinux_enabled, "no") == 0)
940 e->d.include.if_selinux_enabled = FALSE;
941 else
942 {
943 dbus_set_error (error, DBUS_ERROR_FAILED,
944 "if_selinux_enabled attribute must have value"
945 " \"yes\" or \"no\"");
946 return FALSE;
947 }
948 }
949
950 if (selinux_root_relative != NULL)
951 {
952 if (strcmp (selinux_root_relative, "yes") == 0)
953 e->d.include.selinux_root_relative = TRUE;
954 else if (strcmp (selinux_root_relative, "no") == 0)
955 e->d.include.selinux_root_relative = FALSE;
956 else
957 {
958 dbus_set_error (error, DBUS_ERROR_FAILED,
959 "selinux_root_relative attribute must have value"
960 " \"yes\" or \"no\"");
961 return FALSE;
962 }
963 }
964
965 return TRUE;
966 }
967 else if (element_type == ELEMENT_POLICY)
968 {
969 Element *e;
970 const char *context;
971 const char *user;
972 const char *group;
973 const char *at_console;
974
975 if ((e = push_element (parser, ELEMENT_POLICY)) == NULL)
976 {
977 BUS_SET_OOM (error);
978 return FALSE;
979 }
980
981 e->d.policy.type = POLICY_IGNORED;
982
983 if (!locate_attributes (parser, "policy",
984 attribute_names,
985 attribute_values,
986 error,
987 "context", &context,
988 "user", &user,
989 "group", &group,
990 "at_console", &at_console,
991 NULL))
992 return FALSE;
993
994 if (((context && user) ||
995 (context && group) ||
996 (context && at_console)) ||
997 ((user && group) ||
998 (user && at_console)) ||
999 (group && at_console) ||
1000 !(context || user || group || at_console))
1001 {
1002 dbus_set_error (error, DBUS_ERROR_FAILED,
1003 "<policy> element must have exactly one of (context|user|group|at_console) attributes");
1004 return FALSE;
1005 }
1006
1007 if (context != NULL)
1008 {
1009 if (strcmp (context, "default") == 0)
1010 {
1011 e->d.policy.type = POLICY_DEFAULT;
1012 }
1013 else if (strcmp (context, "mandatory") == 0)
1014 {
1015 e->d.policy.type = POLICY_MANDATORY;
1016 }
1017 else
1018 {
1019 dbus_set_error (error, DBUS_ERROR_FAILED,
1020 "context attribute on <policy> must have the value \"default\" or \"mandatory\", not \"%s\"",
1021 context);
1022 return FALSE;
1023 }
1024 }
1025 else if (user != NULL)
1026 {
1027 DBusString username;
1028 _dbus_string_init_const (&username, user);
1029
1030 if (_dbus_parse_unix_user_from_config (&username,
1031 &e->d.policy.gid_uid_or_at_console))
1032 e->d.policy.type = POLICY_USER;
1033 else
1034 _dbus_warn ("Unknown username \"%s\" in message bus configuration file\n",
1035 user);
1036 }
1037 else if (group != NULL)
1038 {
1039 DBusString group_name;
1040 _dbus_string_init_const (&group_name, group);
1041
1042 if (_dbus_parse_unix_group_from_config (&group_name,
1043 &e->d.policy.gid_uid_or_at_console))
1044 e->d.policy.type = POLICY_GROUP;
1045 else
1046 _dbus_warn ("Unknown group \"%s\" in message bus configuration file\n",
1047 group);
1048 }
1049 else if (at_console != NULL)
1050 {
1051 dbus_bool_t t;
1052 t = (strcmp (at_console, "true") == 0);
1053 if (t || strcmp (at_console, "false") == 0)
1054 {
1055 e->d.policy.gid_uid_or_at_console = t;
1056 e->d.policy.type = POLICY_CONSOLE;
1057 }
1058 else
1059 {
1060 dbus_set_error (error, DBUS_ERROR_FAILED,
1061 "Unknown value \"%s\" for at_console in message bus configuration file",
1062 at_console);
1063
1064 return FALSE;
1065 }
1066 }
1067 else
1068 {
1069 _dbus_assert_not_reached ("all <policy> attributes null and we didn't set error");
1070 }
1071
1072 return TRUE;
1073 }
1074 else if (element_type == ELEMENT_LIMIT)
1075 {
1076 Element *e;
1077 const char *name;
1078
1079 if ((e = push_element (parser, ELEMENT_LIMIT)) == NULL)
1080 {
1081 BUS_SET_OOM (error);
1082 return FALSE;
1083 }
1084
1085 if (!locate_attributes (parser, "limit",
1086 attribute_names,
1087 attribute_values,
1088 error,
1089 "name", &name,
1090 NULL))
1091 return FALSE;
1092
1093 if (name == NULL)
1094 {
1095 dbus_set_error (error, DBUS_ERROR_FAILED,
1096 "<limit> element must have a \"name\" attribute");
1097 return FALSE;
1098 }
1099
1100 e->d.limit.name = _dbus_strdup (name);
1101 if (e->d.limit.name == NULL)
1102 {
1103 BUS_SET_OOM (error);
1104 return FALSE;
1105 }
1106
1107 return TRUE;
1108 }
1109 else if (element_type == ELEMENT_SELINUX)
1110 {
1111 if (!check_no_attributes (parser, "selinux", attribute_names, attribute_values, error))
1112 return FALSE;
1113
1114 if (push_element (parser, ELEMENT_SELINUX) == NULL)
1115 {
1116 BUS_SET_OOM (error);
1117 return FALSE;
1118 }
1119
1120 return TRUE;
1121 }
1122 else
1123 {
1124 dbus_set_error (error, DBUS_ERROR_FAILED,
1125 "Element <%s> not allowed inside <%s> in configuration file",
1126 element_name, "busconfig");
1127 return FALSE;
1128 }
1129}
1130
1131static dbus_bool_t
1132append_rule_from_element (BusConfigParser *parser,
1133 const char *element_name,
1134 const char **attribute_names,
1135 const char **attribute_values,
1136 dbus_bool_t allow,
1137 DBusError *error)
1138{
1139 const char *log;
1140 const char *send_interface;
1141 const char *send_member;
1142 const char *send_error;
1143 const char *send_destination;
1144 const char *send_path;
1145 const char *send_type;
1146 const char *receive_interface;
1147 const char *receive_member;
1148 const char *receive_error;
1149 const char *receive_sender;
1150 const char *receive_path;
1151 const char *receive_type;
1152 const char *eavesdrop;
1153 const char *send_requested_reply;
1154 const char *receive_requested_reply;
1155 const char *own;
1156 const char *user;
1157 const char *group;
1158
1159 BusPolicyRule *rule;
1160
1161 if (!locate_attributes (parser, element_name,
1162 attribute_names,
1163 attribute_values,
1164 error,
1165 "send_interface", &send_interface,
1166 "send_member", &send_member,
1167 "send_error", &send_error,
1168 "send_destination", &send_destination,
1169 "send_path", &send_path,
1170 "send_type", &send_type,
1171 "receive_interface", &receive_interface,
1172 "receive_member", &receive_member,
1173 "receive_error", &receive_error,
1174 "receive_sender", &receive_sender,
1175 "receive_path", &receive_path,
1176 "receive_type", &receive_type,
1177 "eavesdrop", &eavesdrop,
1178 "send_requested_reply", &send_requested_reply,
1179 "receive_requested_reply", &receive_requested_reply,
1180 "own", &own,
1181 "user", &user,
1182 "group", &group,
1183 "log", &log,
1184 NULL))
1185 return FALSE;
1186
1187 if (!(send_interface || send_member || send_error || send_destination ||
1188 send_type || send_path ||
1189 receive_interface || receive_member || receive_error || receive_sender ||
1190 receive_type || receive_path || eavesdrop ||
1191 send_requested_reply || receive_requested_reply ||
1192 own || user || group))
1193 {
1194 dbus_set_error (error, DBUS_ERROR_FAILED,
1195 "Element <%s> must have one or more attributes",
1196 element_name);
1197 return FALSE;
1198 }
1199
1200 if ((send_member && (send_interface == NULL && send_path == NULL)) ||
1201 (receive_member && (receive_interface == NULL && receive_path == NULL)))
1202 {
1203 dbus_set_error (error, DBUS_ERROR_FAILED,
1204 "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.",
1205 element_name);
1206 return FALSE;
1207 }
1208
1209 /* Allowed combinations of elements are:
1210 *
1211 * base, must be all send or all receive:
1212 * nothing
1213 * interface
1214 * interface + member
1215 * error
1216 *
1217 * base send_ can combine with send_destination, send_path, send_type, send_requested_reply
1218 * base receive_ with receive_sender, receive_path, receive_type, receive_requested_reply, eavesdrop
1219 *
1220 * user, group, own must occur alone
1221 *
1222 * Pretty sure the below stuff is broken, FIXME think about it more.
1223 */
1224
1225 if (((send_interface && send_error) ||
1226 (send_interface && receive_interface) ||
1227 (send_interface && receive_member) ||
1228 (send_interface && receive_error) ||
1229 (send_interface && receive_sender) ||
1230 (send_interface && receive_requested_reply) ||
1231 (send_interface && own) ||
1232 (send_interface && user) ||
1233 (send_interface && group)) ||
1234
1235 ((send_member && send_error) ||
1236 (send_member && receive_interface) ||
1237 (send_member && receive_member) ||
1238 (send_member && receive_error) ||
1239 (send_member && receive_sender) ||
1240 (send_member && receive_requested_reply) ||
1241 (send_member && own) ||
1242 (send_member && user) ||
1243 (send_member && group)) ||
1244
1245 ((send_error && receive_interface) ||
1246 (send_error && receive_member) ||
1247 (send_error && receive_error) ||
1248 (send_error && receive_sender) ||
1249 (send_error && receive_requested_reply) ||
1250 (send_error && own) ||
1251 (send_error && user) ||
1252 (send_error && group)) ||
1253
1254 ((send_destination && receive_interface) ||
1255 (send_destination && receive_member) ||
1256 (send_destination && receive_error) ||
1257 (send_destination && receive_sender) ||
1258 (send_destination && receive_requested_reply) ||
1259 (send_destination && own) ||
1260 (send_destination && user) ||
1261 (send_destination && group)) ||
1262
1263 ((send_type && receive_interface) ||
1264 (send_type && receive_member) ||
1265 (send_type && receive_error) ||
1266 (send_type && receive_sender) ||
1267 (send_type && receive_requested_reply) ||
1268 (send_type && own) ||
1269 (send_type && user) ||
1270 (send_type && group)) ||
1271
1272 ((send_path && receive_interface) ||
1273 (send_path && receive_member) ||
1274 (send_path && receive_error) ||
1275 (send_path && receive_sender) ||
1276 (send_path && receive_requested_reply) ||
1277 (send_path && own) ||
1278 (send_path && user) ||
1279 (send_path && group)) ||
1280
1281 ((send_requested_reply && receive_interface) ||
1282 (send_requested_reply && receive_member) ||
1283 (send_requested_reply && receive_error) ||
1284 (send_requested_reply && receive_sender) ||
1285 (send_requested_reply && receive_requested_reply) ||
1286 (send_requested_reply && own) ||
1287 (send_requested_reply && user) ||
1288 (send_requested_reply && group)) ||
1289
1290 ((receive_interface && receive_error) ||
1291 (receive_interface && own) ||
1292 (receive_interface && user) ||
1293 (receive_interface && group)) ||
1294
1295 ((receive_member && receive_error) ||
1296 (receive_member && own) ||
1297 (receive_member && user) ||
1298 (receive_member && group)) ||
1299
1300 ((receive_error && own) ||
1301 (receive_error && user) ||
1302 (receive_error && group)) ||
1303
1304 ((eavesdrop && own) ||
1305 (eavesdrop && user) ||
1306 (eavesdrop && group)) ||
1307
1308 ((receive_requested_reply && own) ||
1309 (receive_requested_reply && user) ||
1310 (receive_requested_reply && group)) ||
1311
1312 ((own && user) ||
1313 (own && 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
1642static dbus_bool_t
1643start_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
1688static dbus_bool_t
1689start_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
1760dbus_bool_t
1761bus_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
1825static dbus_bool_t
1826set_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
1955dbus_bool_t
1956bus_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_TYPE:
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
2048static dbus_bool_t
2049all_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
2058static dbus_bool_t
2059make_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
2079static dbus_bool_t
2080include_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_CONTENT_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_CONTENT_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
2152static dbus_bool_t
2153servicehelper_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
2186static dbus_bool_t
2187include_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 _dbus_string_free (&full_path);
2240 goto failed;
2241 }
2242 }
2243
2244 _dbus_string_free (&full_path);
2245 }
2246
2247 if (dbus_error_is_set (&tmp_error))
2248 {
2249 dbus_move_error (&tmp_error, error);
2250 goto failed;
2251 }
2252
2253
2254 if (!_dbus_string_copy_data (dirname, &s))
2255 {
2256 BUS_SET_OOM (error);
2257 goto failed;
2258 }
2259
2260 if (!_dbus_list_append (&parser->conf_dirs, s))
2261 {
2262 dbus_free (s);
2263 BUS_SET_OOM (error);
2264 goto failed;
2265 }
2266
2267 retval = TRUE;
2268
2269 failed:
2270 _dbus_string_free (&filename);
2271
2272 if (dir)
2273 _dbus_directory_close (dir);
2274
2275 return retval;
2276}
2277
2278dbus_bool_t
2279bus_config_parser_content (BusConfigParser *parser,
2280 const DBusString *content,
2281 DBusError *error)
2282{
2283 Element *e;
2284
2285 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2286
2287#if 0
2288 {
2289 const char *c_str;
2290
2291 _dbus_string_get_const_data (content, &c_str);
2292
2293 printf ("CONTENT %d bytes: %s\n", _dbus_string_get_length (content), c_str);
2294 }
2295#endif
2296
2297 e = peek_element (parser);
2298 if (e == NULL)
2299 {
2300 dbus_set_error (error, DBUS_ERROR_FAILED,
2301 "Text content outside of any XML element in configuration file");
2302 return FALSE;
2303 }
2304 else if (e->had_content)
2305 {
2306 _dbus_assert_not_reached ("Element had multiple content blocks");
2307 return FALSE;
2308 }
2309
2310 switch (top_element_type (parser))
2311 {
2312 case ELEMENT_NONE:
2313 _dbus_assert_not_reached ("element at top of stack has no type");
2314 return FALSE;
2315
2316 case ELEMENT_BUSCONFIG:
2317 case ELEMENT_POLICY:
2318 case ELEMENT_ALLOW:
2319 case ELEMENT_DENY:
2320 case ELEMENT_FORK:
2321 case ELEMENT_SYSLOG:
2322 case ELEMENT_KEEP_UMASK:
2323 case ELEMENT_STANDARD_SESSION_SERVICEDIRS:
2324 case ELEMENT_STANDARD_SYSTEM_SERVICEDIRS:
2325 case ELEMENT_ALLOW_ANONYMOUS:
2326 case ELEMENT_SELINUX:
2327 case ELEMENT_ASSOCIATE:
2328 if (all_whitespace (content))
2329 return TRUE;
2330 else
2331 {
2332 dbus_set_error (error, DBUS_ERROR_FAILED,
2333 "No text content expected inside XML element %s in configuration file",
2334 bus_config_parser_element_type_to_name (top_element_type (parser)));
2335 return FALSE;
2336 }
2337
2338 case ELEMENT_PIDFILE:
2339 {
2340 char *s;
2341
2342 e->had_content = TRUE;
2343
2344 if (!_dbus_string_copy_data (content, &s))
2345 goto nomem;
2346
2347 dbus_free (parser->pidfile);
2348 parser->pidfile = s;
2349 }
2350 break;
2351
2352 case ELEMENT_INCLUDE:
2353 {
2354 DBusString full_path, selinux_policy_root;
2355
2356 e->had_content = TRUE;
2357
2358 if (e->d.include.if_selinux_enabled
2359 && !bus_selinux_enabled ())
2360 break;
2361
2362 if (!_dbus_string_init (&full_path))
2363 goto nomem;
2364
2365 if (e->d.include.selinux_root_relative)
2366 {
2367 if (!bus_selinux_get_policy_root ())
2368 {
2369 dbus_set_error (error, DBUS_ERROR_FAILED,
2370 "Could not determine SELinux policy root for relative inclusion");
2371 _dbus_string_free (&full_path);
2372 return FALSE;
2373 }
2374 _dbus_string_init_const (&selinux_policy_root,
2375 bus_selinux_get_policy_root ());
2376 if (!make_full_path (&selinux_policy_root, content, &full_path))
2377 {
2378 _dbus_string_free (&full_path);
2379 goto nomem;
2380 }
2381 }
2382 else if (!make_full_path (&parser->basedir, content, &full_path))
2383 {
2384 _dbus_string_free (&full_path);
2385 goto nomem;
2386 }
2387
2388 if (!include_file (parser, &full_path,
2389 e->d.include.ignore_missing, error))
2390 {
2391 _dbus_string_free (&full_path);
2392 return FALSE;
2393 }
2394
2395 _dbus_string_free (&full_path);
2396 }
2397 break;
2398
2399 case ELEMENT_SERVICEHELPER:
2400 {
2401 DBusString full_path;
2402
2403 e->had_content = TRUE;
2404
2405 if (!_dbus_string_init (&full_path))
2406 goto nomem;
2407
2408 if (!make_full_path (&parser->basedir, content, &full_path))
2409 {
2410 _dbus_string_free (&full_path);
2411 goto nomem;
2412 }
2413
2414 if (!servicehelper_path (parser, &full_path, error))
2415 {
2416 _dbus_string_free (&full_path);
2417 return FALSE;
2418 }
2419
2420 _dbus_string_free (&full_path);
2421 }
2422 break;
2423
2424 case ELEMENT_INCLUDEDIR:
2425 {
2426 DBusString full_path;
2427
2428 e->had_content = TRUE;
2429
2430 if (!_dbus_string_init (&full_path))
2431 goto nomem;
2432
2433 if (!make_full_path (&parser->basedir, content, &full_path))
2434 {
2435 _dbus_string_free (&full_path);
2436 goto nomem;
2437 }
2438
2439 if (!include_dir (parser, &full_path, error))
2440 {
2441 _dbus_string_free (&full_path);
2442 return FALSE;
2443 }
2444
2445 _dbus_string_free (&full_path);
2446 }
2447 break;
2448
2449 case ELEMENT_USER:
2450 {
2451 char *s;
2452
2453 e->had_content = TRUE;
2454
2455 if (!_dbus_string_copy_data (content, &s))
2456 goto nomem;
2457
2458 dbus_free (parser->user);
2459 parser->user = s;
2460 }
2461 break;
2462
2463 case ELEMENT_TYPE:
2464 {
2465 char *s;
2466
2467 e->had_content = TRUE;
2468
2469 if (!_dbus_string_copy_data (content, &s))
2470 goto nomem;
2471
2472 dbus_free (parser->bus_type);
2473 parser->bus_type = s;
2474 }
2475 break;
2476
2477 case ELEMENT_LISTEN:
2478 {
2479 char *s;
2480
2481 e->had_content = TRUE;
2482
2483 if (!_dbus_string_copy_data (content, &s))
2484 goto nomem;
2485
2486 if (!_dbus_list_append (&parser->listen_on,
2487 s))
2488 {
2489 dbus_free (s);
2490 goto nomem;
2491 }
2492 }
2493 break;
2494
2495 case ELEMENT_AUTH:
2496 {
2497 char *s;
2498
2499 e->had_content = TRUE;
2500
2501 if (!_dbus_string_copy_data (content, &s))
2502 goto nomem;
2503
2504 if (!_dbus_list_append (&parser->mechanisms,
2505 s))
2506 {
2507 dbus_free (s);
2508 goto nomem;
2509 }
2510 }
2511 break;
2512
2513 case ELEMENT_SERVICEDIR:
2514 {
2515 char *s;
2516 DBusString full_path;
2517
2518 e->had_content = TRUE;
2519
2520 if (!_dbus_string_init (&full_path))
2521 goto nomem;
2522
2523 if (!make_full_path (&parser->basedir, content, &full_path))
2524 {
2525 _dbus_string_free (&full_path);
2526 goto nomem;
2527 }
2528
2529 if (!_dbus_string_copy_data (&full_path, &s))
2530 {
2531 _dbus_string_free (&full_path);
2532 goto nomem;
2533 }
2534
2535 /* _only_ extra session directories can be specified */
2536 if (!service_dirs_append_unique_or_free (&parser->service_dirs, s))
2537 {
2538 _dbus_string_free (&full_path);
2539 dbus_free (s);
2540 goto nomem;
2541 }
2542
2543 _dbus_string_free (&full_path);
2544 }
2545 break;
2546
2547 case ELEMENT_LIMIT:
2548 {
2549 long val;
2550
2551 e->had_content = TRUE;
2552
2553 val = 0;
2554 if (!_dbus_string_parse_int (content, 0, &val, NULL))
2555 {
2556 dbus_set_error (error, DBUS_ERROR_FAILED,
2557 "<limit name=\"%s\"> element has invalid value (could not parse as integer)",
2558 e->d.limit.name);
2559 return FALSE;
2560 }
2561
2562 e->d.limit.value = val;
2563
2564 _dbus_verbose ("Loaded value %ld for limit %s\n",
2565 e->d.limit.value,
2566 e->d.limit.name);
2567 }
2568 break;
2569 }
2570
2571 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2572 return TRUE;
2573
2574 nomem:
2575 BUS_SET_OOM (error);
2576 return FALSE;
2577}
2578
2579dbus_bool_t
2580bus_config_parser_finished (BusConfigParser *parser,
2581 DBusError *error)
2582{
2583 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2584
2585 if (parser->stack != NULL)
2586 {
2587 dbus_set_error (error, DBUS_ERROR_FAILED,
2588 "Element <%s> was not closed in configuration file",
2589 bus_config_parser_element_type_to_name (top_element_type (parser)));
2590
2591 return FALSE;
2592 }
2593
2594 if (parser->is_toplevel && parser->listen_on == NULL)
2595 {
2596 dbus_set_error (error, DBUS_ERROR_FAILED,
2597 "Configuration file needs one or more <listen> elements giving addresses");
2598 return FALSE;
2599 }
2600
2601 return TRUE;
2602}
2603
2604const char*
2605bus_config_parser_get_user (BusConfigParser *parser)
2606{
2607 return parser->user;
2608}
2609
2610const char*
2611bus_config_parser_get_type (BusConfigParser *parser)
2612{
2613 return parser->bus_type;
2614}
2615
2616DBusList**
2617bus_config_parser_get_addresses (BusConfigParser *parser)
2618{
2619 return &parser->listen_on;
2620}
2621
2622DBusList**
2623bus_config_parser_get_mechanisms (BusConfigParser *parser)
2624{
2625 return &parser->mechanisms;
2626}
2627
2628DBusList**
2629bus_config_parser_get_service_dirs (BusConfigParser *parser)
2630{
2631 return &parser->service_dirs;
2632}
2633
2634DBusList**
2635bus_config_parser_get_conf_dirs (BusConfigParser *parser)
2636{
2637 return &parser->conf_dirs;
2638}
2639
2640dbus_bool_t
2641bus_config_parser_get_fork (BusConfigParser *parser)
2642{
2643 return parser->fork;
2644}
2645
2646dbus_bool_t
2647bus_config_parser_get_syslog (BusConfigParser *parser)
2648{
2649 return parser->syslog;
2650}
2651
2652dbus_bool_t
2653bus_config_parser_get_keep_umask (BusConfigParser *parser)
2654{
2655 return parser->keep_umask;
2656}
2657
2658dbus_bool_t
2659bus_config_parser_get_allow_anonymous (BusConfigParser *parser)
2660{
2661 return parser->allow_anonymous;
2662}
2663
2664const char *
2665bus_config_parser_get_pidfile (BusConfigParser *parser)
2666{
2667 return parser->pidfile;
2668}
2669
2670const char *
2671bus_config_parser_get_servicehelper (BusConfigParser *parser)
2672{
2673 return parser->servicehelper;
2674}
2675
2676BusPolicy*
2677bus_config_parser_steal_policy (BusConfigParser *parser)
2678{
2679 BusPolicy *policy;
2680
2681 _dbus_assert (parser->policy != NULL); /* can only steal the policy 1 time */
2682
2683 policy = parser->policy;
2684
2685 parser->policy = NULL;
2686
2687 return policy;
2688}
2689
2690/* Overwrite any limits that were set in the configuration file */
2691void
2692bus_config_parser_get_limits (BusConfigParser *parser,
2693 BusLimits *limits)
2694{
2695 *limits = parser->limits;
2696}
2697
2698DBusHashTable*
2699bus_config_parser_steal_service_context_table (BusConfigParser *parser)
2700{
2701 DBusHashTable *table;
2702
2703 _dbus_assert (parser->service_context_table != NULL); /* can only steal once */
2704
2705 table = parser->service_context_table;
2706
2707 parser->service_context_table = NULL;
2708
2709 return table;
2710}
2711
2712#ifdef DBUS_BUILD_TESTS
2713#include <stdio.h>
2714
2715typedef enum
2716{
2717 VALID,
2718 INVALID,
2719 UNKNOWN
2720} Validity;
2721
2722static dbus_bool_t
2723do_load (const DBusString *full_path,
2724 Validity validity,
2725 dbus_bool_t oom_possible)
2726{
2727 BusConfigParser *parser;
2728 DBusError error;
2729
2730 dbus_error_init (&error);
2731
2732 parser = bus_config_load (full_path, TRUE, NULL, &error);
2733 if (parser == NULL)
2734 {
2735 _DBUS_ASSERT_ERROR_IS_SET (&error);
2736
2737 if (oom_possible &&
2738 dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
2739 {
2740 _dbus_verbose ("Failed to load valid file due to OOM\n");
2741 dbus_error_free (&error);
2742 return TRUE;
2743 }
2744 else if (validity == VALID)
2745 {
2746 _dbus_warn ("Failed to load valid file but still had memory: %s\n",
2747 error.message);
2748
2749 dbus_error_free (&error);
2750 return FALSE;
2751 }
2752 else
2753 {
2754 dbus_error_free (&error);
2755 return TRUE;
2756 }
2757 }
2758 else
2759 {
2760 _DBUS_ASSERT_ERROR_IS_CLEAR (&error);
2761
2762 bus_config_parser_unref (parser);
2763
2764 if (validity == INVALID)
2765 {
2766 _dbus_warn ("Accepted invalid file\n");
2767 return FALSE;
2768 }
2769
2770 return TRUE;
2771 }
2772}
2773
2774typedef struct
2775{
2776 const DBusString *full_path;
2777 Validity validity;
2778} LoaderOomData;
2779
2780static dbus_bool_t
2781check_loader_oom_func (void *data)
2782{
2783 LoaderOomData *d = data;
2784
2785 return do_load (d->full_path, d->validity, TRUE);
2786}
2787
2788static dbus_bool_t
2789process_test_valid_subdir (const DBusString *test_base_dir,
2790 const char *subdir,
2791 Validity validity)
2792{
2793 DBusString test_directory;
2794 DBusString filename;
2795 DBusDirIter *dir;
2796 dbus_bool_t retval;
2797 DBusError error;
2798
2799 retval = FALSE;
2800 dir = NULL;
2801
2802 if (!_dbus_string_init (&test_directory))
2803 _dbus_assert_not_reached ("didn't allocate test_directory\n");
2804
2805 _dbus_string_init_const (&filename, subdir);
2806
2807 if (!_dbus_string_copy (test_base_dir, 0,
2808 &test_directory, 0))
2809 _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
2810
2811 if (!_dbus_concat_dir_and_file (&test_directory, &filename))
2812 _dbus_assert_not_reached ("couldn't allocate full path");
2813
2814 _dbus_string_free (&filename);
2815 if (!_dbus_string_init (&filename))
2816 _dbus_assert_not_reached ("didn't allocate filename string\n");
2817
2818 dbus_error_init (&error);
2819 dir = _dbus_directory_open (&test_directory, &error);
2820 if (dir == NULL)
2821 {
2822 _dbus_warn ("Could not open %s: %s\n",
2823 _dbus_string_get_const_data (&test_directory),
2824 error.message);
2825 dbus_error_free (&error);
2826 goto failed;
2827 }
2828
2829 if (validity == VALID)
2830 printf ("Testing valid files:\n");
2831 else if (validity == INVALID)
2832 printf ("Testing invalid files:\n");
2833 else
2834 printf ("Testing unknown files:\n");
2835
2836 next:
2837 while (_dbus_directory_get_next_file (dir, &filename, &error))
2838 {
2839 DBusString full_path;
2840 LoaderOomData d;
2841
2842 if (!_dbus_string_init (&full_path))
2843 _dbus_assert_not_reached ("couldn't init string");
2844
2845 if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
2846 _dbus_assert_not_reached ("couldn't copy dir to full_path");
2847
2848 if (!_dbus_concat_dir_and_file (&full_path, &filename))
2849 _dbus_assert_not_reached ("couldn't concat file to dir");
2850
2851 if (!_dbus_string_ends_with_c_str (&full_path, ".conf"))
2852 {
2853 _dbus_verbose ("Skipping non-.conf file %s\n",
2854 _dbus_string_get_const_data (&filename));
2855 _dbus_string_free (&full_path);
2856 goto next;
2857 }
2858
2859 printf (" %s\n", _dbus_string_get_const_data (&filename));
2860
2861 _dbus_verbose (" expecting %s\n",
2862 validity == VALID ? "valid" :
2863 (validity == INVALID ? "invalid" :
2864 (validity == UNKNOWN ? "unknown" : "???")));
2865
2866 d.full_path = &full_path;
2867 d.validity = validity;
2868
2869 /* FIXME hackaround for an expat problem, see
2870 * https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=124747
2871 * http://freedesktop.org/pipermail/dbus/2004-May/001153.html
2872 */
2873 /* if (!_dbus_test_oom_handling ("config-loader", check_loader_oom_func, &d)) */
2874 if (!check_loader_oom_func (&d))
2875 _dbus_assert_not_reached ("test failed");
2876
2877 _dbus_string_free (&full_path);
2878 }
2879
2880 if (dbus_error_is_set (&error))
2881 {
2882 _dbus_warn ("Could not get next file in %s: %s\n",
2883 _dbus_string_get_const_data (&test_directory),
2884 error.message);
2885 dbus_error_free (&error);
2886 goto failed;
2887 }
2888
2889 retval = TRUE;
2890
2891 failed:
2892
2893 if (dir)
2894 _dbus_directory_close (dir);
2895 _dbus_string_free (&test_directory);
2896 _dbus_string_free (&filename);
2897
2898 return retval;
2899}
2900
2901static dbus_bool_t
2902bools_equal (dbus_bool_t a,
2903 dbus_bool_t b)
2904{
2905 return a ? b : !b;
2906}
2907
2908static dbus_bool_t
2909strings_equal_or_both_null (const char *a,
2910 const char *b)
2911{
2912 if (a == NULL || b == NULL)
2913 return a == b;
2914 else
2915 return !strcmp (a, b);
2916}
2917
2918static dbus_bool_t
2919elements_equal (const Element *a,
2920 const Element *b)
2921{
2922 if (a->type != b->type)
2923 return FALSE;
2924
2925 if (!bools_equal (a->had_content, b->had_content))
2926 return FALSE;
2927
2928 switch (a->type)
2929 {
2930
2931 case ELEMENT_INCLUDE:
2932 if (!bools_equal (a->d.include.ignore_missing,
2933 b->d.include.ignore_missing))
2934 return FALSE;
2935 break;
2936
2937 case ELEMENT_POLICY:
2938 if (a->d.policy.type != b->d.policy.type)
2939 return FALSE;
2940 if (a->d.policy.gid_uid_or_at_console != b->d.policy.gid_uid_or_at_console)
2941 return FALSE;
2942 break;
2943
2944 case ELEMENT_LIMIT:
2945 if (strcmp (a->d.limit.name, b->d.limit.name))
2946 return FALSE;
2947 if (a->d.limit.value != b->d.limit.value)
2948 return FALSE;
2949 break;
2950
2951 default:
2952 /* do nothing */
2953 break;
2954 }
2955
2956 return TRUE;
2957
2958}
2959
2960static dbus_bool_t
2961lists_of_elements_equal (DBusList *a,
2962 DBusList *b)
2963{
2964 DBusList *ia;
2965 DBusList *ib;
2966
2967 ia = a;
2968 ib = b;
2969
2970 while (ia != NULL && ib != NULL)
2971 {
2972 if (elements_equal (ia->data, ib->data))
2973 return FALSE;
2974 ia = _dbus_list_get_next_link (&a, ia);
2975 ib = _dbus_list_get_next_link (&b, ib);
2976 }
2977
2978 return ia == NULL && ib == NULL;
2979}
2980
2981static dbus_bool_t
2982lists_of_c_strings_equal (DBusList *a,
2983 DBusList *b)
2984{
2985 DBusList *ia;
2986 DBusList *ib;
2987
2988 ia = a;
2989 ib = b;
2990
2991 while (ia != NULL && ib != NULL)
2992 {
2993 if (strcmp (ia->data, ib->data))
2994 return FALSE;
2995 ia = _dbus_list_get_next_link (&a, ia);
2996 ib = _dbus_list_get_next_link (&b, ib);
2997 }
2998
2999 return ia == NULL && ib == NULL;
3000}
3001
3002static dbus_bool_t
3003limits_equal (const BusLimits *a,
3004 const BusLimits *b)
3005{
3006 return
3007 (a->max_incoming_bytes == b->max_incoming_bytes
3008 || a->max_incoming_unix_fds == b->max_incoming_unix_fds
3009 || a->max_outgoing_bytes == b->max_outgoing_bytes
3010 || a->max_outgoing_unix_fds == b->max_outgoing_unix_fds
3011 || a->max_message_size == b->max_message_size
3012 || a->max_message_unix_fds == b->max_message_unix_fds
3013 || a->activation_timeout == b->activation_timeout
3014 || a->auth_timeout == b->auth_timeout
3015 || a->max_completed_connections == b->max_completed_connections
3016 || a->max_incomplete_connections == b->max_incomplete_connections
3017 || a->max_connections_per_user == b->max_connections_per_user
3018 || a->max_pending_activations == b->max_pending_activations
3019 || a->max_services_per_connection == b->max_services_per_connection
3020 || a->max_match_rules_per_connection == b->max_match_rules_per_connection
3021 || a->max_replies_per_connection == b->max_replies_per_connection
3022 || a->reply_timeout == b->reply_timeout);
3023}
3024
3025static dbus_bool_t
3026config_parsers_equal (const BusConfigParser *a,
3027 const BusConfigParser *b)
3028{
3029 if (!_dbus_string_equal (&a->basedir, &b->basedir))
3030 return FALSE;
3031
3032 if (!lists_of_elements_equal (a->stack, b->stack))
3033 return FALSE;
3034
3035 if (!strings_equal_or_both_null (a->user, b->user))
3036 return FALSE;
3037
3038 if (!lists_of_c_strings_equal (a->listen_on, b->listen_on))
3039 return FALSE;
3040
3041 if (!lists_of_c_strings_equal (a->mechanisms, b->mechanisms))
3042 return FALSE;
3043
3044 if (!lists_of_c_strings_equal (a->service_dirs, b->service_dirs))
3045 return FALSE;
3046
3047 /* FIXME: compare policy */
3048
3049 /* FIXME: compare service selinux ID table */
3050
3051 if (! limits_equal (&a->limits, &b->limits))
3052 return FALSE;
3053
3054 if (!strings_equal_or_both_null (a->pidfile, b->pidfile))
3055 return FALSE;
3056
3057 if (! bools_equal (a->fork, b->fork))
3058 return FALSE;
3059
3060 if (! bools_equal (a->keep_umask, b->keep_umask))
3061 return FALSE;
3062
3063 if (! bools_equal (a->is_toplevel, b->is_toplevel))
3064 return FALSE;
3065
3066 return TRUE;
3067}
3068
3069static dbus_bool_t
3070all_are_equiv (const DBusString *target_directory)
3071{
3072 DBusString filename;
3073 DBusDirIter *dir;
3074 BusConfigParser *first_parser;
3075 BusConfigParser *parser;
3076 DBusError error;
3077 dbus_bool_t equal;
3078 dbus_bool_t retval;
3079
3080 dir = NULL;
3081 first_parser = NULL;
3082 parser = NULL;
3083 retval = FALSE;
3084
3085 if (!_dbus_string_init (&filename))
3086 _dbus_assert_not_reached ("didn't allocate filename string");
3087
3088 dbus_error_init (&error);
3089 dir = _dbus_directory_open (target_directory, &error);
3090 if (dir == NULL)
3091 {
3092 _dbus_warn ("Could not open %s: %s\n",
3093 _dbus_string_get_const_data (target_directory),
3094 error.message);
3095 dbus_error_free (&error);
3096 goto finished;
3097 }
3098
3099 printf ("Comparing equivalent files:\n");
3100
3101 next:
3102 while (_dbus_directory_get_next_file (dir, &filename, &error))
3103 {
3104 DBusString full_path;
3105
3106 if (!_dbus_string_init (&full_path))
3107 _dbus_assert_not_reached ("couldn't init string");
3108
3109 if (!_dbus_string_copy (target_directory, 0, &full_path, 0))
3110 _dbus_assert_not_reached ("couldn't copy dir to full_path");
3111
3112 if (!_dbus_concat_dir_and_file (&full_path, &filename))
3113 _dbus_assert_not_reached ("couldn't concat file to dir");
3114
3115 if (!_dbus_string_ends_with_c_str (&full_path, ".conf"))
3116 {
3117 _dbus_verbose ("Skipping non-.conf file %s\n",
3118 _dbus_string_get_const_data (&filename));
3119 _dbus_string_free (&full_path);
3120 goto next;
3121 }
3122
3123 printf (" %s\n", _dbus_string_get_const_data (&filename));
3124
3125 parser = bus_config_load (&full_path, TRUE, NULL, &error);
3126
3127 if (parser == NULL)
3128 {
3129 _dbus_warn ("Could not load file %s: %s\n",
3130 _dbus_string_get_const_data (&full_path),
3131 error.message);
3132 _dbus_string_free (&full_path);
3133 dbus_error_free (&error);
3134 goto finished;
3135 }
3136 else if (first_parser == NULL)
3137 {
3138 _dbus_string_free (&full_path);
3139 first_parser = parser;
3140 }
3141 else
3142 {
3143 _dbus_string_free (&full_path);
3144 equal = config_parsers_equal (first_parser, parser);
3145 bus_config_parser_unref (parser);
3146 if (! equal)
3147 goto finished;
3148 }
3149 }
3150
3151 retval = TRUE;
3152
3153 finished:
3154 _dbus_string_free (&filename);
3155 if (first_parser)
3156 bus_config_parser_unref (first_parser);
3157 if (dir)
3158 _dbus_directory_close (dir);
3159
3160 return retval;
3161
3162}
3163
3164static dbus_bool_t
3165process_test_equiv_subdir (const DBusString *test_base_dir,
3166 const char *subdir)
3167{
3168 DBusString test_directory;
3169 DBusString filename;
3170 DBusDirIter *dir;
3171 DBusError error;
3172 dbus_bool_t equal;
3173 dbus_bool_t retval;
3174
3175 dir = NULL;
3176 retval = FALSE;
3177
3178 if (!_dbus_string_init (&test_directory))
3179 _dbus_assert_not_reached ("didn't allocate test_directory");
3180
3181 _dbus_string_init_const (&filename, subdir);
3182
3183 if (!_dbus_string_copy (test_base_dir, 0,
3184 &test_directory, 0))
3185 _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
3186
3187 if (!_dbus_concat_dir_and_file (&test_directory, &filename))
3188 _dbus_assert_not_reached ("couldn't allocate full path");
3189
3190 _dbus_string_free (&filename);
3191 if (!_dbus_string_init (&filename))
3192 _dbus_assert_not_reached ("didn't allocate filename string");
3193
3194 dbus_error_init (&error);
3195 dir = _dbus_directory_open (&test_directory, &error);
3196 if (dir == NULL)
3197 {
3198 _dbus_warn ("Could not open %s: %s\n",
3199 _dbus_string_get_const_data (&test_directory),
3200 error.message);
3201 dbus_error_free (&error);
3202 goto finished;
3203 }
3204
3205 while (_dbus_directory_get_next_file (dir, &filename, &error))
3206 {
3207 DBusString full_path;
3208
3209 /* Skip CVS's magic directories! */
3210 if (_dbus_string_equal_c_str (&filename, "CVS"))
3211 continue;
3212
3213 if (!_dbus_string_init (&full_path))
3214 _dbus_assert_not_reached ("couldn't init string");
3215
3216 if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
3217 _dbus_assert_not_reached ("couldn't copy dir to full_path");
3218
3219 if (!_dbus_concat_dir_and_file (&full_path, &filename))
3220 _dbus_assert_not_reached ("couldn't concat file to dir");
3221
3222 equal = all_are_equiv (&full_path);
3223 _dbus_string_free (&full_path);
3224
3225 if (!equal)
3226 goto finished;
3227 }
3228
3229 retval = TRUE;
3230
3231 finished:
3232 _dbus_string_free (&test_directory);
3233 _dbus_string_free (&filename);
3234 if (dir)
3235 _dbus_directory_close (dir);
3236
3237 return retval;
3238
3239}
3240
3241static const char *test_session_service_dir_matches[] =
3242 {
3243#ifdef DBUS_UNIX
3244 "/testusr/testlocal/testshare/dbus-1/services",
3245 "/testusr/testshare/dbus-1/services",
3246#endif
3247 DBUS_DATADIR"/dbus-1/services",
3248#ifdef DBUS_UNIX
3249 "/testhome/foo/.testlocal/testshare/dbus-1/services",
3250#endif
3251#ifdef DBUS_WIN
3252 NULL,
3253#endif
3254 NULL
3255 };
3256
3257static dbus_bool_t
3258test_default_session_servicedirs (void)
3259{
3260 DBusList *dirs;
3261 DBusList *link;
3262 DBusString progs;
3263 const char *common_progs;
3264 int i;
3265
3266 /* On Unix we don't actually use this variable, but it's easier to handle the
3267 * deallocation if we always allocate it, whether needed or not */
3268 if (!_dbus_string_init (&progs))
3269 _dbus_assert_not_reached ("OOM allocating progs");
3270
3271 common_progs = _dbus_getenv ("CommonProgramFiles");
3272#ifndef DBUS_UNIX
3273 if (common_progs)
3274 {
3275 if (!_dbus_string_append (&progs, common_progs))
3276 {
3277 _dbus_string_free (&progs);
3278 return FALSE;
3279 }
3280
3281 if (!_dbus_string_append (&progs, "/dbus-1/services"))
3282 {
3283 _dbus_string_free (&progs);
3284 return FALSE;
3285 }
3286 test_session_service_dir_matches[1] = _dbus_string_get_const_data(&progs);
3287 }
3288#endif
3289 dirs = NULL;
3290
3291 printf ("Testing retrieving the default session service directories\n");
3292 if (!_dbus_get_standard_session_servicedirs (&dirs))
3293 _dbus_assert_not_reached ("couldn't get stardard dirs");
3294
3295 /* make sure our defaults end with share/dbus-1/service */
3296 while ((link = _dbus_list_pop_first_link (&dirs)))
3297 {
3298 DBusString path;
3299
3300 printf (" default service dir: %s\n", (char *)link->data);
3301 _dbus_string_init_const (&path, (char *)link->data);
3302 if (!_dbus_string_ends_with_c_str (&path, "dbus-1/services"))
3303 {
3304 printf ("error with default session service directories\n");
3305 dbus_free (link->data);
3306 _dbus_list_free_link (link);
3307 _dbus_string_free (&progs);
3308 return FALSE;
3309 }
3310
3311 dbus_free (link->data);
3312 _dbus_list_free_link (link);
3313 }
3314
3315#ifdef DBUS_UNIX
3316 if (!_dbus_setenv ("XDG_DATA_HOME", "/testhome/foo/.testlocal/testshare"))
3317 _dbus_assert_not_reached ("couldn't setenv XDG_DATA_HOME");
3318
3319 if (!_dbus_setenv ("XDG_DATA_DIRS", ":/testusr/testlocal/testshare: :/testusr/testshare:"))
3320 _dbus_assert_not_reached ("couldn't setenv XDG_DATA_DIRS");
3321#endif
3322 if (!_dbus_get_standard_session_servicedirs (&dirs))
3323 _dbus_assert_not_reached ("couldn't get stardard dirs");
3324
3325 /* make sure we read and parse the env variable correctly */
3326 i = 0;
3327 while ((link = _dbus_list_pop_first_link (&dirs)))
3328 {
3329 printf (" test service dir: %s\n", (char *)link->data);
3330 if (test_session_service_dir_matches[i] == NULL)
3331 {
3332 printf ("more directories parsed than in match set\n");
3333 dbus_free (link->data);
3334 _dbus_list_free_link (link);
3335 _dbus_string_free (&progs);
3336 return FALSE;
3337 }
3338
3339 if (strcmp (test_session_service_dir_matches[i],
3340 (char *)link->data) != 0)
3341 {
3342 printf ("%s directory does not match %s in the match set\n",
3343 (char *)link->data,
3344 test_session_service_dir_matches[i]);
3345 dbus_free (link->data);
3346 _dbus_list_free_link (link);
3347 _dbus_string_free (&progs);
3348 return FALSE;
3349 }
3350
3351 ++i;
3352
3353 dbus_free (link->data);
3354 _dbus_list_free_link (link);
3355 }
3356
3357 if (test_session_service_dir_matches[i] != NULL)
3358 {
3359 printf ("extra data %s in the match set was not matched\n",
3360 test_session_service_dir_matches[i]);
3361
3362 _dbus_string_free (&progs);
3363 return FALSE;
3364 }
3365
3366 _dbus_string_free (&progs);
3367 return TRUE;
3368}
3369
3370static const char *test_system_service_dir_matches[] =
3371 {
3372#ifdef DBUS_UNIX
3373 "/testusr/testlocal/testshare/dbus-1/system-services",
3374 "/testusr/testshare/dbus-1/system-services",
3375#endif
3376 DBUS_DATADIR"/dbus-1/system-services",
3377#ifdef DBUS_WIN
3378 NULL,
3379#endif
3380 NULL
3381 };
3382
3383static dbus_bool_t
3384test_default_system_servicedirs (void)
3385{
3386 DBusList *dirs;
3387 DBusList *link;
3388 DBusString progs;
3389 const char *common_progs;
3390 int i;
3391
3392 /* On Unix we don't actually use this variable, but it's easier to handle the
3393 * deallocation if we always allocate it, whether needed or not */
3394 if (!_dbus_string_init (&progs))
3395 _dbus_assert_not_reached ("OOM allocating progs");
3396
3397 common_progs = _dbus_getenv ("CommonProgramFiles");
3398#ifndef DBUS_UNIX
3399 if (common_progs)
3400 {
3401 if (!_dbus_string_append (&progs, common_progs))
3402 {
3403 _dbus_string_free (&progs);
3404 return FALSE;
3405 }
3406
3407 if (!_dbus_string_append (&progs, "/dbus-1/system-services"))
3408 {
3409 _dbus_string_free (&progs);
3410 return FALSE;
3411 }
3412 test_system_service_dir_matches[1] = _dbus_string_get_const_data(&progs);
3413 }
3414#endif
3415 dirs = NULL;
3416
3417 printf ("Testing retrieving the default system service directories\n");
3418 if (!_dbus_get_standard_system_servicedirs (&dirs))
3419 _dbus_assert_not_reached ("couldn't get stardard dirs");
3420
3421 /* make sure our defaults end with share/dbus-1/system-service */
3422 while ((link = _dbus_list_pop_first_link (&dirs)))
3423 {
3424 DBusString path;
3425
3426 printf (" default service dir: %s\n", (char *)link->data);
3427 _dbus_string_init_const (&path, (char *)link->data);
3428 if (!_dbus_string_ends_with_c_str (&path, "dbus-1/system-services"))
3429 {
3430 printf ("error with default system service directories\n");
3431 dbus_free (link->data);
3432 _dbus_list_free_link (link);
3433 _dbus_string_free (&progs);
3434 return FALSE;
3435 }
3436
3437 dbus_free (link->data);
3438 _dbus_list_free_link (link);
3439 }
3440
3441#ifdef DBUS_UNIX
3442 if (!_dbus_setenv ("XDG_DATA_HOME", "/testhome/foo/.testlocal/testshare"))
3443 _dbus_assert_not_reached ("couldn't setenv XDG_DATA_HOME");
3444
3445 if (!_dbus_setenv ("XDG_DATA_DIRS", ":/testusr/testlocal/testshare: :/testusr/testshare:"))
3446 _dbus_assert_not_reached ("couldn't setenv XDG_DATA_DIRS");
3447#endif
3448 if (!_dbus_get_standard_system_servicedirs (&dirs))
3449 _dbus_assert_not_reached ("couldn't get stardard dirs");
3450
3451 /* make sure we read and parse the env variable correctly */
3452 i = 0;
3453 while ((link = _dbus_list_pop_first_link (&dirs)))
3454 {
3455 printf (" test service dir: %s\n", (char *)link->data);
3456 if (test_system_service_dir_matches[i] == NULL)
3457 {
3458 printf ("more directories parsed than in match set\n");
3459 dbus_free (link->data);
3460 _dbus_list_free_link (link);
3461 _dbus_string_free (&progs);
3462 return FALSE;
3463 }
3464
3465 if (strcmp (test_system_service_dir_matches[i],
3466 (char *)link->data) != 0)
3467 {
3468 printf ("%s directory does not match %s in the match set\n",
3469 (char *)link->data,
3470 test_system_service_dir_matches[i]);
3471 dbus_free (link->data);
3472 _dbus_list_free_link (link);
3473 _dbus_string_free (&progs);
3474 return FALSE;
3475 }
3476
3477 ++i;
3478
3479 dbus_free (link->data);
3480 _dbus_list_free_link (link);
3481 }
3482
3483 if (test_system_service_dir_matches[i] != NULL)
3484 {
3485 printf ("extra data %s in the match set was not matched\n",
3486 test_system_service_dir_matches[i]);
3487
3488 _dbus_string_free (&progs);
3489 return FALSE;
3490 }
3491
3492 _dbus_string_free (&progs);
3493 return TRUE;
3494}
3495
3496dbus_bool_t
3497bus_config_parser_test (const DBusString *test_data_dir)
3498{
3499 if (test_data_dir == NULL ||
3500 _dbus_string_get_length (test_data_dir) == 0)
3501 {
3502 printf ("No test data\n");
3503 return TRUE;
3504 }
3505
3506 if (!test_default_session_servicedirs())
3507 return FALSE;
3508
3509#ifdef DBUS_WIN
3510 printf("default system service dir skipped\n");
3511#else
3512 if (!test_default_system_servicedirs())
3513 return FALSE;
3514#endif
3515
3516 if (!process_test_valid_subdir (test_data_dir, "valid-config-files", VALID))
3517 return FALSE;
3518
3519 if (!process_test_valid_subdir (test_data_dir, "invalid-config-files", INVALID))
3520 return FALSE;
3521
3522 if (!process_test_equiv_subdir (test_data_dir, "equiv-config-files"))
3523 return FALSE;
3524
3525 return TRUE;
3526}
3527
3528#endif /* DBUS_BUILD_TESTS */