* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
+#include "config-parser-common.h"
#include "config-parser.h"
#include "test.h"
#include "utils.h"
typedef enum
{
- ELEMENT_NONE,
- ELEMENT_BUSCONFIG,
- ELEMENT_INCLUDE,
- ELEMENT_USER,
- ELEMENT_LISTEN,
- ELEMENT_AUTH,
- ELEMENT_POLICY,
- ELEMENT_LIMIT,
- ELEMENT_ALLOW,
- ELEMENT_DENY,
- ELEMENT_FORK,
- ELEMENT_PIDFILE,
- ELEMENT_SERVICEDIR,
- ELEMENT_INCLUDEDIR,
- ELEMENT_TYPE,
- ELEMENT_SELINUX,
- ELEMENT_ASSOCIATE,
- ELEMENT_STANDARD_SESSION_SERVICEDIRS
-} ElementType;
-
-typedef enum
-{
/* we ignore policies for unknown groups/users */
POLICY_IGNORED,
char *user; /**< user to run as */
+ char *servicehelper; /**< location of the setuid helper */
+
char *bus_type; /**< Message bus type */
DBusList *listen_on; /**< List of addresses to listen to */
DBusList *mechanisms; /**< Auth mechanisms */
- DBusList *service_dirs; /**< Directories to look for services in */
+ DBusList *service_dirs; /**< Directories to look for session services in */
DBusList *conf_dirs; /**< Directories to look for policy configuration in */
unsigned int fork : 1; /**< TRUE to fork into daemon mode */
+ unsigned int keep_umask : 1; /**< TRUE to keep original umask when forking */
+
unsigned int is_toplevel : 1; /**< FALSE if we are a sub-config-file inside another one */
};
-static const char*
-element_type_to_name (ElementType type)
-{
- switch (type)
- {
- case ELEMENT_NONE:
- return NULL;
- case ELEMENT_BUSCONFIG:
- return "busconfig";
- case ELEMENT_INCLUDE:
- return "include";
- case ELEMENT_USER:
- return "user";
- case ELEMENT_LISTEN:
- return "listen";
- case ELEMENT_AUTH:
- return "auth";
- case ELEMENT_POLICY:
- return "policy";
- case ELEMENT_LIMIT:
- return "limit";
- case ELEMENT_ALLOW:
- return "allow";
- case ELEMENT_DENY:
- return "deny";
- case ELEMENT_FORK:
- return "fork";
- case ELEMENT_PIDFILE:
- return "pidfile";
- case ELEMENT_STANDARD_SESSION_SERVICEDIRS:
- return "standard_session_servicedirs";
- case ELEMENT_SERVICEDIR:
- return "servicedir";
- case ELEMENT_INCLUDEDIR:
- return "includedir";
- case ELEMENT_TYPE:
- return "type";
- case ELEMENT_SELINUX:
- return "selinux";
- case ELEMENT_ASSOCIATE:
- return "associate";
- }
-
- _dbus_assert_not_reached ("bad element type");
-
- return NULL;
-}
-
static Element*
push_element (BusConfigParser *parser,
ElementType type)
if (included->fork)
parser->fork = TRUE;
+ if (included->keep_umask)
+ parser->keep_umask = TRUE;
+
if (included->pidfile != NULL)
{
dbus_free (parser->pidfile);
pop_element (parser);
dbus_free (parser->user);
+ dbus_free (parser->servicehelper);
dbus_free (parser->bus_type);
dbus_free (parser->pidfile);
va_end (args);
- if (!retval)
- return retval;
-
i = 0;
while (attribute_names[i])
{
const char **attribute_values,
DBusError *error)
{
- if (strcmp (element_name, "user") == 0)
+ ElementType element_type;
+
+ element_type = bus_config_parser_element_name_to_type (element_name);
+
+ if (element_type == ELEMENT_USER)
{
if (!check_no_attributes (parser, "user", attribute_names, attribute_values, error))
return FALSE;
return TRUE;
}
- else if (strcmp (element_name, "type") == 0)
+ else if (element_type == ELEMENT_TYPE)
{
if (!check_no_attributes (parser, "type", attribute_names, attribute_values, error))
return FALSE;
return TRUE;
}
- else if (strcmp (element_name, "fork") == 0)
+ else if (element_type == ELEMENT_FORK)
{
if (!check_no_attributes (parser, "fork", attribute_names, attribute_values, error))
return FALSE;
return TRUE;
}
- else if (strcmp (element_name, "pidfile") == 0)
+ else if (element_type == ELEMENT_KEEP_UMASK)
+ {
+ if (!check_no_attributes (parser, "keep_umask", attribute_names, attribute_values, error))
+ return FALSE;
+
+ if (push_element (parser, ELEMENT_KEEP_UMASK) == NULL)
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ parser->keep_umask = TRUE;
+
+ return TRUE;
+ }
+ else if (element_type == ELEMENT_PIDFILE)
{
if (!check_no_attributes (parser, "pidfile", attribute_names, attribute_values, error))
return FALSE;
return TRUE;
}
- else if (strcmp (element_name, "listen") == 0)
+ else if (element_type == ELEMENT_LISTEN)
{
if (!check_no_attributes (parser, "listen", attribute_names, attribute_values, error))
return FALSE;
return TRUE;
}
- else if (strcmp (element_name, "auth") == 0)
+ else if (element_type == ELEMENT_AUTH)
{
if (!check_no_attributes (parser, "auth", attribute_names, attribute_values, error))
return FALSE;
return TRUE;
}
- else if (strcmp (element_name, "includedir") == 0)
+ else if (element_type == ELEMENT_SERVICEHELPER)
+ {
+ if (!check_no_attributes (parser, "servicehelper", attribute_names, attribute_values, error))
+ return FALSE;
+
+ if (push_element (parser, ELEMENT_SERVICEHELPER) == NULL)
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+ else if (element_type == ELEMENT_INCLUDEDIR)
{
if (!check_no_attributes (parser, "includedir", attribute_names, attribute_values, error))
return FALSE;
return TRUE;
}
- else if (strcmp (element_name, "standard_session_servicedirs") == 0)
+ else if (element_type == ELEMENT_STANDARD_SESSION_SERVICEDIRS)
{
DBusList *link;
DBusList *dirs;
return TRUE;
}
- else if (strcmp (element_name, "servicedir") == 0)
+ else if (element_type == ELEMENT_STANDARD_SYSTEM_SERVICEDIRS)
+ {
+ DBusList *link;
+ DBusList *dirs;
+ dirs = NULL;
+
+ if (!check_no_attributes (parser, "standard_system_servicedirs", attribute_names, attribute_values, error))
+ return FALSE;
+
+ if (push_element (parser, ELEMENT_STANDARD_SYSTEM_SERVICEDIRS) == NULL)
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ if (!_dbus_get_standard_system_servicedirs (&dirs))
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ while ((link = _dbus_list_pop_first_link (&dirs)))
+ service_dirs_append_link_unique_or_free (&parser->service_dirs, link);
+
+ return TRUE;
+ }
+ else if (element_type == ELEMENT_SERVICEDIR)
{
if (!check_no_attributes (parser, "servicedir", attribute_names, attribute_values, error))
return FALSE;
return TRUE;
}
- else if (strcmp (element_name, "include") == 0)
+ else if (element_type == ELEMENT_INCLUDE)
{
Element *e;
const char *if_selinux_enabled;
return TRUE;
}
- else if (strcmp (element_name, "policy") == 0)
+ else if (element_type == ELEMENT_POLICY)
{
Element *e;
const char *context;
return TRUE;
}
- else if (strcmp (element_name, "limit") == 0)
+ else if (element_type == ELEMENT_LIMIT)
{
Element *e;
const char *name;
return TRUE;
}
- else if (strcmp (element_name, "selinux") == 0)
+ else if (element_type == ELEMENT_SELINUX)
{
if (!check_no_attributes (parser, "selinux", attribute_names, attribute_values, error))
return FALSE;
return FALSE;
}
- n = element_type_to_name (t);
+ n = bus_config_parser_element_type_to_name (t);
_dbus_assert (n != NULL);
if (strcmp (n, element_name) != 0)
{
case ELEMENT_PIDFILE:
case ELEMENT_AUTH:
case ELEMENT_SERVICEDIR:
+ case ELEMENT_SERVICEHELPER:
case ELEMENT_INCLUDEDIR:
case ELEMENT_LIMIT:
if (!e->had_content)
{
dbus_set_error (error, DBUS_ERROR_FAILED,
"XML element <%s> was expected to have content inside it",
- element_type_to_name (e->type));
+ bus_config_parser_element_type_to_name (e->type));
return FALSE;
}
case ELEMENT_ALLOW:
case ELEMENT_DENY:
case ELEMENT_FORK:
+ case ELEMENT_KEEP_UMASK:
case ELEMENT_SELINUX:
case ELEMENT_ASSOCIATE:
case ELEMENT_STANDARD_SESSION_SERVICEDIRS:
+ case ELEMENT_STANDARD_SYSTEM_SERVICEDIRS:
break;
}
}
static dbus_bool_t
+servicehelper_path (BusConfigParser *parser,
+ const DBusString *filename,
+ DBusError *error)
+{
+ const char *filename_str;
+ char *servicehelper;
+
+ filename_str = _dbus_string_get_const_data (filename);
+
+ /* copy to avoid overwriting with NULL on OOM */
+ servicehelper = _dbus_strdup (filename_str);
+
+ /* check for OOM */
+ if (servicehelper == NULL)
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ /* save the latest servicehelper only if not OOM */
+ dbus_free (parser->servicehelper);
+ parser->servicehelper = servicehelper;
+
+ /* We don't check whether the helper exists; instead we
+ * would just fail to ever activate anything if it doesn't.
+ * This allows an admin to fix the problem if it doesn't exist.
+ * It also allows the parser test suite to successfully parse
+ * test cases without installing the helper. ;-)
+ */
+
+ return TRUE;
+}
+
+static dbus_bool_t
include_dir (BusConfigParser *parser,
const DBusString *dirname,
DBusError *error)
case ELEMENT_ALLOW:
case ELEMENT_DENY:
case ELEMENT_FORK:
+ case ELEMENT_KEEP_UMASK:
case ELEMENT_STANDARD_SESSION_SERVICEDIRS:
+ case ELEMENT_STANDARD_SYSTEM_SERVICEDIRS:
case ELEMENT_SELINUX:
case ELEMENT_ASSOCIATE:
if (all_whitespace (content))
{
dbus_set_error (error, DBUS_ERROR_FAILED,
"No text content expected inside XML element %s in configuration file",
- element_type_to_name (top_element_type (parser)));
+ bus_config_parser_element_type_to_name (top_element_type (parser)));
return FALSE;
}
}
break;
+ case ELEMENT_SERVICEHELPER:
+ {
+ DBusString full_path;
+
+ e->had_content = TRUE;
+
+ if (!_dbus_string_init (&full_path))
+ goto nomem;
+
+ if (!make_full_path (&parser->basedir, content, &full_path))
+ {
+ _dbus_string_free (&full_path);
+ goto nomem;
+ }
+
+ if (!servicehelper_path (parser, &full_path, error))
+ {
+ _dbus_string_free (&full_path);
+ return FALSE;
+ }
+
+ _dbus_string_free (&full_path);
+ }
+ break;
+
case ELEMENT_INCLUDEDIR:
{
DBusString full_path;
goto nomem;
}
+ /* _only_ extra session directories can be specified */
if (!service_dirs_append_unique_or_free (&parser->service_dirs, s))
{
_dbus_string_free (&full_path);
{
dbus_set_error (error, DBUS_ERROR_FAILED,
"Element <%s> was not closed in configuration file",
- element_type_to_name (top_element_type (parser)));
+ bus_config_parser_element_type_to_name (top_element_type (parser)));
return FALSE;
}
return parser->fork;
}
+dbus_bool_t
+bus_config_parser_get_keep_umask (BusConfigParser *parser)
+{
+ return parser->keep_umask;
+}
+
const char *
bus_config_parser_get_pidfile (BusConfigParser *parser)
{
return parser->pidfile;
}
+const char *
+bus_config_parser_get_servicehelper (BusConfigParser *parser)
+{
+ return parser->servicehelper;
+}
+
BusPolicy*
bus_config_parser_steal_policy (BusConfigParser *parser)
{
if (! bools_equal (a->fork, b->fork))
return FALSE;
+ if (! bools_equal (a->keep_umask, b->keep_umask))
+ return FALSE;
+
if (! bools_equal (a->is_toplevel, b->is_toplevel))
return FALSE;
}
-static const char *test_service_dir_matches[] =
+static const char *test_session_service_dir_matches[] =
{
#ifdef DBUS_UNIX
"/testusr/testlocal/testshare/dbus-1/services",
_dbus_string_free (&progs);
return FALSE;
}
- test_service_dir_matches[1] = _dbus_string_get_const_data(&progs);
+ test_session_service_dir_matches[1] = _dbus_string_get_const_data(&progs);
}
#endif
dirs = NULL;
while ((link = _dbus_list_pop_first_link (&dirs)))
{
printf (" test service dir: %s\n", (char *)link->data);
- if (test_service_dir_matches[i] == NULL)
+ if (test_session_service_dir_matches[i] == NULL)
+ {
+ printf ("more directories parsed than in match set\n");
+ dbus_free (link->data);
+ _dbus_list_free_link (link);
+ _dbus_string_free (&progs);
+ return FALSE;
+ }
+
+ if (strcmp (test_session_service_dir_matches[i],
+ (char *)link->data) != 0)
+ {
+ printf ("%s directory does not match %s in the match set\n",
+ (char *)link->data,
+ test_session_service_dir_matches[i]);
+ dbus_free (link->data);
+ _dbus_list_free_link (link);
+ _dbus_string_free (&progs);
+ return FALSE;
+ }
+
+ ++i;
+
+ dbus_free (link->data);
+ _dbus_list_free_link (link);
+ }
+
+ if (test_session_service_dir_matches[i] != NULL)
+ {
+ printf ("extra data %s in the match set was not matched\n",
+ test_session_service_dir_matches[i]);
+
+ _dbus_string_free (&progs);
+ return FALSE;
+ }
+
+ _dbus_string_free (&progs);
+ return TRUE;
+}
+
+static const char *test_system_service_dir_matches[] =
+ {
+#ifdef DBUS_UNIX
+ "/testusr/testlocal/testshare/dbus-1/system-services",
+ "/testusr/testshare/dbus-1/system-services",
+#endif
+ DBUS_DATADIR"/dbus-1/system-services",
+ NULL
+ };
+
+static dbus_bool_t
+test_default_system_servicedirs (void)
+{
+ DBusList *dirs;
+ DBusList *link;
+ DBusString progs;
+ const char *common_progs;
+ int i;
+
+ /* On Unix we don't actually use this variable, but it's easier to handle the
+ * deallocation if we always allocate it, whether needed or not */
+ if (!_dbus_string_init (&progs))
+ _dbus_assert_not_reached ("OOM allocating progs");
+
+ common_progs = _dbus_getenv ("CommonProgramFiles");
+#ifndef DBUS_UNIX
+ if (common_progs)
+ {
+ if (!_dbus_string_append (&progs, common_progs))
+ {
+ _dbus_string_free (&progs);
+ return FALSE;
+ }
+
+ if (!_dbus_string_append (&progs, "/dbus-1/system-services"))
+ {
+ _dbus_string_free (&progs);
+ return FALSE;
+ }
+ test_system_service_dir_matches[1] = _dbus_string_get_const_data(&progs);
+ }
+#endif
+ dirs = NULL;
+
+ printf ("Testing retrieving the default system service directories\n");
+ if (!_dbus_get_standard_system_servicedirs (&dirs))
+ _dbus_assert_not_reached ("couldn't get stardard dirs");
+
+ /* make sure our defaults end with share/dbus-1/system-service */
+ while ((link = _dbus_list_pop_first_link (&dirs)))
+ {
+ DBusString path;
+
+ printf (" default service dir: %s\n", (char *)link->data);
+ _dbus_string_init_const (&path, (char *)link->data);
+ if (!_dbus_string_ends_with_c_str (&path, "dbus-1/system-services"))
+ {
+ printf ("error with default system service directories\n");
+ dbus_free (link->data);
+ _dbus_list_free_link (link);
+ _dbus_string_free (&progs);
+ return FALSE;
+ }
+
+ dbus_free (link->data);
+ _dbus_list_free_link (link);
+ }
+
+#ifdef DBUS_UNIX
+ if (!_dbus_setenv ("XDG_DATA_HOME", "/testhome/foo/.testlocal/testshare"))
+ _dbus_assert_not_reached ("couldn't setenv XDG_DATA_HOME");
+
+ if (!_dbus_setenv ("XDG_DATA_DIRS", ":/testusr/testlocal/testshare: :/testusr/testshare:"))
+ _dbus_assert_not_reached ("couldn't setenv XDG_DATA_DIRS");
+#endif
+ if (!_dbus_get_standard_system_servicedirs (&dirs))
+ _dbus_assert_not_reached ("couldn't get stardard dirs");
+
+ /* make sure we read and parse the env variable correctly */
+ i = 0;
+ while ((link = _dbus_list_pop_first_link (&dirs)))
+ {
+ printf (" test service dir: %s\n", (char *)link->data);
+ if (test_system_service_dir_matches[i] == NULL)
{
printf ("more directories parsed than in match set\n");
dbus_free (link->data);
return FALSE;
}
- if (strcmp (test_service_dir_matches[i],
+ if (strcmp (test_system_service_dir_matches[i],
(char *)link->data) != 0)
{
printf ("%s directory does not match %s in the match set\n",
(char *)link->data,
- test_service_dir_matches[i]);
+ test_system_service_dir_matches[i]);
dbus_free (link->data);
_dbus_list_free_link (link);
_dbus_string_free (&progs);
_dbus_list_free_link (link);
}
- if (test_service_dir_matches[i] != NULL)
+ if (test_system_service_dir_matches[i] != NULL)
{
printf ("extra data %s in the match set was not matched\n",
- test_service_dir_matches[i]);
+ test_system_service_dir_matches[i]);
_dbus_string_free (&progs);
return FALSE;
_dbus_string_free (&progs);
return TRUE;
}
-
+
dbus_bool_t
bus_config_parser_test (const DBusString *test_data_dir)
{
if (!test_default_session_servicedirs())
return FALSE;
+ if (!test_default_system_servicedirs())
+ return FALSE;
+
if (!process_test_valid_subdir (test_data_dir, "valid-config-files", VALID))
return FALSE;