1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* bus.c message bus context object
4 * Copyright (C) 2003 Red Hat, Inc.
6 * Licensed under the Academic Free License version 1.2
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "activation.h"
27 #include "connection.h"
31 #include "config-parser.h"
32 #include <dbus/dbus-list.h>
33 #include <dbus/dbus-hash.h>
34 #include <dbus/dbus-internals.h>
41 BusConnections *connections;
42 BusActivation *activation;
43 BusRegistry *registry;
44 DBusList *default_rules; /**< Default policy rules */
45 DBusList *mandatory_rules; /**< Mandatory policy rules */
46 DBusHashTable *rules_by_uid; /**< per-UID policy rules */
47 DBusHashTable *rules_by_gid; /**< per-GID policy rules */
51 server_watch_callback (DBusWatch *watch,
52 unsigned int condition,
55 DBusServer *server = data;
57 return dbus_server_handle_watch (server, watch, condition);
61 add_server_watch (DBusWatch *watch,
64 return bus_loop_add_watch (watch, server_watch_callback, data,
69 remove_server_watch (DBusWatch *watch,
72 bus_loop_remove_watch (watch, server_watch_callback, data);
77 server_timeout_callback (DBusTimeout *timeout,
80 /* can return FALSE on OOM but we just let it fire again later */
81 dbus_timeout_handle (timeout);
85 add_server_timeout (DBusTimeout *timeout,
88 return bus_loop_add_timeout (timeout, server_timeout_callback, data, NULL);
92 remove_server_timeout (DBusTimeout *timeout,
95 bus_loop_remove_timeout (timeout, server_timeout_callback, data);
99 new_connection_callback (DBusServer *server,
100 DBusConnection *new_connection,
103 BusContext *context = data;
105 if (!bus_connections_setup_connection (context->connections, new_connection))
107 _dbus_verbose ("No memory to setup new connection\n");
109 /* if we don't do this, it will get unref'd without
110 * being disconnected... kind of strange really
111 * that we have to do this, people won't get it right
114 dbus_connection_disconnect (new_connection);
117 /* on OOM, we won't have ref'd the connection so it will die. */
121 free_rule_func (void *data,
124 BusPolicyRule *rule = data;
126 bus_policy_rule_unref (rule);
130 free_rule_list_func (void *data)
132 DBusList **list = data;
134 _dbus_list_foreach (list, free_rule_func, NULL);
136 _dbus_list_clear (list);
142 setup_server (BusContext *context,
144 char **auth_mechanisms,
147 if (!dbus_server_set_auth_mechanisms (server, (const char**) auth_mechanisms))
153 dbus_server_set_new_connection_function (server,
154 new_connection_callback,
157 if (!dbus_server_set_watch_functions (server,
168 if (!dbus_server_set_timeout_functions (server,
170 remove_server_timeout,
182 bus_context_new (const DBusString *config_file,
187 DBusList **addresses;
188 BusConfigParser *parser;
189 DBusString full_address;
191 char **auth_mechanisms;
192 DBusList **auth_mechanisms_list;
195 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
197 if (!_dbus_string_init (&full_address))
202 auth_mechanisms = NULL;
204 parser = bus_config_load (config_file, error);
208 context = dbus_new0 (BusContext, 1);
215 context->refcount = 1;
217 /* Build an array of auth mechanisms */
219 auth_mechanisms_list = bus_config_parser_get_mechanisms (parser);
220 len = _dbus_list_get_length (auth_mechanisms_list);
226 auth_mechanisms = dbus_new0 (char*, len + 1);
227 if (auth_mechanisms == NULL)
231 link = _dbus_list_get_first_link (auth_mechanisms_list);
234 auth_mechanisms[i] = _dbus_strdup (link->data);
235 if (auth_mechanisms[i] == NULL)
237 link = _dbus_list_get_next_link (auth_mechanisms_list, link);
242 auth_mechanisms = NULL;
245 /* Listen on our addresses */
247 addresses = bus_config_parser_get_addresses (parser);
249 link = _dbus_list_get_first_link (addresses);
254 server = dbus_server_listen (link->data, error);
257 else if (!setup_server (context, server, auth_mechanisms, error))
260 if (!_dbus_list_append (&context->servers, server))
266 link = _dbus_list_get_next_link (addresses, link);
269 /* Here we change our credentials if required,
270 * as soon as we've set up our sockets
272 user = bus_config_parser_get_user (parser);
275 DBusCredentials creds;
278 _dbus_string_init_const (&u, user);
280 if (!_dbus_credentials_from_username (&u, &creds) ||
284 dbus_set_error (error, DBUS_ERROR_FAILED,
285 "Could not get UID and GID for username \"%s\"",
290 if (!_dbus_change_identity (creds.uid, creds.gid, error))
294 /* We have to build the address backward, so that
295 * <listen> later in the config file have priority
297 link = _dbus_list_get_last_link (&context->servers);
302 addr = dbus_server_get_address (link->data);
309 if (_dbus_string_get_length (&full_address) > 0)
311 if (!_dbus_string_append (&full_address, ";"))
318 if (!_dbus_string_append (&full_address, addr))
326 link = _dbus_list_get_prev_link (&context->servers, link);
329 if (!_dbus_string_copy_data (&full_address, &context->address))
335 /* Create activation subsystem */
337 context->activation = bus_activation_new (context, &full_address,
338 bus_config_parser_get_service_dirs (parser),
340 if (context->activation == NULL)
342 _DBUS_ASSERT_ERROR_IS_SET (error);
346 context->connections = bus_connections_new (context);
347 if (context->connections == NULL)
353 context->registry = bus_registry_new (context);
354 if (context->registry == NULL)
360 context->rules_by_uid = _dbus_hash_table_new (DBUS_HASH_ULONG,
362 free_rule_list_func);
363 if (context->rules_by_uid == NULL)
369 context->rules_by_gid = _dbus_hash_table_new (DBUS_HASH_ULONG,
371 free_rule_list_func);
372 if (context->rules_by_gid == NULL)
378 /* Now become a daemon if appropriate */
379 if (bus_config_parser_get_fork (parser))
381 if (!_dbus_become_daemon (error))
385 bus_config_parser_unref (parser);
386 _dbus_string_free (&full_address);
387 dbus_free_string_array (auth_mechanisms);
393 bus_config_parser_unref (parser);
396 bus_context_unref (context);
398 _dbus_string_free (&full_address);
399 dbus_free_string_array (auth_mechanisms);
404 shutdown_server (BusContext *context,
407 if (server == NULL ||
408 !dbus_server_get_is_connected (server))
411 if (!dbus_server_set_watch_functions (server,
415 _dbus_assert_not_reached ("setting watch functions to NULL failed");
417 if (!dbus_server_set_timeout_functions (server,
421 _dbus_assert_not_reached ("setting timeout functions to NULL failed");
423 dbus_server_disconnect (server);
427 bus_context_shutdown (BusContext *context)
431 link = _dbus_list_get_first_link (&context->servers);
434 shutdown_server (context, link->data);
436 link = _dbus_list_get_next_link (&context->servers, link);
441 bus_context_ref (BusContext *context)
443 _dbus_assert (context->refcount > 0);
444 context->refcount += 1;
448 bus_context_unref (BusContext *context)
450 _dbus_assert (context->refcount > 0);
451 context->refcount -= 1;
453 if (context->refcount == 0)
457 _dbus_verbose ("Finalizing bus context %p\n", context);
459 bus_context_shutdown (context);
461 if (context->connections)
463 bus_connections_unref (context->connections);
464 context->connections = NULL;
467 if (context->registry)
469 bus_registry_unref (context->registry);
470 context->registry = NULL;
473 if (context->activation)
475 bus_activation_unref (context->activation);
476 context->activation = NULL;
479 link = _dbus_list_get_first_link (&context->servers);
482 dbus_server_unref (link->data);
484 link = _dbus_list_get_next_link (&context->servers, link);
486 _dbus_list_clear (&context->servers);
488 if (context->rules_by_uid)
490 _dbus_hash_table_unref (context->rules_by_uid);
491 context->rules_by_uid = NULL;
494 if (context->rules_by_gid)
496 _dbus_hash_table_unref (context->rules_by_gid);
497 context->rules_by_gid = NULL;
500 dbus_free (context->address);
506 bus_context_get_registry (BusContext *context)
508 return context->registry;
512 bus_context_get_connections (BusContext *context)
514 return context->connections;
518 bus_context_get_activation (BusContext *context)
520 return context->activation;
524 list_allows_user (dbus_bool_t def,
527 const unsigned long *group_ids,
535 link = _dbus_list_get_first_link (list);
538 BusPolicyRule *rule = link->data;
539 link = _dbus_list_get_next_link (list, link);
541 if (rule->type == BUS_POLICY_RULE_USER)
543 if (rule->d.user.uid != uid)
546 else if (rule->type == BUS_POLICY_RULE_GROUP)
551 while (i < n_group_ids)
553 if (rule->d.group.gid == group_ids[i])
558 if (i == n_group_ids)
564 allowed = rule->allow;
571 bus_context_allow_user (BusContext *context,
575 unsigned long *group_ids;
578 /* On OOM or error we always reject the user */
579 if (!_dbus_get_groups (uid, &group_ids, &n_group_ids))
581 _dbus_verbose ("Did not get any groups for UID %lu\n",
588 allowed = list_allows_user (allowed,
589 &context->default_rules,
591 group_ids, n_group_ids);
593 allowed = list_allows_user (allowed,
594 &context->mandatory_rules,
596 group_ids, n_group_ids);
598 dbus_free (group_ids);
604 add_list_to_policy (DBusList **list,
609 link = _dbus_list_get_first_link (list);
612 BusPolicyRule *rule = link->data;
613 link = _dbus_list_get_next_link (list, link);
617 case BUS_POLICY_RULE_USER:
618 case BUS_POLICY_RULE_GROUP:
619 /* These aren't per-connection policies */
622 case BUS_POLICY_RULE_OWN:
623 case BUS_POLICY_RULE_SEND:
624 case BUS_POLICY_RULE_RECEIVE:
625 /* These are per-connection */
626 if (!bus_policy_append_rule (policy, rule))
636 bus_context_create_connection_policy (BusContext *context,
637 DBusConnection *connection)
643 _dbus_assert (dbus_connection_get_is_authenticated (connection));
645 policy = bus_policy_new ();
649 if (!add_list_to_policy (&context->default_rules,
653 /* we avoid the overhead of looking up user's groups
654 * if we don't have any group rules anyway
656 if (_dbus_hash_table_get_n_entries (context->rules_by_gid) > 0)
658 const unsigned long *groups;
662 if (!bus_connection_get_groups (connection, &groups, &n_groups))
668 list = _dbus_hash_table_lookup_ulong (context->rules_by_gid,
673 if (!add_list_to_policy (list, policy))
681 if (!dbus_connection_get_unix_user (connection, &uid))
684 list = _dbus_hash_table_lookup_ulong (context->rules_by_uid,
687 if (!add_list_to_policy (list, policy))
690 if (!add_list_to_policy (&context->mandatory_rules,
694 bus_policy_optimize (policy);
699 bus_policy_unref (policy);