X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=bus%2Fbus.c;h=61f6d7d307333ebc0241343a9fb96f03d9a6523b;hb=1e9b185b0c274ef0d684b1e43418388225321e72;hp=91c9e6a7740bf2c1a0bd2240e5d4fc745a0d24c1;hpb=d6e1b2adb3d8e51ce1bb47295cef12d9fe1a15a8;p=platform%2Fupstream%2Fdbus.git diff --git a/bus/bus.c b/bus/bus.c index 91c9e6a..61f6d7d 100644 --- a/bus/bus.c +++ b/bus/bus.c @@ -1,9 +1,9 @@ /* -*- mode: C; c-file-style: "gnu" -*- */ /* bus.c message bus context object * - * Copyright (C) 2003 Red Hat, Inc. + * Copyright (C) 2003, 2004 Red Hat, Inc. * - * Licensed under the Academic Free License version 1.2 + * Licensed under the Academic Free License version 2.0 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,6 +29,7 @@ #include "policy.h" #include "config-parser.h" #include "signals.h" +#include "selinux.h" #include #include #include @@ -36,10 +37,11 @@ struct BusContext { int refcount; + char *config_file; char *type; - char *bus_env_var; char *address; char *pidfile; + char *user; DBusLoop *loop; DBusList *servers; BusConnections *connections; @@ -49,6 +51,7 @@ struct BusContext BusMatchmaker *matchmaker; DBusUserDatabase *user_database; BusLimits limits; + unsigned int fork : 1; }; static dbus_int32_t server_data_slot = -1; @@ -248,45 +251,26 @@ setup_server (BusContext *context, return TRUE; } -BusContext* -bus_context_new (const DBusString *config_file, - dbus_bool_t force_fork, - int print_addr_fd, - int print_pid_fd, - DBusError *error) +/* This code only gets executed the first time the + config files are parsed. It is not executed + when config files are reloaded.*/ +static dbus_bool_t +process_config_first_time_only (BusContext *context, + BusConfigParser *parser, + DBusError *error) { - BusContext *context; DBusList *link; DBusList **addresses; - BusConfigParser *parser; - DBusString full_address; const char *user, *pidfile; char **auth_mechanisms; DBusList **auth_mechanisms_list; int len; - - _DBUS_ASSERT_ERROR_IS_CLEAR (error); + dbus_bool_t retval; - if (!_dbus_string_init (&full_address)) - { - BUS_SET_OOM (error); - return NULL; - } + _DBUS_ASSERT_ERROR_IS_CLEAR (error); - if (!dbus_server_allocate_data_slot (&server_data_slot)) - { - BUS_SET_OOM (error); - _dbus_string_free (&full_address); - return NULL; - } - - parser = NULL; - context = NULL; + retval = FALSE; auth_mechanisms = NULL; - - parser = bus_config_load (config_file, TRUE, error); - if (parser == NULL) - goto failed; /* Check for an existing pid file. Of course this is a race; * we'd have to use fcntl() locks on the pid file to @@ -313,38 +297,9 @@ bus_context_new (const DBusString *config_file, } } - context = dbus_new0 (BusContext, 1); - if (context == NULL) - { - BUS_SET_OOM (error); - goto failed; - } - - context->refcount = 1; + /* keep around the pid filename so we can delete it later */ + context->pidfile = _dbus_strdup (pidfile); - /* get our limits and timeout lengths */ - bus_config_parser_get_limits (parser, &context->limits); - - /* we need another ref of the server data slot for the context - * to own - */ - if (!dbus_server_allocate_data_slot (&server_data_slot)) - _dbus_assert_not_reached ("second ref of server data slot failed"); - - context->user_database = _dbus_user_database_new (); - if (context->user_database == NULL) - { - BUS_SET_OOM (error); - goto failed; - } - - context->loop = _dbus_loop_new (); - if (context->loop == NULL) - { - BUS_SET_OOM (error); - goto failed; - } - /* Build an array of auth mechanisms */ auth_mechanisms_list = bus_config_parser_get_mechanisms (parser); @@ -356,7 +311,10 @@ bus_context_new (const DBusString *config_file, auth_mechanisms = dbus_new0 (char*, len + 1); if (auth_mechanisms == NULL) - goto failed; + { + BUS_SET_OOM (error); + goto failed; + } i = 0; link = _dbus_list_get_first_link (auth_mechanisms_list); @@ -364,7 +322,10 @@ bus_context_new (const DBusString *config_file, { auth_mechanisms[i] = _dbus_strdup (link->data); if (auth_mechanisms[i] == NULL) - goto failed; + { + BUS_SET_OOM (error); + goto failed; + } link = _dbus_list_get_next_link (auth_mechanisms_list, link); } } @@ -384,9 +345,15 @@ bus_context_new (const DBusString *config_file, server = dbus_server_listen (link->data, error); if (server == NULL) - goto failed; + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed; + } else if (!setup_server (context, server, auth_mechanisms, error)) - goto failed; + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed; + } if (!_dbus_list_append (&context->servers, server)) { @@ -404,7 +371,59 @@ bus_context_new (const DBusString *config_file, BUS_SET_OOM (error); goto failed; } + + user = bus_config_parser_get_user (parser); + if (user != NULL) + { + context->user = _dbus_strdup (user); + if (context->user == NULL) + { + BUS_SET_OOM (error); + goto failed; + } + } + + context->fork = bus_config_parser_get_fork (parser); + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + retval = TRUE; + + failed: + dbus_free_string_array (auth_mechanisms); + return retval; +} + +/* This code gets executed every time the config files + are parsed: both during BusContext construction + and on reloads. */ +static dbus_bool_t +process_config_every_time (BusContext *context, + BusConfigParser *parser, + dbus_bool_t is_reload, + DBusError *error) +{ + DBusString full_address; + DBusList *link; + DBusHashTable *service_sid_table; + dbus_bool_t retval; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + retval = FALSE; + + if (!_dbus_string_init (&full_address)) + { + BUS_SET_OOM (error); + return FALSE; + } + + /* get our limits and timeout lengths */ + bus_config_parser_get_limits (parser, &context->limits); + + context->policy = bus_config_parser_steal_policy (parser); + _dbus_assert (context->policy != NULL); + /* We have to build the address backward, so that * later in the config file have priority */ @@ -440,12 +459,149 @@ bus_context_new (const DBusString *config_file, link = _dbus_list_get_prev_link (&context->servers, link); } + if (is_reload) + dbus_free (context->address); + if (!_dbus_string_copy_data (&full_address, &context->address)) { BUS_SET_OOM (error); goto failed; } + /* Create activation subsystem */ + + if (is_reload) + bus_activation_unref (context->activation); + + context->activation = bus_activation_new (context, &full_address, + bus_config_parser_get_service_dirs (parser), + error); + if (context->activation == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed; + } + + service_sid_table = bus_config_parser_steal_service_sid_table (parser); + bus_registry_set_service_sid_table (context->registry, + service_sid_table); + _dbus_hash_table_unref (service_sid_table); + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + retval = TRUE; + + failed: + _dbus_string_free (&full_address); + return retval; +} + +static dbus_bool_t +load_config (BusContext *context, + dbus_bool_t is_reload, + DBusError *error) +{ + BusConfigParser *parser; + DBusString config_file; + dbus_bool_t retval; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + retval = FALSE; + parser = NULL; + + _dbus_string_init_const (&config_file, context->config_file); + parser = bus_config_load (&config_file, TRUE, NULL, error); + if (parser == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed; + } + + if (!is_reload && !process_config_first_time_only (context, parser, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed; + } + + if (!process_config_every_time (context, parser, is_reload, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed; + } + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + retval = TRUE; + + failed: + if (parser) + bus_config_parser_unref (parser); + return retval; +} + +BusContext* +bus_context_new (const DBusString *config_file, + dbus_bool_t force_fork, + int print_addr_fd, + int print_pid_fd, + DBusError *error) +{ + BusContext *context; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (!dbus_server_allocate_data_slot (&server_data_slot)) + { + BUS_SET_OOM (error); + return NULL; + } + + context = dbus_new0 (BusContext, 1); + if (context == NULL) + { + BUS_SET_OOM (error); + goto failed; + } + context->refcount = 1; + + if (!_dbus_string_copy_data (config_file, &context->config_file)) + { + BUS_SET_OOM (error); + goto failed; + } + + context->loop = _dbus_loop_new (); + if (context->loop == NULL) + { + BUS_SET_OOM (error); + goto failed; + } + + context->registry = bus_registry_new (context); + if (context->registry == NULL) + { + BUS_SET_OOM (error); + goto failed; + } + + if (!load_config (context, FALSE, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed; + } + + /* we need another ref of the server data slot for the context + * to own + */ + if (!dbus_server_allocate_data_slot (&server_data_slot)) + _dbus_assert_not_reached ("second ref of server data slot failed"); + + context->user_database = _dbus_user_database_new (); + if (context->user_database == NULL) + { + BUS_SET_OOM (error); + goto failed; + } + /* Note that we don't know whether the print_addr_fd is * one of the sockets we're using to listen on, or some * other random thing. But I think the answer is "don't do @@ -488,17 +644,6 @@ bus_context_new (const DBusString *config_file, _dbus_string_free (&addr); } - /* Create activation subsystem */ - - context->activation = bus_activation_new (context, &full_address, - bus_config_parser_get_service_dirs (parser), - error); - if (context->activation == NULL) - { - _DBUS_ASSERT_ERROR_IS_SET (error); - goto failed; - } - context->connections = bus_connections_new (context); if (context->connections == NULL) { @@ -506,13 +651,6 @@ bus_context_new (const DBusString *config_file, goto failed; } - context->registry = bus_registry_new (context); - if (context->registry == NULL) - { - BUS_SET_OOM (error); - goto failed; - } - context->matchmaker = bus_matchmaker_new (); if (context->matchmaker == NULL) { @@ -520,37 +658,37 @@ bus_context_new (const DBusString *config_file, goto failed; } - context->policy = bus_config_parser_steal_policy (parser); - _dbus_assert (context->policy != NULL); - /* Now become a daemon if appropriate */ - if (force_fork || bus_config_parser_get_fork (parser)) + if (force_fork || context->fork) { DBusString u; - if (pidfile) - _dbus_string_init_const (&u, pidfile); + if (context->pidfile) + _dbus_string_init_const (&u, context->pidfile); - if (!_dbus_become_daemon (pidfile ? &u : NULL, error)) - goto failed; + if (!_dbus_become_daemon (context->pidfile ? &u : NULL, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed; + } } else { /* Need to write PID file for ourselves, not for the child process */ - if (pidfile != NULL) + if (context->pidfile != NULL) { DBusString u; - _dbus_string_init_const (&u, pidfile); + _dbus_string_init_const (&u, context->pidfile); if (!_dbus_write_pid_file (&u, _dbus_getpid (), error)) - goto failed; + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed; + } } } - /* keep around the pid filename so we can delete it later */ - context->pidfile = _dbus_strdup (pidfile); - /* Write PID if requested */ if (print_pid_fd >= 0) { @@ -590,13 +728,12 @@ bus_context_new (const DBusString *config_file, /* Here we change our credentials if required, * as soon as we've set up our sockets and pidfile */ - user = bus_config_parser_get_user (parser); - if (user != NULL) + if (context->user != NULL) { DBusCredentials creds; DBusString u; - _dbus_string_init_const (&u, user); + _dbus_string_init_const (&u, context->user); if (!_dbus_credentials_from_username (&u, &creds) || creds.uid < 0 || @@ -604,36 +741,40 @@ bus_context_new (const DBusString *config_file, { dbus_set_error (error, DBUS_ERROR_FAILED, "Could not get UID and GID for username \"%s\"", - user); + context->user); goto failed; } if (!_dbus_change_identity (creds.uid, creds.gid, error)) - goto failed; + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed; + } } - bus_config_parser_unref (parser); - _dbus_string_free (&full_address); - dbus_free_string_array (auth_mechanisms); dbus_server_free_data_slot (&server_data_slot); return context; failed: - if (parser != NULL) - bus_config_parser_unref (parser); - if (context != NULL) bus_context_unref (context); - _dbus_string_free (&full_address); - dbus_free_string_array (auth_mechanisms); - - dbus_server_free_data_slot (&server_data_slot); + if (server_data_slot >= 0) + dbus_server_free_data_slot (&server_data_slot); return NULL; } +dbus_bool_t +bus_context_reload_config (BusContext *context, + DBusError *error) +{ + return load_config (context, + TRUE, /* yes, we are re-loading */ + error); +} + static void shutdown_server (BusContext *context, DBusServer *server) @@ -671,11 +812,13 @@ bus_context_shutdown (BusContext *context) } } -void +BusContext * bus_context_ref (BusContext *context) { _dbus_assert (context->refcount > 0); context->refcount += 1; + + return context; } void @@ -737,8 +880,10 @@ bus_context_unref (BusContext *context) context->matchmaker = NULL; } + dbus_free (context->config_file); dbus_free (context->type); dbus_free (context->address); + dbus_free (context->user); if (context->pidfile) { @@ -753,7 +898,8 @@ bus_context_unref (BusContext *context) dbus_free (context->pidfile); } - _dbus_user_database_unref (context->user_database); + if (context->user_database != NULL) + _dbus_user_database_unref (context->user_database); dbus_free (context); @@ -819,6 +965,12 @@ bus_context_allow_user (BusContext *context, uid); } +BusPolicy * +bus_context_get_policy (BusContext *context) +{ + return context->policy; +} + BusClientPolicy* bus_context_create_client_policy (BusContext *context, DBusConnection *connection, @@ -921,7 +1073,8 @@ bus_context_check_security_policy (BusContext *context, /* dispatch.c was supposed to ensure these invariants */ _dbus_assert (dbus_message_get_destination (message) != NULL || - type == DBUS_MESSAGE_TYPE_SIGNAL); + type == DBUS_MESSAGE_TYPE_SIGNAL || + (sender == NULL && !bus_connection_is_active (proposed_recipient))); _dbus_assert (type == DBUS_MESSAGE_TYPE_SIGNAL || addressed_recipient != NULL || strcmp (dbus_message_get_destination (message), DBUS_SERVICE_ORG_FREEDESKTOP_DBUS) == 0); @@ -948,6 +1101,28 @@ bus_context_check_security_policy (BusContext *context, if (sender != NULL) { + /* First verify the SELinux access controls. If allowed then + * go on with the standard checks. + */ + if (!bus_selinux_allows_send (sender, proposed_recipient)) + { + const char *dest = dbus_message_get_destination (message); + dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, + "An SELinux policy prevents this sender " + "from sending this message to this recipient " + "(rejected message had interface \"%s\" " + "member \"%s\" error name \"%s\" destination \"%s\")", + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : "(unset)", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : "(unset)", + dbus_message_get_error_name (message) ? + dbus_message_get_error_name (message) : "(unset)", + dest ? dest : DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); + _dbus_verbose ("SELinux security check denying send to service\n"); + return FALSE; + } + if (bus_connection_is_active (sender)) { sender_policy = bus_connection_get_policy (sender); @@ -1049,7 +1224,9 @@ bus_context_check_security_policy (BusContext *context, if (sender_policy && !bus_client_policy_check_can_send (sender_policy, - context->registry, proposed_recipient, + context->registry, + requested_reply, + proposed_recipient, message)) { const char *dest = dbus_message_get_destination (message);