2003-01-06 01:08:14 +00:00
|
|
|
/* -*- mode: C; c-file-style: "gnu" -*- */
|
|
|
|
|
/* services.c Service management
|
|
|
|
|
*
|
|
|
|
|
* Copyright (C) 2003 Red Hat, Inc.
|
2003-01-27 11:20:55 +00:00
|
|
|
* Copyright (C) 2003 CodeFactory AB
|
2003-01-06 01:08:14 +00:00
|
|
|
*
|
2004-08-10 03:07:01 +00:00
|
|
|
* Licensed under the Academic Free License version 2.1
|
2003-01-06 01:08:14 +00:00
|
|
|
*
|
|
|
|
|
* 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
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
#include <dbus/dbus-hash.h>
|
|
|
|
|
#include <dbus/dbus-list.h>
|
|
|
|
|
#include <dbus/dbus-mempool.h>
|
2005-01-21 03:44:10 +00:00
|
|
|
#include <dbus/dbus-marshal-validate.h>
|
2003-01-06 01:08:14 +00:00
|
|
|
|
2003-03-13 00:56:43 +00:00
|
|
|
#include "driver.h"
|
|
|
|
|
#include "services.h"
|
|
|
|
|
#include "connection.h"
|
|
|
|
|
#include "utils.h"
|
2003-03-16 22:25:18 +00:00
|
|
|
#include "activation.h"
|
2003-04-25 23:50:34 +00:00
|
|
|
#include "policy.h"
|
2004-07-30 05:59:34 +00:00
|
|
|
#include "bus.h"
|
|
|
|
|
#include "selinux.h"
|
2003-03-13 00:56:43 +00:00
|
|
|
|
2003-01-06 01:08:14 +00:00
|
|
|
struct BusService
|
|
|
|
|
{
|
2003-04-11 00:03:06 +00:00
|
|
|
int refcount;
|
|
|
|
|
|
2003-03-13 03:52:58 +00:00
|
|
|
BusRegistry *registry;
|
2003-01-06 01:08:14 +00:00
|
|
|
char *name;
|
|
|
|
|
DBusList *owners;
|
2003-03-13 00:56:43 +00:00
|
|
|
|
|
|
|
|
unsigned int prohibit_replacement : 1;
|
2003-01-06 01:08:14 +00:00
|
|
|
};
|
|
|
|
|
|
2003-03-13 03:52:58 +00:00
|
|
|
struct BusRegistry
|
|
|
|
|
{
|
|
|
|
|
int refcount;
|
2003-03-16 22:25:18 +00:00
|
|
|
|
|
|
|
|
BusContext *context;
|
2003-03-13 03:52:58 +00:00
|
|
|
|
|
|
|
|
DBusHashTable *service_hash;
|
|
|
|
|
DBusMemPool *service_pool;
|
2004-07-30 05:59:34 +00:00
|
|
|
|
|
|
|
|
DBusHashTable *service_sid_table;
|
2003-03-13 03:52:58 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
BusRegistry*
|
2003-03-16 22:25:18 +00:00
|
|
|
bus_registry_new (BusContext *context)
|
2003-03-13 03:52:58 +00:00
|
|
|
{
|
|
|
|
|
BusRegistry *registry;
|
|
|
|
|
|
|
|
|
|
registry = dbus_new0 (BusRegistry, 1);
|
|
|
|
|
if (registry == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
registry->refcount = 1;
|
2003-03-16 22:25:18 +00:00
|
|
|
registry->context = context;
|
|
|
|
|
|
2003-03-13 03:52:58 +00:00
|
|
|
registry->service_hash = _dbus_hash_table_new (DBUS_HASH_STRING,
|
|
|
|
|
NULL, NULL);
|
|
|
|
|
if (registry->service_hash == NULL)
|
|
|
|
|
goto failed;
|
|
|
|
|
|
|
|
|
|
registry->service_pool = _dbus_mem_pool_new (sizeof (BusService),
|
|
|
|
|
TRUE);
|
|
|
|
|
if (registry->service_pool == NULL)
|
|
|
|
|
goto failed;
|
|
|
|
|
|
2004-07-30 05:59:34 +00:00
|
|
|
registry->service_sid_table = NULL;
|
|
|
|
|
|
2003-03-13 03:52:58 +00:00
|
|
|
return registry;
|
|
|
|
|
|
|
|
|
|
failed:
|
|
|
|
|
bus_registry_unref (registry);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2003-11-27 01:25:50 +00:00
|
|
|
BusRegistry *
|
2003-03-13 03:52:58 +00:00
|
|
|
bus_registry_ref (BusRegistry *registry)
|
|
|
|
|
{
|
|
|
|
|
_dbus_assert (registry->refcount > 0);
|
|
|
|
|
registry->refcount += 1;
|
2003-11-27 01:25:50 +00:00
|
|
|
|
|
|
|
|
return registry;
|
2003-03-13 03:52:58 +00:00
|
|
|
}
|
2003-01-06 01:08:14 +00:00
|
|
|
|
2003-03-13 03:52:58 +00:00
|
|
|
void
|
|
|
|
|
bus_registry_unref (BusRegistry *registry)
|
2003-01-06 01:08:14 +00:00
|
|
|
{
|
2003-03-13 03:52:58 +00:00
|
|
|
_dbus_assert (registry->refcount > 0);
|
|
|
|
|
registry->refcount -= 1;
|
|
|
|
|
|
|
|
|
|
if (registry->refcount == 0)
|
2003-01-06 01:08:14 +00:00
|
|
|
{
|
2003-03-13 03:52:58 +00:00
|
|
|
if (registry->service_hash)
|
|
|
|
|
_dbus_hash_table_unref (registry->service_hash);
|
|
|
|
|
if (registry->service_pool)
|
|
|
|
|
_dbus_mem_pool_free (registry->service_pool);
|
2004-07-30 05:59:34 +00:00
|
|
|
if (registry->service_sid_table)
|
|
|
|
|
_dbus_hash_table_unref (registry->service_sid_table);
|
|
|
|
|
|
2003-03-13 03:52:58 +00:00
|
|
|
dbus_free (registry);
|
2003-01-06 01:08:14 +00:00
|
|
|
}
|
2003-03-13 00:56:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BusService*
|
2003-03-13 03:52:58 +00:00
|
|
|
bus_registry_lookup (BusRegistry *registry,
|
|
|
|
|
const DBusString *service_name)
|
2003-03-13 00:56:43 +00:00
|
|
|
{
|
|
|
|
|
BusService *service;
|
2003-01-06 01:08:14 +00:00
|
|
|
|
2003-03-13 03:52:58 +00:00
|
|
|
service = _dbus_hash_table_lookup_string (registry->service_hash,
|
2003-03-31 20:56:29 +00:00
|
|
|
_dbus_string_get_const_data (service_name));
|
2003-01-06 01:08:14 +00:00
|
|
|
|
2003-03-13 00:56:43 +00:00
|
|
|
return service;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BusService*
|
2003-03-13 03:52:58 +00:00
|
|
|
bus_registry_ensure (BusRegistry *registry,
|
|
|
|
|
const DBusString *service_name,
|
|
|
|
|
DBusConnection *owner_if_created,
|
|
|
|
|
BusTransaction *transaction,
|
|
|
|
|
DBusError *error)
|
2003-03-13 00:56:43 +00:00
|
|
|
{
|
|
|
|
|
BusService *service;
|
|
|
|
|
|
2003-03-26 03:58:11 +00:00
|
|
|
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
|
|
|
|
|
|
2003-03-13 00:56:43 +00:00
|
|
|
_dbus_assert (owner_if_created != NULL);
|
|
|
|
|
_dbus_assert (transaction != NULL);
|
|
|
|
|
|
2003-03-13 03:52:58 +00:00
|
|
|
service = _dbus_hash_table_lookup_string (registry->service_hash,
|
2003-03-31 20:56:29 +00:00
|
|
|
_dbus_string_get_const_data (service_name));
|
2003-03-13 00:56:43 +00:00
|
|
|
if (service != NULL)
|
|
|
|
|
return service;
|
|
|
|
|
|
2003-03-13 03:52:58 +00:00
|
|
|
service = _dbus_mem_pool_alloc (registry->service_pool);
|
2003-01-06 01:08:14 +00:00
|
|
|
if (service == NULL)
|
2003-03-13 00:56:43 +00:00
|
|
|
{
|
|
|
|
|
BUS_SET_OOM (error);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2003-01-06 01:08:14 +00:00
|
|
|
|
2003-03-13 03:52:58 +00:00
|
|
|
service->registry = registry;
|
2003-04-11 00:03:06 +00:00
|
|
|
service->refcount = 1;
|
2005-01-15 Havoc Pennington <hp@redhat.com>
* Land the new message args API and type system.
This patch is huge, but the public API change is not
really large. The set of D-BUS types has changed somewhat,
and the arg "getters" are more geared toward language bindings;
they don't make a copy, etc.
There are also some known issues. See these emails for details
on this huge patch:
http://lists.freedesktop.org/archives/dbus/2004-December/001836.html
http://lists.freedesktop.org/archives/dbus/2005-January/001922.html
* dbus/dbus-marshal-*: all the new stuff
* dbus/dbus-message.c: basically rewritten
* dbus/dbus-memory.c (check_guards): with "guards" enabled, init
freed blocks to be all non-nul bytes so using freed memory is less
likely to work right
* dbus/dbus-internals.c (_dbus_test_oom_handling): add
DBUS_FAIL_MALLOC=N environment variable, so you can do
DBUS_FAIL_MALLOC=0 to skip the out-of-memory checking, or
DBUS_FAIL_MALLOC=10 to make it really, really, really slow and
thorough.
* qt/message.cpp: port to the new message args API
(operator<<): use str.utf8() rather than str.unicode()
(pretty sure this is right from the Qt docs?)
* glib/dbus-gvalue.c: port to the new message args API
* bus/dispatch.c, bus/driver.c: port to the new message args API
* dbus/dbus-string.c (_dbus_string_init_const_len): initialize the
"locked" flag to TRUE and align_offset to 0; I guess we never
looked at these anyhow, but seems cleaner.
* dbus/dbus-string.h (_DBUS_STRING_ALLOCATION_PADDING):
move allocation padding macro to this header; use it to implement
(_DBUS_STRING_STATIC): ability to declare a static string.
* dbus/dbus-message.c (_dbus_message_has_type_interface_member):
change to return TRUE if the interface is not set.
* dbus/dbus-string.[hc]: move the D-BUS specific validation stuff
to dbus-marshal-validate.[hc]
* dbus/dbus-marshal-basic.c (_dbus_type_to_string): move here from
dbus-internals.c
* dbus/Makefile.am: cut over from dbus-marshal.[hc]
to dbus-marshal-*.[hc]
* dbus/dbus-object-tree.c (_dbus_decompose_path): move this
function here from dbus-marshal.c
2005-01-15 07:15:38 +00:00
|
|
|
|
|
|
|
|
_dbus_verbose ("copying string %p '%s' to service->name\n",
|
|
|
|
|
service_name, _dbus_string_get_const_data (service_name));
|
2003-03-31 20:56:29 +00:00
|
|
|
if (!_dbus_string_copy_data (service_name, &service->name))
|
2003-01-06 01:08:14 +00:00
|
|
|
{
|
2003-03-13 03:52:58 +00:00
|
|
|
_dbus_mem_pool_dealloc (registry->service_pool, service);
|
2003-03-13 00:56:43 +00:00
|
|
|
BUS_SET_OOM (error);
|
2003-01-06 01:08:14 +00:00
|
|
|
return NULL;
|
|
|
|
|
}
|
2005-01-15 Havoc Pennington <hp@redhat.com>
* Land the new message args API and type system.
This patch is huge, but the public API change is not
really large. The set of D-BUS types has changed somewhat,
and the arg "getters" are more geared toward language bindings;
they don't make a copy, etc.
There are also some known issues. See these emails for details
on this huge patch:
http://lists.freedesktop.org/archives/dbus/2004-December/001836.html
http://lists.freedesktop.org/archives/dbus/2005-January/001922.html
* dbus/dbus-marshal-*: all the new stuff
* dbus/dbus-message.c: basically rewritten
* dbus/dbus-memory.c (check_guards): with "guards" enabled, init
freed blocks to be all non-nul bytes so using freed memory is less
likely to work right
* dbus/dbus-internals.c (_dbus_test_oom_handling): add
DBUS_FAIL_MALLOC=N environment variable, so you can do
DBUS_FAIL_MALLOC=0 to skip the out-of-memory checking, or
DBUS_FAIL_MALLOC=10 to make it really, really, really slow and
thorough.
* qt/message.cpp: port to the new message args API
(operator<<): use str.utf8() rather than str.unicode()
(pretty sure this is right from the Qt docs?)
* glib/dbus-gvalue.c: port to the new message args API
* bus/dispatch.c, bus/driver.c: port to the new message args API
* dbus/dbus-string.c (_dbus_string_init_const_len): initialize the
"locked" flag to TRUE and align_offset to 0; I guess we never
looked at these anyhow, but seems cleaner.
* dbus/dbus-string.h (_DBUS_STRING_ALLOCATION_PADDING):
move allocation padding macro to this header; use it to implement
(_DBUS_STRING_STATIC): ability to declare a static string.
* dbus/dbus-message.c (_dbus_message_has_type_interface_member):
change to return TRUE if the interface is not set.
* dbus/dbus-string.[hc]: move the D-BUS specific validation stuff
to dbus-marshal-validate.[hc]
* dbus/dbus-marshal-basic.c (_dbus_type_to_string): move here from
dbus-internals.c
* dbus/Makefile.am: cut over from dbus-marshal.[hc]
to dbus-marshal-*.[hc]
* dbus/dbus-object-tree.c (_dbus_decompose_path): move this
function here from dbus-marshal.c
2005-01-15 07:15:38 +00:00
|
|
|
_dbus_verbose ("copied string %p '%s' to '%s'\n",
|
|
|
|
|
service_name, _dbus_string_get_const_data (service_name),
|
|
|
|
|
service->name);
|
2003-01-06 01:08:14 +00:00
|
|
|
|
2004-09-24 10:43:36 +00:00
|
|
|
if (!bus_driver_send_service_owner_changed (service->name,
|
|
|
|
|
NULL,
|
|
|
|
|
bus_connection_get_name (owner_if_created),
|
|
|
|
|
transaction, error))
|
2003-03-13 00:56:43 +00:00
|
|
|
{
|
2003-04-11 00:03:06 +00:00
|
|
|
bus_service_unref (service);
|
2003-03-13 00:56:43 +00:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2003-03-16 22:25:18 +00:00
|
|
|
if (!bus_activation_service_created (bus_context_get_activation (registry->context),
|
2003-04-02 20:14:52 +00:00
|
|
|
service->name, transaction, error))
|
2003-03-16 22:25:18 +00:00
|
|
|
{
|
2003-04-11 00:03:06 +00:00
|
|
|
bus_service_unref (service);
|
2003-03-16 22:25:18 +00:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2003-03-13 00:56:43 +00:00
|
|
|
if (!bus_service_add_owner (service, owner_if_created,
|
|
|
|
|
transaction, error))
|
|
|
|
|
{
|
2003-04-11 00:03:06 +00:00
|
|
|
bus_service_unref (service);
|
2003-03-13 00:56:43 +00:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2003-03-13 03:52:58 +00:00
|
|
|
if (!_dbus_hash_table_insert_string (registry->service_hash,
|
2003-01-06 01:08:14 +00:00
|
|
|
service->name,
|
|
|
|
|
service))
|
|
|
|
|
{
|
2003-04-11 00:03:06 +00:00
|
|
|
/* The add_owner gets reverted on transaction cancel */
|
2003-03-13 00:56:43 +00:00
|
|
|
BUS_SET_OOM (error);
|
2003-01-06 01:08:14 +00:00
|
|
|
return NULL;
|
|
|
|
|
}
|
2003-02-13 21:37:58 +00:00
|
|
|
|
2003-01-06 01:08:14 +00:00
|
|
|
return service;
|
|
|
|
|
}
|
|
|
|
|
|
2003-03-13 03:52:58 +00:00
|
|
|
void
|
|
|
|
|
bus_registry_foreach (BusRegistry *registry,
|
|
|
|
|
BusServiceForeachFunction function,
|
|
|
|
|
void *data)
|
|
|
|
|
{
|
|
|
|
|
DBusHashIter iter;
|
|
|
|
|
|
|
|
|
|
_dbus_hash_iter_init (registry->service_hash, &iter);
|
|
|
|
|
while (_dbus_hash_iter_next (&iter))
|
|
|
|
|
{
|
|
|
|
|
BusService *service = _dbus_hash_iter_get_value (&iter);
|
|
|
|
|
|
|
|
|
|
(* function) (service, data);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dbus_bool_t
|
|
|
|
|
bus_registry_list_services (BusRegistry *registry,
|
|
|
|
|
char ***listp,
|
|
|
|
|
int *array_len)
|
|
|
|
|
{
|
|
|
|
|
int i, j, len;
|
|
|
|
|
char **retval;
|
|
|
|
|
DBusHashIter iter;
|
|
|
|
|
|
|
|
|
|
len = _dbus_hash_table_get_n_entries (registry->service_hash);
|
|
|
|
|
retval = dbus_new (char *, len + 1);
|
|
|
|
|
|
|
|
|
|
if (retval == NULL)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
_dbus_hash_iter_init (registry->service_hash, &iter);
|
|
|
|
|
i = 0;
|
|
|
|
|
while (_dbus_hash_iter_next (&iter))
|
|
|
|
|
{
|
|
|
|
|
BusService *service = _dbus_hash_iter_get_value (&iter);
|
|
|
|
|
|
|
|
|
|
retval[i] = _dbus_strdup (service->name);
|
|
|
|
|
if (retval[i] == NULL)
|
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
retval[i] = NULL;
|
|
|
|
|
|
|
|
|
|
if (array_len)
|
|
|
|
|
*array_len = len;
|
|
|
|
|
|
|
|
|
|
*listp = retval;
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
error:
|
|
|
|
|
for (j = 0; j < i; j++)
|
|
|
|
|
dbus_free (retval[i]);
|
|
|
|
|
dbus_free (retval);
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2003-04-11 00:03:06 +00:00
|
|
|
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;
|
|
|
|
|
DBusConnection *current_owner;
|
2003-04-25 23:50:34 +00:00
|
|
|
BusClientPolicy *policy;
|
2003-04-11 00:03:06 +00:00
|
|
|
BusService *service;
|
2004-03-16 18:00:35 +00:00
|
|
|
BusActivation *activation;
|
2004-07-30 05:59:34 +00:00
|
|
|
BusSELinuxID *sid;
|
2003-04-11 00:03:06 +00:00
|
|
|
|
|
|
|
|
retval = FALSE;
|
|
|
|
|
|
2005-01-21 03:44:10 +00:00
|
|
|
if (!_dbus_validate_bus_name (service_name, 0,
|
|
|
|
|
_dbus_string_get_length (service_name)))
|
2003-04-11 00:03:06 +00:00
|
|
|
{
|
2005-01-21 03:44:10 +00:00
|
|
|
dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
|
|
|
|
|
"Requested bus name \"%s\" is not valid",
|
|
|
|
|
_dbus_string_get_const_data (service_name));
|
2003-04-11 00:03:06 +00:00
|
|
|
|
2005-01-21 03:44:10 +00:00
|
|
|
_dbus_verbose ("Attempt to acquire invalid service name\n");
|
2003-04-11 00:03:06 +00:00
|
|
|
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_dbus_string_get_byte (service_name, 0) == ':')
|
|
|
|
|
{
|
|
|
|
|
/* Not allowed; only base services can start with ':' */
|
2005-01-21 03:44:10 +00:00
|
|
|
dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
|
2003-04-11 00:03:06 +00:00
|
|
|
"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;
|
|
|
|
|
}
|
2003-04-25 23:50:34 +00:00
|
|
|
|
2003-04-27 06:25:42 +00:00
|
|
|
policy = bus_connection_get_policy (connection);
|
|
|
|
|
_dbus_assert (policy != NULL);
|
2003-04-25 23:50:34 +00:00
|
|
|
|
2004-07-30 05:59:34 +00:00
|
|
|
/* 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);
|
|
|
|
|
|
2004-11-09 Colin Walters <walters@verbum.org>
* dbus/dbus-string.c (_dbus_string_get_length): New
function, writes DBusString to C buffer.
* dbus/dbus-string.h: Prototype it.
* dbus/dbus-message.c (dbus_message_type_to_string): New
function, converts message type into C string.
* dbus/dbus-message.h: Prototype it.
* bus/selinux.c (bus_selinux_check): Take source pid,
target pid, and audit data. Pass audit data to
avc_has_perm.
(log_audit_callback): New function, appends extra
audit information.
(bus_selinux_allows_acquire_service): Also take
service name, add it to audit data.
(bus_selinux_allows_send): Also take message
type, interface, method member, error name,
and destination, and add them to audit data.
(log_cb): Initialize func_audit.
* bus/selinux.h (bus_selinux_allows_acquire_service)
(bus_selinux_allows_send): Update prototypes
* bus/services.c (bus_registry_acquire_service): Pass
service name to bus_selinux_allows_acquire_service.
* bus/bus.c (bus_context_check_security_policy): Pass
additional audit data. Move assignment of dest
to its own line.
2004-11-09 06:11:33 +00:00
|
|
|
if (!bus_selinux_allows_acquire_service (connection, sid,
|
2005-04-13 14:27:11 +00:00
|
|
|
_dbus_string_get_const_data (service_name), error))
|
2004-07-30 05:59:34 +00:00
|
|
|
{
|
2005-04-13 14:27:11 +00:00
|
|
|
|
|
|
|
|
if (dbus_error_is_set (error) &&
|
|
|
|
|
dbus_error_has_name (error, DBUS_ERROR_NO_MEMORY))
|
|
|
|
|
{
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
2004-07-30 05:59:34 +00:00
|
|
|
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)",
|
2004-10-29 18:13:53 +00:00
|
|
|
_dbus_string_get_const_data (service_name));
|
2004-07-30 05:59:34 +00:00
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
2003-04-25 23:50:34 +00:00
|
|
|
if (!bus_client_policy_check_can_own (policy, connection,
|
|
|
|
|
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) :
|
2004-02-24 19:50:25 +00:00
|
|
|
"(inactive)",
|
2004-10-29 18:13:53 +00:00
|
|
|
_dbus_string_get_const_data (service_name));
|
2003-04-25 23:50:34 +00:00
|
|
|
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;
|
|
|
|
|
}
|
2003-04-11 00:03:06 +00:00
|
|
|
|
|
|
|
|
service = bus_registry_lookup (registry, service_name);
|
|
|
|
|
|
|
|
|
|
if (service != NULL)
|
|
|
|
|
old_owner = bus_service_get_primary_owner (service);
|
|
|
|
|
else
|
|
|
|
|
old_owner = NULL;
|
|
|
|
|
|
|
|
|
|
if (service == NULL)
|
|
|
|
|
{
|
|
|
|
|
service = bus_registry_ensure (registry,
|
|
|
|
|
service_name, connection, transaction, error);
|
|
|
|
|
if (service == NULL)
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
current_owner = bus_service_get_primary_owner (service);
|
|
|
|
|
|
|
|
|
|
if (old_owner == NULL)
|
|
|
|
|
{
|
|
|
|
|
_dbus_assert (current_owner == connection);
|
|
|
|
|
|
|
|
|
|
bus_service_set_prohibit_replacement (service,
|
2005-01-18 20:42:15 +00:00
|
|
|
(flags & DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT));
|
2003-04-11 00:03:06 +00:00
|
|
|
|
2005-01-18 20:42:15 +00:00
|
|
|
*result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;
|
2003-04-11 00:03:06 +00:00
|
|
|
}
|
|
|
|
|
else if (old_owner == connection)
|
2005-01-18 20:42:15 +00:00
|
|
|
*result = DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER;
|
|
|
|
|
else if (!((flags & DBUS_NAME_FLAG_REPLACE_EXISTING)))
|
|
|
|
|
*result = DBUS_REQUEST_NAME_REPLY_EXISTS;
|
2003-04-11 00:03:06 +00:00
|
|
|
else if (bus_service_get_prohibit_replacement (service))
|
|
|
|
|
{
|
|
|
|
|
/* Queue the connection */
|
|
|
|
|
if (!bus_service_add_owner (service, connection,
|
|
|
|
|
transaction, error))
|
|
|
|
|
goto out;
|
|
|
|
|
|
2005-01-18 20:42:15 +00:00
|
|
|
*result = DBUS_REQUEST_NAME_REPLY_IN_QUEUE;
|
2003-04-11 00:03:06 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Replace the current owner */
|
|
|
|
|
|
|
|
|
|
/* We enqueue the new owner and remove the first one because
|
2005-01-18 20:42:15 +00:00
|
|
|
* that will cause NameAcquired and NameLost messages to
|
2003-04-11 00:03:06 +00:00
|
|
|
* be sent.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (!bus_service_add_owner (service, connection,
|
|
|
|
|
transaction, error))
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
if (!bus_service_remove_owner (service, old_owner,
|
|
|
|
|
transaction, error))
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
_dbus_assert (connection == bus_service_get_primary_owner (service));
|
2005-01-18 20:42:15 +00:00
|
|
|
*result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;
|
2003-04-11 00:03:06 +00:00
|
|
|
}
|
|
|
|
|
|
2004-03-16 18:00:35 +00:00
|
|
|
activation = bus_context_get_activation (registry->context);
|
|
|
|
|
retval = bus_activation_send_pending_auto_activation_messages (activation,
|
|
|
|
|
service,
|
|
|
|
|
transaction,
|
|
|
|
|
error);
|
2003-04-11 00:03:06 +00:00
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
|
2004-11-07 Colin Walters <walters@verbum.org>
* bus/bus.c (load_config): Break into three
separate functions: process_config_first_time_only,
process_config_every_time, and process_config_postinit.
(process_config_every_time): Move call of
bus_registry_set_service_context_table into
process_config_postinit.
(process_config_postinit): New function, does
any processing that needs to happen late
in initialization (and also on reload).
(bus_context_new): Instead of calling load_config,
open config parser here and call process_config_first_time_only
and process_config_every_time directly. Later, after
we have forked but before changing UID,
invoke bus_selinux_full_init, and then call
process_config_postinit.
(bus_context_reload_config): As in bus_context_new,
load parse file inside here, and call process_config_every_time
and process_config_postinit.
* bus/services.h, bus/services.c
(bus_registry_set_service_context_table): Rename
from bus_registry_set_sid_table. Take string hash from config
parser, and convert them here into SIDs.
* bus/config-parser.c (struct BusConfigParser): Have
config parser only store a mapping of service->context
string.
(merge_service_context_hash): New function.
(merge_included): Merge context string hashes instead
of using bus_selinux_id_table_union.
(bus_config_parser_new): Don't use bus_selinux_id_table_new;
simply create a new string hash.
(bus_config_parser_unref): Unref it.
(start_selinux_child): Simply insert strings into hash,
don't call bus_selinux_id_table_copy_over.
* bus/selinux.h, bus/selinux.c (bus_selinux_id_table_union)
(bus_selinux_id_table_copy_over): Delete.
2004-11-07 17:05:19 +00:00
|
|
|
dbus_bool_t
|
|
|
|
|
bus_registry_set_service_context_table (BusRegistry *registry,
|
|
|
|
|
DBusHashTable *table)
|
2004-07-30 05:59:34 +00:00
|
|
|
{
|
2004-11-07 Colin Walters <walters@verbum.org>
* bus/bus.c (load_config): Break into three
separate functions: process_config_first_time_only,
process_config_every_time, and process_config_postinit.
(process_config_every_time): Move call of
bus_registry_set_service_context_table into
process_config_postinit.
(process_config_postinit): New function, does
any processing that needs to happen late
in initialization (and also on reload).
(bus_context_new): Instead of calling load_config,
open config parser here and call process_config_first_time_only
and process_config_every_time directly. Later, after
we have forked but before changing UID,
invoke bus_selinux_full_init, and then call
process_config_postinit.
(bus_context_reload_config): As in bus_context_new,
load parse file inside here, and call process_config_every_time
and process_config_postinit.
* bus/services.h, bus/services.c
(bus_registry_set_service_context_table): Rename
from bus_registry_set_sid_table. Take string hash from config
parser, and convert them here into SIDs.
* bus/config-parser.c (struct BusConfigParser): Have
config parser only store a mapping of service->context
string.
(merge_service_context_hash): New function.
(merge_included): Merge context string hashes instead
of using bus_selinux_id_table_union.
(bus_config_parser_new): Don't use bus_selinux_id_table_new;
simply create a new string hash.
(bus_config_parser_unref): Unref it.
(start_selinux_child): Simply insert strings into hash,
don't call bus_selinux_id_table_copy_over.
* bus/selinux.h, bus/selinux.c (bus_selinux_id_table_union)
(bus_selinux_id_table_copy_over): Delete.
2004-11-07 17:05:19 +00:00
|
|
|
DBusHashTable *new_table;
|
|
|
|
|
DBusHashIter iter;
|
|
|
|
|
|
|
|
|
|
new_table = bus_selinux_id_table_new ();
|
|
|
|
|
if (!new_table)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
_dbus_hash_iter_init (table, &iter);
|
|
|
|
|
while (_dbus_hash_iter_next (&iter))
|
|
|
|
|
{
|
|
|
|
|
const char *service = _dbus_hash_iter_get_string_key (&iter);
|
|
|
|
|
const char *context = _dbus_hash_iter_get_value (&iter);
|
|
|
|
|
|
|
|
|
|
if (!bus_selinux_id_table_insert (new_table,
|
|
|
|
|
service,
|
|
|
|
|
context))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2004-07-30 05:59:34 +00:00
|
|
|
|
|
|
|
|
if (registry->service_sid_table)
|
|
|
|
|
_dbus_hash_table_unref (registry->service_sid_table);
|
2004-11-07 Colin Walters <walters@verbum.org>
* bus/bus.c (load_config): Break into three
separate functions: process_config_first_time_only,
process_config_every_time, and process_config_postinit.
(process_config_every_time): Move call of
bus_registry_set_service_context_table into
process_config_postinit.
(process_config_postinit): New function, does
any processing that needs to happen late
in initialization (and also on reload).
(bus_context_new): Instead of calling load_config,
open config parser here and call process_config_first_time_only
and process_config_every_time directly. Later, after
we have forked but before changing UID,
invoke bus_selinux_full_init, and then call
process_config_postinit.
(bus_context_reload_config): As in bus_context_new,
load parse file inside here, and call process_config_every_time
and process_config_postinit.
* bus/services.h, bus/services.c
(bus_registry_set_service_context_table): Rename
from bus_registry_set_sid_table. Take string hash from config
parser, and convert them here into SIDs.
* bus/config-parser.c (struct BusConfigParser): Have
config parser only store a mapping of service->context
string.
(merge_service_context_hash): New function.
(merge_included): Merge context string hashes instead
of using bus_selinux_id_table_union.
(bus_config_parser_new): Don't use bus_selinux_id_table_new;
simply create a new string hash.
(bus_config_parser_unref): Unref it.
(start_selinux_child): Simply insert strings into hash,
don't call bus_selinux_id_table_copy_over.
* bus/selinux.h, bus/selinux.c (bus_selinux_id_table_union)
(bus_selinux_id_table_copy_over): Delete.
2004-11-07 17:05:19 +00:00
|
|
|
registry->service_sid_table = new_table;
|
|
|
|
|
return TRUE;
|
2004-07-30 05:59:34 +00:00
|
|
|
}
|
|
|
|
|
|
2003-04-11 00:03:06 +00:00
|
|
|
static void
|
|
|
|
|
bus_service_unlink_owner (BusService *service,
|
|
|
|
|
DBusConnection *owner)
|
|
|
|
|
{
|
|
|
|
|
_dbus_list_remove_last (&service->owners, owner);
|
|
|
|
|
bus_connection_remove_owned_service (owner, service);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
bus_service_unlink (BusService *service)
|
|
|
|
|
{
|
|
|
|
|
_dbus_assert (service->owners == NULL);
|
|
|
|
|
|
|
|
|
|
/* the service may not be in the hash, if
|
|
|
|
|
* the failure causing transaction cancel
|
|
|
|
|
* was in the right place, but that's OK
|
|
|
|
|
*/
|
|
|
|
|
_dbus_hash_table_remove_string (service->registry->service_hash,
|
|
|
|
|
service->name);
|
|
|
|
|
|
|
|
|
|
bus_service_unref (service);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
bus_service_relink (BusService *service,
|
|
|
|
|
DBusPreallocatedHash *preallocated)
|
|
|
|
|
{
|
|
|
|
|
_dbus_assert (service->owners == NULL);
|
|
|
|
|
_dbus_assert (preallocated != NULL);
|
|
|
|
|
|
|
|
|
|
_dbus_hash_table_insert_string_preallocated (service->registry->service_hash,
|
|
|
|
|
preallocated,
|
|
|
|
|
service->name,
|
|
|
|
|
service);
|
|
|
|
|
|
|
|
|
|
bus_service_ref (service);
|
|
|
|
|
}
|
|
|
|
|
|
2003-09-07 23:04:54 +00:00
|
|
|
/**
|
|
|
|
|
* Data used to represent an ownership cancellation in
|
|
|
|
|
* a bus transaction.
|
|
|
|
|
*/
|
2003-04-11 00:03:06 +00:00
|
|
|
typedef struct
|
|
|
|
|
{
|
2003-09-07 23:04:54 +00:00
|
|
|
DBusConnection *connection; /**< the connection */
|
|
|
|
|
BusService *service; /**< service to cancel ownership of */
|
2003-04-11 00:03:06 +00:00
|
|
|
} OwnershipCancelData;
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
cancel_ownership (void *data)
|
|
|
|
|
{
|
|
|
|
|
OwnershipCancelData *d = data;
|
|
|
|
|
|
|
|
|
|
/* We don't need to send messages notifying of these
|
|
|
|
|
* changes, since we're reverting something that was
|
|
|
|
|
* cancelled (effectively never really happened)
|
|
|
|
|
*/
|
|
|
|
|
bus_service_unlink_owner (d->service, d->connection);
|
|
|
|
|
|
|
|
|
|
if (d->service->owners == NULL)
|
|
|
|
|
bus_service_unlink (d->service);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
free_ownership_cancel_data (void *data)
|
|
|
|
|
{
|
|
|
|
|
OwnershipCancelData *d = data;
|
|
|
|
|
|
|
|
|
|
dbus_connection_unref (d->connection);
|
|
|
|
|
bus_service_unref (d->service);
|
|
|
|
|
|
|
|
|
|
dbus_free (d);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static dbus_bool_t
|
|
|
|
|
add_cancel_ownership_to_transaction (BusTransaction *transaction,
|
|
|
|
|
BusService *service,
|
|
|
|
|
DBusConnection *connection)
|
|
|
|
|
{
|
|
|
|
|
OwnershipCancelData *d;
|
|
|
|
|
|
|
|
|
|
d = dbus_new (OwnershipCancelData, 1);
|
|
|
|
|
if (d == NULL)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
d->service = service;
|
|
|
|
|
d->connection = connection;
|
|
|
|
|
|
|
|
|
|
if (!bus_transaction_add_cancel_hook (transaction, cancel_ownership, d,
|
|
|
|
|
free_ownership_cancel_data))
|
|
|
|
|
{
|
|
|
|
|
dbus_free (d);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bus_service_ref (d->service);
|
|
|
|
|
dbus_connection_ref (d->connection);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* this function is self-cancelling if you cancel the transaction */
|
2003-01-06 01:08:14 +00:00
|
|
|
dbus_bool_t
|
|
|
|
|
bus_service_add_owner (BusService *service,
|
2003-03-13 00:56:43 +00:00
|
|
|
DBusConnection *owner,
|
|
|
|
|
BusTransaction *transaction,
|
|
|
|
|
DBusError *error)
|
2003-01-06 01:08:14 +00:00
|
|
|
{
|
2003-03-26 03:58:11 +00:00
|
|
|
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
|
|
|
|
|
|
2003-03-13 00:56:43 +00:00
|
|
|
/* Send service acquired message first, OOM will result
|
|
|
|
|
* in cancelling the transaction
|
|
|
|
|
*/
|
|
|
|
|
if (service->owners == NULL)
|
|
|
|
|
{
|
|
|
|
|
if (!bus_driver_send_service_acquired (owner, service->name, transaction, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-06 01:08:14 +00:00
|
|
|
if (!_dbus_list_append (&service->owners,
|
|
|
|
|
owner))
|
2003-03-13 00:56:43 +00:00
|
|
|
{
|
|
|
|
|
BUS_SET_OOM (error);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2003-01-06 01:08:14 +00:00
|
|
|
|
|
|
|
|
if (!bus_connection_add_owned_service (owner, service))
|
|
|
|
|
{
|
|
|
|
|
_dbus_list_remove_last (&service->owners, owner);
|
2003-03-13 00:56:43 +00:00
|
|
|
BUS_SET_OOM (error);
|
2003-01-06 01:08:14 +00:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
2003-04-11 00:03:06 +00:00
|
|
|
|
|
|
|
|
if (!add_cancel_ownership_to_transaction (transaction,
|
|
|
|
|
service,
|
|
|
|
|
owner))
|
|
|
|
|
{
|
|
|
|
|
bus_service_unlink_owner (service, owner);
|
|
|
|
|
BUS_SET_OOM (error);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2003-01-27 11:20:55 +00:00
|
|
|
|
2003-01-06 01:08:14 +00:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2003-04-11 00:03:06 +00:00
|
|
|
typedef struct
|
|
|
|
|
{
|
|
|
|
|
DBusConnection *connection;
|
|
|
|
|
BusService *service;
|
|
|
|
|
DBusConnection *before_connection; /* restore to position before this connection in owners list */
|
|
|
|
|
DBusList *connection_link;
|
|
|
|
|
DBusList *service_link;
|
|
|
|
|
DBusPreallocatedHash *hash_entry;
|
|
|
|
|
} OwnershipRestoreData;
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
restore_ownership (void *data)
|
|
|
|
|
{
|
|
|
|
|
OwnershipRestoreData *d = data;
|
|
|
|
|
DBusList *link;
|
|
|
|
|
|
|
|
|
|
_dbus_assert (d->service_link != NULL);
|
|
|
|
|
_dbus_assert (d->connection_link != NULL);
|
|
|
|
|
|
|
|
|
|
if (d->service->owners == NULL)
|
|
|
|
|
{
|
|
|
|
|
_dbus_assert (d->hash_entry != NULL);
|
|
|
|
|
bus_service_relink (d->service, d->hash_entry);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_dbus_assert (d->hash_entry == NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* We don't need to send messages notifying of these
|
|
|
|
|
* changes, since we're reverting something that was
|
|
|
|
|
* cancelled (effectively never really happened)
|
|
|
|
|
*/
|
|
|
|
|
link = _dbus_list_get_first_link (&d->service->owners);
|
|
|
|
|
while (link != NULL)
|
|
|
|
|
{
|
|
|
|
|
if (link->data == d->before_connection)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
link = _dbus_list_get_next_link (&d->service->owners, link);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_dbus_list_insert_before_link (&d->service->owners, link, d->connection_link);
|
|
|
|
|
|
|
|
|
|
/* Note that removing then restoring this changes the order in which
|
|
|
|
|
* ServiceDeleted messages are sent on destruction of the
|
|
|
|
|
* connection. This should be OK as the only guarantee there is
|
|
|
|
|
* that the base service is destroyed last, and we never even
|
|
|
|
|
* tentatively remove the base service.
|
|
|
|
|
*/
|
|
|
|
|
bus_connection_add_owned_service_link (d->connection, d->service_link);
|
|
|
|
|
|
|
|
|
|
d->hash_entry = NULL;
|
|
|
|
|
d->service_link = NULL;
|
|
|
|
|
d->connection_link = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
free_ownership_restore_data (void *data)
|
|
|
|
|
{
|
|
|
|
|
OwnershipRestoreData *d = data;
|
|
|
|
|
|
|
|
|
|
if (d->service_link)
|
|
|
|
|
_dbus_list_free_link (d->service_link);
|
|
|
|
|
if (d->connection_link)
|
|
|
|
|
_dbus_list_free_link (d->connection_link);
|
|
|
|
|
if (d->hash_entry)
|
|
|
|
|
_dbus_hash_table_free_preallocated_entry (d->service->registry->service_hash,
|
|
|
|
|
d->hash_entry);
|
|
|
|
|
|
|
|
|
|
dbus_connection_unref (d->connection);
|
|
|
|
|
bus_service_unref (d->service);
|
|
|
|
|
|
|
|
|
|
dbus_free (d);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static dbus_bool_t
|
|
|
|
|
add_restore_ownership_to_transaction (BusTransaction *transaction,
|
|
|
|
|
BusService *service,
|
|
|
|
|
DBusConnection *connection)
|
|
|
|
|
{
|
|
|
|
|
OwnershipRestoreData *d;
|
|
|
|
|
DBusList *link;
|
|
|
|
|
|
|
|
|
|
d = dbus_new (OwnershipRestoreData, 1);
|
|
|
|
|
if (d == NULL)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
d->service = service;
|
|
|
|
|
d->connection = connection;
|
|
|
|
|
d->service_link = _dbus_list_alloc_link (service);
|
|
|
|
|
d->connection_link = _dbus_list_alloc_link (connection);
|
|
|
|
|
d->hash_entry = _dbus_hash_table_preallocate_entry (service->registry->service_hash);
|
|
|
|
|
|
|
|
|
|
bus_service_ref (d->service);
|
|
|
|
|
dbus_connection_ref (d->connection);
|
|
|
|
|
|
|
|
|
|
d->before_connection = NULL;
|
|
|
|
|
link = _dbus_list_get_first_link (&service->owners);
|
|
|
|
|
while (link != NULL)
|
|
|
|
|
{
|
|
|
|
|
if (link->data == connection)
|
|
|
|
|
{
|
|
|
|
|
link = _dbus_list_get_next_link (&service->owners, link);
|
|
|
|
|
|
|
|
|
|
if (link)
|
|
|
|
|
d->before_connection = link->data;
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
link = _dbus_list_get_next_link (&service->owners, link);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (d->service_link == NULL ||
|
|
|
|
|
d->connection_link == NULL ||
|
|
|
|
|
d->hash_entry == NULL ||
|
|
|
|
|
!bus_transaction_add_cancel_hook (transaction, restore_ownership, d,
|
|
|
|
|
free_ownership_restore_data))
|
|
|
|
|
{
|
|
|
|
|
free_ownership_restore_data (d);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* this function is self-cancelling if you cancel the transaction */
|
2003-03-13 00:56:43 +00:00
|
|
|
dbus_bool_t
|
2003-01-06 01:08:14 +00:00
|
|
|
bus_service_remove_owner (BusService *service,
|
2003-03-13 00:56:43 +00:00
|
|
|
DBusConnection *owner,
|
|
|
|
|
BusTransaction *transaction,
|
|
|
|
|
DBusError *error)
|
2003-01-06 01:08:14 +00:00
|
|
|
{
|
2003-03-26 03:58:11 +00:00
|
|
|
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
|
|
|
|
|
|
2003-03-13 00:56:43 +00:00
|
|
|
/* We send out notifications before we do any work we
|
|
|
|
|
* might have to undo if the notification-sending failed
|
|
|
|
|
*/
|
|
|
|
|
|
2003-01-27 11:20:55 +00:00
|
|
|
/* Send service lost message */
|
|
|
|
|
if (bus_service_get_primary_owner (service) == owner)
|
2003-03-13 00:56:43 +00:00
|
|
|
{
|
|
|
|
|
if (!bus_driver_send_service_lost (owner, service->name,
|
|
|
|
|
transaction, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2003-03-15 20:47:16 +00:00
|
|
|
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))
|
2003-03-13 00:56:43 +00:00
|
|
|
{
|
2004-09-24 10:43:36 +00:00
|
|
|
if (!bus_driver_send_service_owner_changed (service->name,
|
|
|
|
|
bus_connection_get_name (owner),
|
|
|
|
|
NULL,
|
|
|
|
|
transaction, error))
|
2003-03-13 00:56:43 +00:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
DBusList *link;
|
2004-09-24 10:43:36 +00:00
|
|
|
DBusConnection *new_owner;
|
2004-07-22 07:07:01 +00:00
|
|
|
link = _dbus_list_get_first_link (&service->owners);
|
2003-03-15 20:47:16 +00:00
|
|
|
_dbus_assert (link != NULL);
|
2003-03-13 00:56:43 +00:00
|
|
|
link = _dbus_list_get_next_link (&service->owners, link);
|
2003-04-11 00:03:06 +00:00
|
|
|
_dbus_assert (link != NULL);
|
|
|
|
|
|
2004-09-24 10:43:36 +00:00
|
|
|
new_owner = link->data;
|
|
|
|
|
|
|
|
|
|
if (!bus_driver_send_service_owner_changed (service->name,
|
|
|
|
|
bus_connection_get_name (owner),
|
|
|
|
|
bus_connection_get_name (new_owner),
|
|
|
|
|
transaction, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2003-04-11 00:03:06 +00:00
|
|
|
/* This will be our new owner */
|
2004-09-24 10:43:36 +00:00
|
|
|
if (!bus_driver_send_service_acquired (new_owner,
|
2003-04-11 00:03:06 +00:00
|
|
|
service->name,
|
|
|
|
|
transaction,
|
|
|
|
|
error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!add_restore_ownership_to_transaction (transaction, service, owner))
|
|
|
|
|
{
|
|
|
|
|
BUS_SET_OOM (error);
|
|
|
|
|
return FALSE;
|
2003-03-13 00:56:43 +00:00
|
|
|
}
|
2003-01-27 11:20:55 +00:00
|
|
|
|
2003-04-11 00:03:06 +00:00
|
|
|
bus_service_unlink_owner (service, owner);
|
2003-01-27 11:20:55 +00:00
|
|
|
|
|
|
|
|
if (service->owners == NULL)
|
2003-04-11 00:03:06 +00:00
|
|
|
bus_service_unlink (service);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2003-11-27 01:25:50 +00:00
|
|
|
BusService *
|
2003-04-11 00:03:06 +00:00
|
|
|
bus_service_ref (BusService *service)
|
|
|
|
|
{
|
|
|
|
|
_dbus_assert (service->refcount > 0);
|
|
|
|
|
|
|
|
|
|
service->refcount += 1;
|
2003-11-27 01:25:50 +00:00
|
|
|
|
|
|
|
|
return service;
|
2003-04-11 00:03:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
bus_service_unref (BusService *service)
|
|
|
|
|
{
|
|
|
|
|
_dbus_assert (service->refcount > 0);
|
|
|
|
|
|
|
|
|
|
service->refcount -= 1;
|
|
|
|
|
|
|
|
|
|
if (service->refcount == 0)
|
2003-01-27 11:20:55 +00:00
|
|
|
{
|
2003-04-11 00:03:06 +00:00
|
|
|
_dbus_assert (service->owners == NULL);
|
2003-01-27 11:20:55 +00:00
|
|
|
|
|
|
|
|
dbus_free (service->name);
|
2003-03-13 03:52:58 +00:00
|
|
|
_dbus_mem_pool_dealloc (service->registry->service_pool, service);
|
2003-01-27 11:20:55 +00:00
|
|
|
}
|
2003-01-06 01:08:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DBusConnection*
|
|
|
|
|
bus_service_get_primary_owner (BusService *service)
|
|
|
|
|
{
|
|
|
|
|
return _dbus_list_get_first (&service->owners);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char*
|
|
|
|
|
bus_service_get_name (BusService *service)
|
|
|
|
|
{
|
|
|
|
|
return service->name;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-27 11:20:55 +00:00
|
|
|
void
|
|
|
|
|
bus_service_set_prohibit_replacement (BusService *service,
|
|
|
|
|
dbus_bool_t prohibit_replacement)
|
|
|
|
|
{
|
|
|
|
|
service->prohibit_replacement = prohibit_replacement != FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dbus_bool_t
|
|
|
|
|
bus_service_get_prohibit_replacement (BusService *service)
|
|
|
|
|
{
|
|
|
|
|
return service->prohibit_replacement;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dbus_bool_t
|
|
|
|
|
bus_service_has_owner (BusService *service,
|
|
|
|
|
DBusConnection *owner)
|
|
|
|
|
{
|
|
|
|
|
DBusList *link;
|
|
|
|
|
|
|
|
|
|
link = _dbus_list_get_first_link (&service->owners);
|
|
|
|
|
|
|
|
|
|
while (link != NULL)
|
|
|
|
|
{
|
|
|
|
|
if (link->data == owner)
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
link = _dbus_list_get_next_link (&service->owners, link);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|