static dbus_bool_t send_ack_reply (DBusConnection *connection, BusTransaction *transaction, DBusMessage *message, DBusError *error) { DBusMessage *reply; reply = dbus_message_new_method_return (message); if (reply == NULL) { BUS_SET_OOM (error); return FALSE; } if (!bus_transaction_send_from_driver (transaction, connection, reply)) { BUS_SET_OOM (error); dbus_message_unref (reply); return FALSE; } dbus_message_unref (reply); return TRUE; }
static dbus_bool_t bus_driver_handle_release_service (DBusConnection *connection, BusTransaction *transaction, DBusMessage *message, DBusError *error) { DBusMessage *reply; DBusString service_name; const char *name; dbus_uint32_t service_reply; dbus_bool_t retval; BusRegistry *registry; _DBUS_ASSERT_ERROR_IS_CLEAR (error); registry = bus_connection_get_registry (connection); if (!dbus_message_get_args (message, error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) return FALSE; _dbus_verbose ("Trying to release name %s\n", name); retval = FALSE; reply = NULL; _dbus_string_init_const (&service_name, name); if (!bus_registry_release_service (registry, connection, &service_name, &service_reply, transaction, error)) goto out; reply = dbus_message_new_method_return (message); if (reply == NULL) { BUS_SET_OOM (error); goto out; } if (!dbus_message_append_args (reply, DBUS_TYPE_UINT32, &service_reply, DBUS_TYPE_INVALID)) { BUS_SET_OOM (error); goto out; } if (!bus_transaction_send_from_driver (transaction, connection, reply)) { BUS_SET_OOM (error); goto out; } retval = TRUE; out: if (reply) dbus_message_unref (reply); return retval; }
static dbus_bool_t setup_server (BusContext *context, DBusServer *server, char **auth_mechanisms, DBusError *error) { BusServerData *bd; bd = dbus_new0 (BusServerData, 1); if (bd == NULL || !dbus_server_set_data (server, server_data_slot, bd, free_server_data)) { dbus_free (bd); BUS_SET_OOM (error); return FALSE; } bd->context = context; if (!dbus_server_set_auth_mechanisms (server, (const char**) auth_mechanisms)) { BUS_SET_OOM (error); return FALSE; } dbus_server_set_new_connection_function (server, new_connection_callback, context, NULL); if (!dbus_server_set_watch_functions (server, add_server_watch, remove_server_watch, toggle_server_watch, server, NULL)) { BUS_SET_OOM (error); return FALSE; } if (!dbus_server_set_timeout_functions (server, add_server_timeout, remove_server_timeout, NULL, server, NULL)) { BUS_SET_OOM (error); return FALSE; } return TRUE; }
dbus_bool_t bus_driver_send_service_owner_changed (const char *service_name, const char *old_owner, const char *new_owner, BusTransaction *transaction, DBusError *error) { DBusMessage *message; dbus_bool_t retval; const char *null_service; _DBUS_ASSERT_ERROR_IS_CLEAR (error); null_service = ""; _dbus_verbose ("sending name owner changed: %s [%s -> %s]\n", service_name, old_owner ? old_owner : null_service, new_owner ? new_owner : null_service); message = dbus_message_new_signal (DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "NameOwnerChanged"); if (message == NULL) { BUS_SET_OOM (error); return FALSE; } if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS)) goto oom; if (!dbus_message_append_args (message, DBUS_TYPE_STRING, &service_name, DBUS_TYPE_STRING, old_owner ? &old_owner : &null_service, DBUS_TYPE_STRING, new_owner ? &new_owner : &null_service, DBUS_TYPE_INVALID)) goto oom; _dbus_assert (dbus_message_has_signature (message, "sss")); retval = bus_dispatch_matches (transaction, NULL, NULL, message, error); dbus_message_unref (message); return retval; oom: dbus_message_unref (message); BUS_SET_OOM (error); return FALSE; }
dbus_bool_t bus_desktop_file_get_string (BusDesktopFile *desktop_file, const char *section, const char *keyname, char **val, DBusError *error) { const char *raw; _DBUS_ASSERT_ERROR_IS_CLEAR (error); *val = NULL; if (!bus_desktop_file_get_raw (desktop_file, section, keyname, &raw)) { dbus_set_error (error, DBUS_ERROR_FAILED, "No \"%s\" key in .service file\n", keyname); return FALSE; } *val = _dbus_strdup (raw); if (*val == NULL) { BUS_SET_OOM (error); return FALSE; } return TRUE; }
dbus_bool_t bus_service_list_queued_owners (BusService *service, DBusList **return_list, DBusError *error) { DBusList *link; _dbus_assert (*return_list == NULL); link = _dbus_list_get_first_link (&service->owners); _dbus_assert (link != NULL); while (link != NULL) { BusOwner *owner; const char *uname; owner = (BusOwner *) link->data; uname = bus_connection_get_name (owner->conn); if (!_dbus_list_append (return_list, (char *)uname)) goto oom; link = _dbus_list_get_next_link (&service->owners, link); } return TRUE; oom: _dbus_list_clear (return_list); BUS_SET_OOM (error); return FALSE; }
BusAppArmorConfinement* bus_apparmor_init_connection_confinement (DBusConnection *connection, DBusError *error) { #ifdef HAVE_APPARMOR BusAppArmorConfinement *confinement; char *label, *mode; int fd; if (!apparmor_enabled) return NULL; _dbus_assert (connection != NULL); if (!dbus_connection_get_socket (connection, &fd)) { dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to get socket file descriptor of connection"); return NULL; } if (aa_getpeercon (fd, &label, &mode) == -1) { if (errno == ENOMEM) BUS_SET_OOM (error); else dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to get AppArmor confinement information of socket peer: %s", _dbus_strerror (errno)); return NULL; } confinement = bus_apparmor_confinement_new (label, mode); if (confinement == NULL) { BUS_SET_OOM (error); free (label); return NULL; } return confinement; #else return NULL; #endif /* HAVE_APPARMOR */ }
static dbus_bool_t bus_driver_send_welcome_message (DBusConnection *connection, DBusMessage *hello_message, BusTransaction *transaction, DBusError *error) { DBusMessage *welcome; const char *name; _DBUS_ASSERT_ERROR_IS_CLEAR (error); name = bus_connection_get_name (connection); _dbus_assert (name != NULL); welcome = dbus_message_new_method_return (hello_message); if (welcome == NULL) { BUS_SET_OOM (error); return FALSE; } if (!dbus_message_append_args (welcome, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) { dbus_message_unref (welcome); BUS_SET_OOM (error); return FALSE; } _dbus_assert (dbus_message_has_signature (welcome, DBUS_TYPE_STRING_AS_STRING)); if (!bus_transaction_send_from_driver (transaction, connection, welcome)) { dbus_message_unref (welcome); BUS_SET_OOM (error); return FALSE; } else { dbus_message_unref (welcome); return TRUE; } }
static dbus_bool_t parse_section_start (BusDesktopFileParser *parser, DBusError *error) { int line_end, eol_len; char *section_name; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (!_dbus_string_find_eol (&parser->data, parser->pos, &line_end, &eol_len)) line_end = parser->len; if (line_end - parser->pos <= 2 || _dbus_string_get_byte (&parser->data, line_end - 1) != ']') { report_error (parser, "Invalid syntax for section header", BUS_DESKTOP_PARSE_ERROR_INVALID_SYNTAX, error); parser_free (parser); return FALSE; } section_name = unescape_string (parser, &parser->data, parser->pos + 1, line_end - 1, error); if (section_name == NULL) { parser_free (parser); return FALSE; } if (!is_valid_section_name (section_name)) { report_error (parser, "Invalid characters in section name", BUS_DESKTOP_PARSE_ERROR_INVALID_CHARS, error); parser_free (parser); dbus_free (section_name); return FALSE; } if (open_section (parser, section_name) == NULL) { dbus_free (section_name); parser_free (parser); BUS_SET_OOM (error); return FALSE; } if (line_end == parser->len) parser->pos = parser->len; else parser->pos = line_end + eol_len; parser->line_num += 1; dbus_free (section_name); return TRUE; }
dbus_bool_t bus_driver_send_service_lost (DBusConnection *connection, const char *service_name, BusTransaction *transaction, DBusError *error) { DBusMessage *message; _DBUS_ASSERT_ERROR_IS_CLEAR (error); message = dbus_message_new_signal (DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "NameLost"); if (message == NULL) { BUS_SET_OOM (error); return FALSE; } if (!dbus_message_set_destination (message, bus_connection_get_name (connection)) || !dbus_message_append_args (message, DBUS_TYPE_STRING, &service_name, DBUS_TYPE_INVALID)) { dbus_message_unref (message); BUS_SET_OOM (error); return FALSE; } if (!bus_transaction_send_from_driver (transaction, connection, message)) { dbus_message_unref (message); BUS_SET_OOM (error); return FALSE; } else { dbus_message_unref (message); return TRUE; } }
/** * Verify that the config mode is compatible with the kernel's AppArmor * support. If AppArmor mediation will be enabled, determine the bus * confinement label. */ dbus_bool_t bus_apparmor_full_init (DBusError *error) { #ifdef HAVE_APPARMOR char *label, *mode; if (apparmor_enabled) { if (apparmor_config_mode == APPARMOR_DISABLED) { apparmor_enabled = FALSE; return TRUE; } if (bus_con == NULL) { if (aa_getcon (&label, &mode) == -1) { dbus_set_error (error, DBUS_ERROR_FAILED, "Error getting AppArmor context of bus: %s", _dbus_strerror (errno)); return FALSE; } bus_con = bus_apparmor_confinement_new (label, mode); if (bus_con == NULL) { BUS_SET_OOM (error); free (label); return FALSE; } } } else { if (apparmor_config_mode == APPARMOR_REQUIRED) { dbus_set_error (error, DBUS_ERROR_FAILED, "AppArmor mediation required but not present"); return FALSE; } else if (apparmor_config_mode == APPARMOR_ENABLED) { return TRUE; } } #endif return TRUE; }
dbus_bool_t bus_config_parser_start_element (BusConfigParser *parser, const char *element_name, const char **attribute_names, const char **attribute_values, DBusError *error) { /* we don't do processing of attribute names, we don't need to */ parser->type = bus_config_parser_element_name_to_type (element_name); switch (parser->type) { case ELEMENT_SERVICEHELPER: case ELEMENT_USER: case ELEMENT_TYPE: /* content about to be handled */ break; case ELEMENT_STANDARD_SYSTEM_SERVICEDIRS: { DBusList *link; DBusList *dirs; dirs = NULL; 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); break; } default: { /* we really don't care about the others... */ _dbus_verbose (" START We dont care about '%s' type '%i'\n", element_name, parser->type); break; } } return TRUE; }
static dbus_bool_t bus_driver_handle_reload_config (DBusConnection *connection, BusTransaction *transaction, DBusMessage *message, DBusError *error) { BusContext *context; DBusMessage *reply; _DBUS_ASSERT_ERROR_IS_CLEAR (error); reply = NULL; context = bus_connection_get_context (connection); if (!bus_context_reload_config (context, error)) goto failed; reply = dbus_message_new_method_return (message); if (reply == NULL) goto oom; if (! bus_transaction_send_from_driver (transaction, connection, reply)) goto oom; dbus_message_unref (reply); return TRUE; oom: BUS_SET_OOM (error); failed: _DBUS_ASSERT_ERROR_IS_SET (error); if (reply) dbus_message_unref (reply); return FALSE; }
static dbus_bool_t bus_driver_handle_list_queued_owners (DBusConnection *connection, BusTransaction *transaction, DBusMessage *message, DBusError *error) { const char *text; DBusList *base_names; DBusList *link; DBusString str; BusRegistry *registry; BusService *service; DBusMessage *reply; DBusMessageIter iter, array_iter; char *dbus_service_name = DBUS_SERVICE_DBUS; _DBUS_ASSERT_ERROR_IS_CLEAR (error); registry = bus_connection_get_registry (connection); base_names = NULL; text = NULL; reply = NULL; if (! dbus_message_get_args (message, error, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID)) goto failed; _dbus_string_init_const (&str, text); service = bus_registry_lookup (registry, &str); if (service == NULL && _dbus_string_equal_c_str (&str, DBUS_SERVICE_DBUS)) { /* ORG_FREEDESKTOP_DBUS owns itself */ if (! _dbus_list_append (&base_names, dbus_service_name)) goto oom; } else if (service == NULL) { dbus_set_error (error, DBUS_ERROR_NAME_HAS_NO_OWNER, "Could not get owners of name '%s': no such name", text); goto failed; } else { if (!bus_service_list_queued_owners (service, &base_names, error)) goto failed; } _dbus_assert (base_names != NULL); reply = dbus_message_new_method_return (message); if (reply == NULL) goto oom; dbus_message_iter_init_append (reply, &iter); if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &array_iter)) goto oom; link = _dbus_list_get_first_link (&base_names); while (link != NULL) { char *uname; _dbus_assert (link->data != NULL); uname = (char *)link->data; if (!dbus_message_iter_append_basic (&array_iter, DBUS_TYPE_STRING, &uname)) goto oom; link = _dbus_list_get_next_link (&base_names, link); } if (! dbus_message_iter_close_container (&iter, &array_iter)) goto oom; if (! bus_transaction_send_from_driver (transaction, connection, reply)) goto oom; dbus_message_unref (reply); return TRUE; oom: BUS_SET_OOM (error); failed: _DBUS_ASSERT_ERROR_IS_SET (error); if (reply) dbus_message_unref (reply); if (base_names) _dbus_list_clear (&base_names); return FALSE; }
static dbus_bool_t bus_driver_handle_get_service_owner (DBusConnection *connection, BusTransaction *transaction, DBusMessage *message, DBusError *error) { const char *text; const char *base_name; DBusString str; BusRegistry *registry; BusService *service; DBusMessage *reply; _DBUS_ASSERT_ERROR_IS_CLEAR (error); registry = bus_connection_get_registry (connection); text = NULL; reply = NULL; if (! dbus_message_get_args (message, error, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID)) goto failed; _dbus_string_init_const (&str, text); service = bus_registry_lookup (registry, &str); if (service == NULL && _dbus_string_equal_c_str (&str, DBUS_SERVICE_DBUS)) { /* ORG_FREEDESKTOP_DBUS owns itself */ base_name = DBUS_SERVICE_DBUS; } else if (service == NULL) { dbus_set_error (error, DBUS_ERROR_NAME_HAS_NO_OWNER, "Could not get owner of name '%s': no such name", text); goto failed; } else { base_name = bus_connection_get_name (bus_service_get_primary_owners_connection (service)); if (base_name == NULL) { /* FIXME - how is this error possible? */ dbus_set_error (error, DBUS_ERROR_FAILED, "Could not determine unique name for '%s'", text); goto failed; } _dbus_assert (*base_name == ':'); } _dbus_assert (base_name != NULL); reply = dbus_message_new_method_return (message); if (reply == NULL) goto oom; if (! dbus_message_append_args (reply, DBUS_TYPE_STRING, &base_name, DBUS_TYPE_INVALID)) goto oom; if (! bus_transaction_send_from_driver (transaction, connection, reply)) goto oom; dbus_message_unref (reply); return TRUE; oom: BUS_SET_OOM (error); failed: _DBUS_ASSERT_ERROR_IS_SET (error); if (reply) dbus_message_unref (reply); return FALSE; }
dbus_bool_t bus_registry_acquire_service (BusRegistry *registry, DBusConnection *connection, const DBusString *service_name, dbus_uint32_t flags, dbus_uint32_t *result, BusTransaction *transaction, DBusError *error) { dbus_bool_t retval; DBusConnection *old_owner_conn; BusClientPolicy *policy; BusService *service; BusActivation *activation; BusSELinuxID *sid; BusOwner *primary_owner; retval = FALSE; if (!_dbus_validate_bus_name (service_name, 0, _dbus_string_get_length (service_name))) { dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Requested bus name \"%s\" is not valid", _dbus_string_get_const_data (service_name)); _dbus_verbose ("Attempt to acquire invalid service name\n"); goto out; } if (_dbus_string_get_byte (service_name, 0) == ':') { /* Not allowed; only base services can start with ':' */ dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Cannot acquire a service starting with ':' such as \"%s\"", _dbus_string_get_const_data (service_name)); _dbus_verbose ("Attempt to acquire invalid base service name \"%s\"", _dbus_string_get_const_data (service_name)); goto out; } if (_dbus_string_equal_c_str (service_name, DBUS_SERVICE_DBUS)) { dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Connection \"%s\" is not allowed to own the service \"%s\"because " "it is reserved for D-Bus' use only", bus_connection_is_active (connection) ? bus_connection_get_name (connection) : "(inactive)", DBUS_SERVICE_DBUS); goto out; } policy = bus_connection_get_policy (connection); _dbus_assert (policy != NULL); /* Note that if sid is #NULL then the bus's own context gets used * in bus_connection_selinux_allows_acquire_service() */ sid = bus_selinux_id_table_lookup (registry->service_sid_table, service_name); if (!bus_selinux_allows_acquire_service (connection, sid, _dbus_string_get_const_data (service_name), error)) { if (dbus_error_is_set (error) && dbus_error_has_name (error, DBUS_ERROR_NO_MEMORY)) { goto out; } dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, "Connection \"%s\" is not allowed to own the service \"%s\" due " "to SELinux policy", bus_connection_is_active (connection) ? bus_connection_get_name (connection) : "(inactive)", _dbus_string_get_const_data (service_name)); goto out; } if (!bus_client_policy_check_can_own (policy, service_name)) { dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, "Connection \"%s\" is not allowed to own the service \"%s\" due " "to security policies in the configuration file", bus_connection_is_active (connection) ? bus_connection_get_name (connection) : "(inactive)", _dbus_string_get_const_data (service_name)); goto out; } if (bus_connection_get_n_services_owned (connection) >= bus_context_get_max_services_per_connection (registry->context)) { dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, "Connection \"%s\" is not allowed to own more services " "(increase limits in configuration file if required)", bus_connection_is_active (connection) ? bus_connection_get_name (connection) : "(inactive)"); goto out; } service = bus_registry_lookup (registry, service_name); if (service != NULL) { primary_owner = bus_service_get_primary_owner (service); if (primary_owner != NULL) old_owner_conn = primary_owner->conn; else old_owner_conn = NULL; } else old_owner_conn = NULL; if (service == NULL) { service = bus_registry_ensure (registry, service_name, connection, flags, transaction, error); if (service == NULL) goto out; } primary_owner = bus_service_get_primary_owner (service); if (primary_owner == NULL) goto out; if (old_owner_conn == NULL) { _dbus_assert (primary_owner->conn == connection); *result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER; } else if (old_owner_conn == connection) { bus_owner_set_flags (primary_owner, flags); *result = DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER; } else if (((flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) && !(bus_service_get_allow_replacement (service))) || ((flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) && !(flags & DBUS_NAME_FLAG_REPLACE_EXISTING))) { DBusList *link; BusOwner *temp_owner; /* Since we can't be queued if we are already in the queue remove us */ link = _bus_service_find_owner_link (service, connection); if (link != NULL) { _dbus_list_unlink (&service->owners, link); temp_owner = (BusOwner *)link->data; bus_owner_unref (temp_owner); _dbus_list_free_link (link); } *result = DBUS_REQUEST_NAME_REPLY_EXISTS; } else if (!(flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) && (!(flags & DBUS_NAME_FLAG_REPLACE_EXISTING) || !(bus_service_get_allow_replacement (service)))) { /* Queue the connection */ if (!bus_service_add_owner (service, connection, flags, transaction, error)) goto out; *result = DBUS_REQUEST_NAME_REPLY_IN_QUEUE; } else { /* Replace the current owner */ /* We enqueue the new owner and remove the first one because * that will cause NameAcquired and NameLost messages to * be sent. */ if (!bus_service_add_owner (service, connection, flags, transaction, error)) goto out; if (primary_owner->do_not_queue) { if (!bus_service_remove_owner (service, old_owner_conn, transaction, error)) goto out; } else { if (!bus_service_swap_owner (service, old_owner_conn, transaction, error)) goto out; } _dbus_assert (connection == bus_service_get_primary_owner (service)->conn); *result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER; } activation = bus_context_get_activation (registry->context); retval = bus_activation_send_pending_auto_activation_messages (activation, service, transaction); if (!retval) BUS_SET_OOM (error); out: return retval; }
static dbus_bool_t get_correct_parser (BusConfigParser **parser, DBusError *error) { DBusString config_file; dbus_bool_t retval; #ifdef ACTIVATION_LAUNCHER_TEST const char *test_config_file; #endif retval = FALSE; #ifdef ACTIVATION_LAUNCHER_TEST test_config_file = NULL; /* there is no _way_ we should be setuid if this define is set. * but we should be doubly paranoid and check... */ if (getuid() != geteuid()) _dbus_assert_not_reached ("dbus-daemon-launch-helper-test binary is setuid!"); /* this is not a security hole. The environment variable is only passed in the * dbus-daemon-lauch-helper-test NON-SETUID launcher */ test_config_file = _dbus_getenv ("TEST_LAUNCH_HELPER_CONFIG"); if (test_config_file == NULL) { dbus_set_error (error, DBUS_ERROR_SPAWN_SETUP_FAILED, "the TEST_LAUNCH_HELPER_CONFIG env variable is not set"); goto out; } #endif /* we _only_ use the predefined system config file */ if (!_dbus_string_init (&config_file)) { BUS_SET_OOM (error); goto out; } #ifndef ACTIVATION_LAUNCHER_TEST if (!_dbus_string_append (&config_file, DBUS_SYSTEM_CONFIG_FILE)) { BUS_SET_OOM (error); goto out_free_config; } #else if (!_dbus_string_append (&config_file, test_config_file)) { BUS_SET_OOM (error); goto out_free_config; } #endif /* where are we pointing.... */ _dbus_verbose ("dbus-daemon-activation-helper: using config file: %s\n", _dbus_string_get_const_data (&config_file)); /* get the dbus user */ *parser = bus_config_load (&config_file, TRUE, NULL, error); if (*parser == NULL) { goto out_free_config; } /* woot */ retval = TRUE; out_free_config: _dbus_string_free (&config_file); out: return retval; }
static dbus_bool_t bus_driver_handle_list_services (DBusConnection *connection, BusTransaction *transaction, DBusMessage *message, DBusError *error) { DBusMessage *reply; int len; char **services; BusRegistry *registry; int i; DBusMessageIter iter; DBusMessageIter sub; _DBUS_ASSERT_ERROR_IS_CLEAR (error); registry = bus_connection_get_registry (connection); reply = dbus_message_new_method_return (message); if (reply == NULL) { BUS_SET_OOM (error); return FALSE; } if (!bus_registry_list_services (registry, &services, &len)) { dbus_message_unref (reply); BUS_SET_OOM (error); return FALSE; } dbus_message_iter_init_append (reply, &iter); if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &sub)) { dbus_free_string_array (services); dbus_message_unref (reply); BUS_SET_OOM (error); return FALSE; } { /* Include the bus driver in the list */ const char *v_STRING = DBUS_SERVICE_DBUS; if (!dbus_message_iter_append_basic (&sub, DBUS_TYPE_STRING, &v_STRING)) { dbus_free_string_array (services); dbus_message_unref (reply); BUS_SET_OOM (error); return FALSE; } } i = 0; while (i < len) { if (!dbus_message_iter_append_basic (&sub, DBUS_TYPE_STRING, &services[i])) { dbus_free_string_array (services); dbus_message_unref (reply); BUS_SET_OOM (error); return FALSE; } ++i; } if (!dbus_message_iter_close_container (&iter, &sub)) { dbus_free_string_array (services); dbus_message_unref (reply); BUS_SET_OOM (error); return FALSE; } dbus_free_string_array (services); if (!bus_transaction_send_from_driver (transaction, connection, reply)) { dbus_message_unref (reply); BUS_SET_OOM (error); return FALSE; } else { dbus_message_unref (reply); return TRUE; } }
static BusDesktopFile * desktop_file_for_name (BusConfigParser *parser, const char *name, DBusError *error) { BusDesktopFile *desktop_file; DBusList **service_dirs; DBusList *link; DBusError tmp_error; DBusString full_path; DBusString filename; const char *dir; _DBUS_ASSERT_ERROR_IS_CLEAR (error); desktop_file = NULL; if (!_dbus_string_init (&filename)) { BUS_SET_OOM (error); goto out_all; } if (!_dbus_string_init (&full_path)) { BUS_SET_OOM (error); goto out_filename; } if (!_dbus_string_append (&filename, name) || !_dbus_string_append (&filename, ".service")) { BUS_SET_OOM (error); goto out; } service_dirs = bus_config_parser_get_service_dirs (parser); for (link = _dbus_list_get_first_link (service_dirs); link != NULL; link = _dbus_list_get_next_link (service_dirs, link)) { dir = link->data; _dbus_verbose ("Looking at '%s'\n", dir); dbus_error_init (&tmp_error); /* clear the path from last time */ _dbus_string_set_length (&full_path, 0); /* build the full path */ if (!_dbus_string_append (&full_path, dir) || !_dbus_concat_dir_and_file (&full_path, &filename)) { BUS_SET_OOM (error); goto out; } _dbus_verbose ("Trying to load file '%s'\n", _dbus_string_get_data (&full_path)); desktop_file = bus_desktop_file_load (&full_path, &tmp_error); if (desktop_file == NULL) { _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); _dbus_verbose ("Could not load %s: %s: %s\n", _dbus_string_get_const_data (&full_path), tmp_error.name, tmp_error.message); /* we may have failed if the file is not found; this is not fatal */ if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY)) { dbus_move_error (&tmp_error, error); /* we only bail out on OOM */ goto out; } dbus_error_free (&tmp_error); } /* did we find the desktop file we want? */ if (desktop_file != NULL) break; } /* Didn't find desktop file; set error */ if (desktop_file == NULL) { dbus_set_error (error, DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND, "The name %s was not provided by any .service files", name); } out: _dbus_string_free (&full_path); out_filename: _dbus_string_free (&filename); out_all: return desktop_file; }
static dbus_bool_t bus_driver_handle_get_connection_unix_process_id (DBusConnection *connection, BusTransaction *transaction, DBusMessage *message, DBusError *error) { const char *service; DBusString str; BusRegistry *registry; BusService *serv; DBusConnection *conn; DBusMessage *reply; unsigned long pid; dbus_uint32_t pid32; _DBUS_ASSERT_ERROR_IS_CLEAR (error); registry = bus_connection_get_registry (connection); service = NULL; reply = NULL; if (! dbus_message_get_args (message, error, DBUS_TYPE_STRING, &service, DBUS_TYPE_INVALID)) goto failed; _dbus_verbose ("asked for PID of connection %s\n", service); _dbus_string_init_const (&str, service); serv = bus_registry_lookup (registry, &str); if (serv == NULL) { dbus_set_error (error, DBUS_ERROR_NAME_HAS_NO_OWNER, "Could not get PID of name '%s': no such name", service); goto failed; } conn = bus_service_get_primary_owners_connection (serv); reply = dbus_message_new_method_return (message); if (reply == NULL) goto oom; if (!dbus_connection_get_unix_process_id (conn, &pid)) { dbus_set_error (error, DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN, "Could not determine PID for '%s'", service); goto failed; } pid32 = pid; if (! dbus_message_append_args (reply, DBUS_TYPE_UINT32, &pid32, DBUS_TYPE_INVALID)) goto oom; if (! bus_transaction_send_from_driver (transaction, connection, reply)) goto oom; dbus_message_unref (reply); return TRUE; oom: BUS_SET_OOM (error); failed: _DBUS_ASSERT_ERROR_IS_SET (error); if (reply) dbus_message_unref (reply); return FALSE; }
static dbus_bool_t bus_driver_handle_hello (DBusConnection *connection, BusTransaction *transaction, DBusMessage *message, DBusError *error) { DBusString unique_name; BusService *service; dbus_bool_t retval; BusRegistry *registry; BusConnections *connections; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (bus_connection_is_active (connection)) { /* We already handled an Hello message for this connection. */ dbus_set_error (error, DBUS_ERROR_FAILED, "Already handled an Hello message"); return FALSE; } /* Note that when these limits are exceeded we don't disconnect the * connection; we just sort of leave it hanging there until it times * out or disconnects itself or is dropped due to the max number of * incomplete connections. It's even OK if the connection wants to * retry the hello message, we support that. */ connections = bus_connection_get_connections (connection); if (!bus_connections_check_limits (connections, connection, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); return FALSE; } if (!_dbus_string_init (&unique_name)) { BUS_SET_OOM (error); return FALSE; } retval = FALSE; registry = bus_connection_get_registry (connection); if (!create_unique_client_name (registry, &unique_name)) { BUS_SET_OOM (error); goto out_0; } if (!bus_connection_complete (connection, &unique_name, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); goto out_0; } if (!dbus_message_set_sender (message, bus_connection_get_name (connection))) { BUS_SET_OOM (error); goto out_0; } if (!bus_driver_send_welcome_message (connection, message, transaction, error)) goto out_0; /* Create the service */ service = bus_registry_ensure (registry, &unique_name, connection, 0, transaction, error); if (service == NULL) goto out_0; _dbus_assert (bus_connection_is_active (connection)); retval = TRUE; out_0: _dbus_string_free (&unique_name); return retval; }
static dbus_bool_t bus_driver_handle_introspect (DBusConnection *connection, BusTransaction *transaction, DBusMessage *message, DBusError *error) { DBusString xml; DBusMessage *reply; const char *v_STRING; int i; _dbus_verbose ("Introspect() on bus driver\n"); _DBUS_ASSERT_ERROR_IS_CLEAR (error); reply = NULL; if (! dbus_message_get_args (message, error, DBUS_TYPE_INVALID)) { _DBUS_ASSERT_ERROR_IS_SET (error); return FALSE; } if (!_dbus_string_init (&xml)) { BUS_SET_OOM (error); return FALSE; } if (!_dbus_string_append (&xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE)) goto oom; if (!_dbus_string_append (&xml, "<node>\n")) goto oom; if (!_dbus_string_append_printf (&xml, " <interface name=\"%s\">\n", DBUS_INTERFACE_INTROSPECTABLE)) goto oom; if (!_dbus_string_append (&xml, " <method name=\"Introspect\">\n")) goto oom; if (!_dbus_string_append_printf (&xml, " <arg name=\"data\" direction=\"out\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING)) goto oom; if (!_dbus_string_append (&xml, " </method>\n")) goto oom; if (!_dbus_string_append (&xml, " </interface>\n")) goto oom; if (!_dbus_string_append_printf (&xml, " <interface name=\"%s\">\n", DBUS_INTERFACE_DBUS)) goto oom; i = 0; while (i < _DBUS_N_ELEMENTS (message_handlers)) { if (!_dbus_string_append_printf (&xml, " <method name=\"%s\">\n", message_handlers[i].name)) goto oom; if (!write_args_for_direction (&xml, message_handlers[i].in_args, TRUE)) goto oom; if (!write_args_for_direction (&xml, message_handlers[i].out_args, FALSE)) goto oom; if (!_dbus_string_append (&xml, " </method>\n")) goto oom; ++i; } if (!_dbus_string_append_printf (&xml, " <signal name=\"NameOwnerChanged\">\n")) goto oom; if (!_dbus_string_append_printf (&xml, " <arg type=\"s\"/>\n")) goto oom; if (!_dbus_string_append_printf (&xml, " <arg type=\"s\"/>\n")) goto oom; if (!_dbus_string_append_printf (&xml, " <arg type=\"s\"/>\n")) goto oom; if (!_dbus_string_append_printf (&xml, " </signal>\n")) goto oom; if (!_dbus_string_append_printf (&xml, " <signal name=\"NameLost\">\n")) goto oom; if (!_dbus_string_append_printf (&xml, " <arg type=\"s\"/>\n")) goto oom; if (!_dbus_string_append_printf (&xml, " </signal>\n")) goto oom; if (!_dbus_string_append_printf (&xml, " <signal name=\"NameAcquired\">\n")) goto oom; if (!_dbus_string_append_printf (&xml, " <arg type=\"s\"/>\n")) goto oom; if (!_dbus_string_append_printf (&xml, " </signal>\n")) goto oom; if (!_dbus_string_append (&xml, " </interface>\n")) goto oom; if (!_dbus_string_append (&xml, "</node>\n")) goto oom; reply = dbus_message_new_method_return (message); if (reply == NULL) goto oom; v_STRING = _dbus_string_get_const_data (&xml); if (! dbus_message_append_args (reply, DBUS_TYPE_STRING, &v_STRING, DBUS_TYPE_INVALID)) goto oom; if (! bus_transaction_send_from_driver (transaction, connection, reply)) goto oom; dbus_message_unref (reply); _dbus_string_free (&xml); return TRUE; oom: BUS_SET_OOM (error); if (reply) dbus_message_unref (reply); _dbus_string_free (&xml); return FALSE; }
dbus_bool_t bus_service_swap_owner (BusService *service, DBusConnection *connection, BusTransaction *transaction, DBusError *error) { DBusList *swap_link; BusOwner *primary_owner; _DBUS_ASSERT_ERROR_IS_CLEAR (error); /* We send out notifications before we do any work we * might have to undo if the notification-sending failed */ /* Send service lost message */ primary_owner = bus_service_get_primary_owner (service); if (primary_owner == NULL || primary_owner->conn != connection) _dbus_assert_not_reached ("Tried to swap a non primary owner"); if (!bus_driver_send_service_lost (connection, service->name, transaction, error)) return FALSE; if (service->owners == NULL) { _dbus_assert_not_reached ("Tried to swap owner of a service that has no owners"); } else if (_dbus_list_length_is_one (&service->owners)) { _dbus_assert_not_reached ("Tried to swap owner of a service that has no other owners in the queue"); } else { DBusList *link; BusOwner *new_owner; DBusConnection *new_owner_conn; link = _dbus_list_get_first_link (&service->owners); _dbus_assert (link != NULL); link = _dbus_list_get_next_link (&service->owners, link); _dbus_assert (link != NULL); new_owner = (BusOwner *)link->data; new_owner_conn = new_owner->conn; if (!bus_driver_send_service_owner_changed (service->name, bus_connection_get_name (connection), bus_connection_get_name (new_owner_conn), transaction, error)) return FALSE; /* This will be our new owner */ if (!bus_driver_send_service_acquired (new_owner_conn, service->name, transaction, error)) return FALSE; } if (!add_restore_ownership_to_transaction (transaction, service, primary_owner)) { BUS_SET_OOM (error); return FALSE; } /* unlink the primary and make it the second link */ swap_link = _dbus_list_get_first_link (&service->owners); _dbus_list_unlink (&service->owners, swap_link); _dbus_list_insert_after_link (&service->owners, _dbus_list_get_first_link (&service->owners), swap_link); return TRUE; }
static dbus_bool_t bus_driver_handle_service_exists (DBusConnection *connection, BusTransaction *transaction, DBusMessage *message, DBusError *error) { DBusMessage *reply; DBusString service_name; BusService *service; dbus_bool_t service_exists; const char *name; dbus_bool_t retval; BusRegistry *registry; _DBUS_ASSERT_ERROR_IS_CLEAR (error); registry = bus_connection_get_registry (connection); if (!dbus_message_get_args (message, error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) return FALSE; retval = FALSE; if (strcmp (name, DBUS_SERVICE_DBUS) == 0) { service_exists = TRUE; } else { _dbus_string_init_const (&service_name, name); service = bus_registry_lookup (registry, &service_name); service_exists = service != NULL; } reply = dbus_message_new_method_return (message); if (reply == NULL) { BUS_SET_OOM (error); goto out; } if (!dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &service_exists, 0)) { BUS_SET_OOM (error); goto out; } if (!bus_transaction_send_from_driver (transaction, connection, reply)) { BUS_SET_OOM (error); goto out; } retval = TRUE; out: if (reply) dbus_message_unref (reply); return retval; }
/* this function is self-cancelling if you cancel the transaction */ dbus_bool_t bus_service_remove_owner (BusService *service, DBusConnection *connection, BusTransaction *transaction, DBusError *error) { BusOwner *primary_owner; _DBUS_ASSERT_ERROR_IS_CLEAR (error); /* We send out notifications before we do any work we * might have to undo if the notification-sending failed */ /* Send service lost message */ primary_owner = bus_service_get_primary_owner (service); if (primary_owner != NULL && primary_owner->conn == connection) { if (!bus_driver_send_service_lost (connection, service->name, transaction, error)) return FALSE; } else { /* if we are not the primary owner then just remove us from the queue */ DBusList *link; BusOwner *temp_owner; link = _bus_service_find_owner_link (service, connection); _dbus_list_unlink (&service->owners, link); temp_owner = (BusOwner *)link->data; bus_owner_unref (temp_owner); _dbus_list_free_link (link); return TRUE; } if (service->owners == NULL) { _dbus_assert_not_reached ("Tried to remove owner of a service that has no owners"); } else if (_dbus_list_length_is_one (&service->owners)) { if (!bus_driver_send_service_owner_changed (service->name, bus_connection_get_name (connection), NULL, transaction, error)) return FALSE; } else { DBusList *link; BusOwner *new_owner; DBusConnection *new_owner_conn; link = _dbus_list_get_first_link (&service->owners); _dbus_assert (link != NULL); link = _dbus_list_get_next_link (&service->owners, link); _dbus_assert (link != NULL); new_owner = (BusOwner *)link->data; new_owner_conn = new_owner->conn; if (!bus_driver_send_service_owner_changed (service->name, bus_connection_get_name (connection), bus_connection_get_name (new_owner_conn), transaction, error)) return FALSE; /* This will be our new owner */ if (!bus_driver_send_service_acquired (new_owner_conn, service->name, transaction, error)) return FALSE; } if (!add_restore_ownership_to_transaction (transaction, service, primary_owner)) { BUS_SET_OOM (error); return FALSE; } bus_service_unlink_owner (service, primary_owner); if (service->owners == NULL) bus_service_unlink (service); return TRUE; }
BusDesktopFile* bus_desktop_file_load (DBusString *filename, DBusError *error) { DBusString str; BusDesktopFileParser parser; DBusStat sb; _DBUS_ASSERT_ERROR_IS_CLEAR (error); /* Clearly there's a race here, but it's just to make it unlikely * that we do something silly, we still handle doing it below. */ if (!_dbus_stat (filename, &sb, error)) return NULL; if (sb.size > _DBUS_ONE_KILOBYTE * 128) { dbus_set_error (error, DBUS_ERROR_FAILED, "Desktop file size (%ld bytes) is too large", (long) sb.size); return NULL; } if (!_dbus_string_init (&str)) return NULL; if (!_dbus_file_get_contents (&str, filename, error)) { _dbus_string_free (&str); return NULL; } if (!_dbus_string_validate_utf8 (&str, 0, _dbus_string_get_length (&str))) { _dbus_string_free (&str); dbus_set_error (error, DBUS_ERROR_FAILED, "invalid UTF-8"); return NULL; } parser.desktop_file = dbus_new0 (BusDesktopFile, 1); if (parser.desktop_file == NULL) { _dbus_string_free (&str); BUS_SET_OOM (error); return NULL; } parser.data = str; parser.line_num = 1; parser.pos = 0; parser.len = _dbus_string_get_length (&parser.data); parser.current_section = -1; while (parser.pos < parser.len) { if (_dbus_string_get_byte (&parser.data, parser.pos) == '[') { if (!parse_section_start (&parser, error)) { return NULL; } } else if (is_blank_line (&parser) || _dbus_string_get_byte (&parser.data, parser.pos) == '#') parse_comment_or_blank (&parser); else { if (!parse_key_value (&parser, error)) { return NULL; } } } _dbus_string_free (&parser.data); return parser.desktop_file; }
BusService* bus_registry_ensure (BusRegistry *registry, const DBusString *service_name, DBusConnection *owner_connection_if_created, dbus_uint32_t flags, BusTransaction *transaction, DBusError *error) { BusService *service; _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_assert (owner_connection_if_created != NULL); _dbus_assert (transaction != NULL); service = _dbus_hash_table_lookup_string (registry->service_hash, _dbus_string_get_const_data (service_name)); if (service != NULL) return service; service = _dbus_mem_pool_alloc (registry->service_pool); if (service == NULL) { BUS_SET_OOM (error); return NULL; } service->registry = registry; service->refcount = 1; _dbus_verbose ("copying string %p '%s' to service->name\n", service_name, _dbus_string_get_const_data (service_name)); if (!_dbus_string_copy_data (service_name, &service->name)) { _dbus_mem_pool_dealloc (registry->service_pool, service); BUS_SET_OOM (error); return NULL; } _dbus_verbose ("copied string %p '%s' to '%s'\n", service_name, _dbus_string_get_const_data (service_name), service->name); if (!bus_driver_send_service_owner_changed (service->name, NULL, bus_connection_get_name (owner_connection_if_created), transaction, error)) { bus_service_unref (service); return NULL; } if (!bus_activation_service_created (bus_context_get_activation (registry->context), service->name, transaction, error)) { bus_service_unref (service); return NULL; } if (!bus_service_add_owner (service, owner_connection_if_created, flags, transaction, error)) { bus_service_unref (service); return NULL; } if (!_dbus_hash_table_insert_string (registry->service_hash, service->name, service)) { /* The add_owner gets reverted on transaction cancel */ BUS_SET_OOM (error); return NULL; } return service; }
static dbus_bool_t bus_driver_handle_add_match (DBusConnection *connection, BusTransaction *transaction, DBusMessage *message, DBusError *error) { BusMatchRule *rule; const char *text; DBusString str; BusMatchmaker *matchmaker; _DBUS_ASSERT_ERROR_IS_CLEAR (error); text = NULL; rule = NULL; if (bus_connection_get_n_match_rules (connection) >= bus_context_get_max_match_rules_per_connection (bus_transaction_get_context (transaction))) { dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, "Connection \"%s\" is not allowed to add more match rules " "(increase limits in configuration file if required)", bus_connection_is_active (connection) ? bus_connection_get_name (connection) : "(inactive)"); goto failed; } if (!dbus_message_get_args (message, error, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID)) { _dbus_verbose ("No memory to get arguments to AddMatch\n"); goto failed; } _dbus_string_init_const (&str, text); rule = bus_match_rule_parse (connection, &str, error); if (rule == NULL) goto failed; matchmaker = bus_connection_get_matchmaker (connection); if (!bus_matchmaker_add_rule (matchmaker, rule)) { BUS_SET_OOM (error); goto failed; } if (!send_ack_reply (connection, transaction, message, error)) { bus_matchmaker_remove_rule (matchmaker, rule); goto failed; } bus_match_rule_unref (rule); return TRUE; failed: _DBUS_ASSERT_ERROR_IS_SET (error); if (rule) bus_match_rule_unref (rule); return FALSE; }
/* this function is self-cancelling if you cancel the transaction */ dbus_bool_t bus_service_add_owner (BusService *service, DBusConnection *connection, dbus_uint32_t flags, BusTransaction *transaction, DBusError *error) { BusOwner *bus_owner; DBusList *bus_owner_link; _DBUS_ASSERT_ERROR_IS_CLEAR (error); /* Send service acquired message first, OOM will result * in cancelling the transaction */ if (service->owners == NULL) { if (!bus_driver_send_service_acquired (connection, service->name, transaction, error)) return FALSE; } bus_owner_link = _bus_service_find_owner_link (service, connection); if (bus_owner_link == NULL) { bus_owner = bus_owner_new (service, connection, flags); if (bus_owner == NULL) { BUS_SET_OOM (error); return FALSE; } bus_owner_set_flags (bus_owner, flags); if (!(flags & DBUS_NAME_FLAG_REPLACE_EXISTING) || service->owners == NULL) { if (!_dbus_list_append (&service->owners, bus_owner)) { bus_owner_unref (bus_owner); BUS_SET_OOM (error); return FALSE; } } else { if (!_dbus_list_insert_after (&service->owners, _dbus_list_get_first_link (&service->owners), bus_owner)) { bus_owner_unref (bus_owner); BUS_SET_OOM (error); return FALSE; } } } else { /* Update the link since we are already in the queue * No need for operations that can produce OOM */ bus_owner = (BusOwner *) bus_owner_link->data; if (flags & DBUS_NAME_FLAG_REPLACE_EXISTING) { DBusList *link; _dbus_list_unlink (&service->owners, bus_owner_link); link = _dbus_list_get_first_link (&service->owners); _dbus_assert (link != NULL); _dbus_list_insert_after_link (&service->owners, link, bus_owner_link); } bus_owner_set_flags (bus_owner, flags); return TRUE; } if (!add_cancel_ownership_to_transaction (transaction, service, bus_owner)) { bus_service_unlink_owner (service, bus_owner); BUS_SET_OOM (error); return FALSE; } return TRUE; }
static dbus_bool_t bus_driver_handle_get_connection_selinux_security_context (DBusConnection *connection, BusTransaction *transaction, DBusMessage *message, DBusError *error) { const char *service; DBusString str; BusRegistry *registry; BusService *serv; DBusConnection *conn; DBusMessage *reply; BusSELinuxID *context; _DBUS_ASSERT_ERROR_IS_CLEAR (error); registry = bus_connection_get_registry (connection); service = NULL; reply = NULL; if (! dbus_message_get_args (message, error, DBUS_TYPE_STRING, &service, DBUS_TYPE_INVALID)) goto failed; _dbus_verbose ("asked for security context of connection %s\n", service); _dbus_string_init_const (&str, service); serv = bus_registry_lookup (registry, &str); if (serv == NULL) { dbus_set_error (error, DBUS_ERROR_NAME_HAS_NO_OWNER, "Could not get security context of name '%s': no such name", service); goto failed; } conn = bus_service_get_primary_owners_connection (serv); reply = dbus_message_new_method_return (message); if (reply == NULL) goto oom; context = bus_connection_get_selinux_id (conn); if (!context) { dbus_set_error (error, DBUS_ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN, "Could not determine security context for '%s'", service); goto failed; } if (! bus_selinux_append_context (reply, context, error)) goto failed; if (! bus_transaction_send_from_driver (transaction, connection, reply)) goto oom; dbus_message_unref (reply); return TRUE; oom: BUS_SET_OOM (error); failed: _DBUS_ASSERT_ERROR_IS_SET (error); if (reply) dbus_message_unref (reply); return FALSE; }