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>
43 BusConnections *connections;
44 BusActivation *activation;
45 BusRegistry *registry;
46 DBusList *default_rules; /**< Default policy rules */
47 DBusList *mandatory_rules; /**< Mandatory policy rules */
48 DBusHashTable *rules_by_uid; /**< per-UID policy rules */
49 DBusHashTable *rules_by_gid; /**< per-GID policy rules */
52 static int server_data_slot = -1;
53 static int server_data_slot_refcount = 0;
60 #define BUS_SERVER_DATA(server) (dbus_server_get_data ((server), server_data_slot))
63 server_data_slot_ref (void)
65 if (server_data_slot < 0)
67 server_data_slot = dbus_server_allocate_data_slot ();
69 if (server_data_slot < 0)
72 _dbus_assert (server_data_slot_refcount == 0);
75 server_data_slot_refcount += 1;
81 server_data_slot_unref (void)
83 _dbus_assert (server_data_slot_refcount > 0);
85 server_data_slot_refcount -= 1;
87 if (server_data_slot_refcount == 0)
89 dbus_server_free_data_slot (server_data_slot);
90 server_data_slot = -1;
95 server_get_context (DBusServer *server)
100 if (!server_data_slot_ref ())
103 bd = BUS_SERVER_DATA (server);
107 context = bd->context;
109 server_data_slot_unref ();
115 server_watch_callback (DBusWatch *watch,
116 unsigned int condition,
119 DBusServer *server = data;
121 return dbus_server_handle_watch (server, watch, condition);
125 add_server_watch (DBusWatch *watch,
128 DBusServer *server = data;
131 context = server_get_context (server);
133 return bus_loop_add_watch (context->loop,
134 watch, server_watch_callback, server,
139 remove_server_watch (DBusWatch *watch,
142 DBusServer *server = data;
145 context = server_get_context (server);
147 bus_loop_remove_watch (context->loop,
148 watch, server_watch_callback, server);
153 server_timeout_callback (DBusTimeout *timeout,
156 /* can return FALSE on OOM but we just let it fire again later */
157 dbus_timeout_handle (timeout);
161 add_server_timeout (DBusTimeout *timeout,
164 DBusServer *server = data;
167 context = server_get_context (server);
169 return bus_loop_add_timeout (context->loop,
170 timeout, server_timeout_callback, server, NULL);
174 remove_server_timeout (DBusTimeout *timeout,
177 DBusServer *server = data;
180 context = server_get_context (server);
182 bus_loop_remove_timeout (context->loop,
183 timeout, server_timeout_callback, server);
187 new_connection_callback (DBusServer *server,
188 DBusConnection *new_connection,
191 BusContext *context = data;
193 if (!bus_connections_setup_connection (context->connections, new_connection))
195 _dbus_verbose ("No memory to setup new connection\n");
197 /* if we don't do this, it will get unref'd without
198 * being disconnected... kind of strange really
199 * that we have to do this, people won't get it right
202 dbus_connection_disconnect (new_connection);
205 /* on OOM, we won't have ref'd the connection so it will die. */
209 free_rule_func (void *data,
212 BusPolicyRule *rule = data;
214 bus_policy_rule_unref (rule);
218 free_rule_list_func (void *data)
220 DBusList **list = data;
222 _dbus_list_foreach (list, free_rule_func, NULL);
224 _dbus_list_clear (list);
230 free_server_data (void *data)
232 BusServerData *bd = data;
238 setup_server (BusContext *context,
240 char **auth_mechanisms,
245 if (!dbus_server_set_auth_mechanisms (server, (const char**) auth_mechanisms))
251 dbus_server_set_new_connection_function (server,
252 new_connection_callback,
255 if (!dbus_server_set_watch_functions (server,
266 if (!dbus_server_set_timeout_functions (server,
268 remove_server_timeout,
276 bd = dbus_new0 (BusServerData, 1);
277 if (!dbus_server_set_data (server,
279 bd, free_server_data))
285 bd->context = context;
291 bus_context_new (const DBusString *config_file,
296 DBusList **addresses;
297 BusConfigParser *parser;
298 DBusString full_address;
300 char **auth_mechanisms;
301 DBusList **auth_mechanisms_list;
304 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
306 if (!_dbus_string_init (&full_address))
312 if (!server_data_slot_ref ())
315 _dbus_string_free (&full_address);
321 auth_mechanisms = NULL;
323 parser = bus_config_load (config_file, error);
327 context = dbus_new0 (BusContext, 1);
334 context->refcount = 1;
336 context->loop = bus_loop_new ();
337 if (context->loop == NULL)
343 /* Build an array of auth mechanisms */
345 auth_mechanisms_list = bus_config_parser_get_mechanisms (parser);
346 len = _dbus_list_get_length (auth_mechanisms_list);
352 auth_mechanisms = dbus_new0 (char*, len + 1);
353 if (auth_mechanisms == NULL)
357 link = _dbus_list_get_first_link (auth_mechanisms_list);
360 auth_mechanisms[i] = _dbus_strdup (link->data);
361 if (auth_mechanisms[i] == NULL)
363 link = _dbus_list_get_next_link (auth_mechanisms_list, link);
368 auth_mechanisms = NULL;
371 /* Listen on our addresses */
373 addresses = bus_config_parser_get_addresses (parser);
375 link = _dbus_list_get_first_link (addresses);
380 server = dbus_server_listen (link->data, error);
383 else if (!setup_server (context, server, auth_mechanisms, error))
386 if (!_dbus_list_append (&context->servers, server))
392 link = _dbus_list_get_next_link (addresses, link);
395 /* Here we change our credentials if required,
396 * as soon as we've set up our sockets
398 user = bus_config_parser_get_user (parser);
401 DBusCredentials creds;
404 _dbus_string_init_const (&u, user);
406 if (!_dbus_credentials_from_username (&u, &creds) ||
410 dbus_set_error (error, DBUS_ERROR_FAILED,
411 "Could not get UID and GID for username \"%s\"",
416 if (!_dbus_change_identity (creds.uid, creds.gid, error))
420 /* note that type may be NULL */
421 context->type = _dbus_strdup (bus_config_parser_get_type (parser));
423 /* We have to build the address backward, so that
424 * <listen> later in the config file have priority
426 link = _dbus_list_get_last_link (&context->servers);
431 addr = dbus_server_get_address (link->data);
438 if (_dbus_string_get_length (&full_address) > 0)
440 if (!_dbus_string_append (&full_address, ";"))
447 if (!_dbus_string_append (&full_address, addr))
455 link = _dbus_list_get_prev_link (&context->servers, link);
458 if (!_dbus_string_copy_data (&full_address, &context->address))
464 /* Create activation subsystem */
466 context->activation = bus_activation_new (context, &full_address,
467 bus_config_parser_get_service_dirs (parser),
469 if (context->activation == NULL)
471 _DBUS_ASSERT_ERROR_IS_SET (error);
475 context->connections = bus_connections_new (context);
476 if (context->connections == NULL)
482 context->registry = bus_registry_new (context);
483 if (context->registry == NULL)
489 context->rules_by_uid = _dbus_hash_table_new (DBUS_HASH_ULONG,
491 free_rule_list_func);
492 if (context->rules_by_uid == NULL)
498 context->rules_by_gid = _dbus_hash_table_new (DBUS_HASH_ULONG,
500 free_rule_list_func);
501 if (context->rules_by_gid == NULL)
507 /* Now become a daemon if appropriate */
508 if (bus_config_parser_get_fork (parser))
510 if (!_dbus_become_daemon (error))
514 bus_config_parser_unref (parser);
515 _dbus_string_free (&full_address);
516 dbus_free_string_array (auth_mechanisms);
522 bus_config_parser_unref (parser);
525 bus_context_unref (context);
527 _dbus_string_free (&full_address);
528 dbus_free_string_array (auth_mechanisms);
530 server_data_slot_unref ();
536 shutdown_server (BusContext *context,
539 if (server == NULL ||
540 !dbus_server_get_is_connected (server))
543 if (!dbus_server_set_watch_functions (server,
547 _dbus_assert_not_reached ("setting watch functions to NULL failed");
549 if (!dbus_server_set_timeout_functions (server,
553 _dbus_assert_not_reached ("setting timeout functions to NULL failed");
555 dbus_server_disconnect (server);
559 bus_context_shutdown (BusContext *context)
563 link = _dbus_list_get_first_link (&context->servers);
566 shutdown_server (context, link->data);
568 link = _dbus_list_get_next_link (&context->servers, link);
573 bus_context_ref (BusContext *context)
575 _dbus_assert (context->refcount > 0);
576 context->refcount += 1;
580 bus_context_unref (BusContext *context)
582 _dbus_assert (context->refcount > 0);
583 context->refcount -= 1;
585 if (context->refcount == 0)
589 _dbus_verbose ("Finalizing bus context %p\n", context);
591 bus_context_shutdown (context);
593 if (context->connections)
595 bus_connections_unref (context->connections);
596 context->connections = NULL;
599 if (context->registry)
601 bus_registry_unref (context->registry);
602 context->registry = NULL;
605 if (context->activation)
607 bus_activation_unref (context->activation);
608 context->activation = NULL;
611 link = _dbus_list_get_first_link (&context->servers);
614 dbus_server_unref (link->data);
616 link = _dbus_list_get_next_link (&context->servers, link);
618 _dbus_list_clear (&context->servers);
620 if (context->rules_by_uid)
622 _dbus_hash_table_unref (context->rules_by_uid);
623 context->rules_by_uid = NULL;
626 if (context->rules_by_gid)
628 _dbus_hash_table_unref (context->rules_by_gid);
629 context->rules_by_gid = NULL;
634 bus_loop_unref (context->loop);
635 context->loop = NULL;
638 dbus_free (context->type);
639 dbus_free (context->address);
642 server_data_slot_unref ();
646 /* type may be NULL */
648 bus_context_get_type (BusContext *context)
650 return context->type;
654 bus_context_get_registry (BusContext *context)
656 return context->registry;
660 bus_context_get_connections (BusContext *context)
662 return context->connections;
666 bus_context_get_activation (BusContext *context)
668 return context->activation;
672 bus_context_get_loop (BusContext *context)
674 return context->loop;
678 list_allows_user (dbus_bool_t def,
681 const unsigned long *group_ids,
689 link = _dbus_list_get_first_link (list);
692 BusPolicyRule *rule = link->data;
693 link = _dbus_list_get_next_link (list, link);
695 if (rule->type == BUS_POLICY_RULE_USER)
697 if (rule->d.user.uid != uid)
700 else if (rule->type == BUS_POLICY_RULE_GROUP)
705 while (i < n_group_ids)
707 if (rule->d.group.gid == group_ids[i])
712 if (i == n_group_ids)
718 allowed = rule->allow;
725 bus_context_allow_user (BusContext *context,
729 unsigned long *group_ids;
732 /* On OOM or error we always reject the user */
733 if (!_dbus_get_groups (uid, &group_ids, &n_group_ids))
735 _dbus_verbose ("Did not get any groups for UID %lu\n",
742 allowed = list_allows_user (allowed,
743 &context->default_rules,
745 group_ids, n_group_ids);
747 allowed = list_allows_user (allowed,
748 &context->mandatory_rules,
750 group_ids, n_group_ids);
752 dbus_free (group_ids);
758 add_list_to_policy (DBusList **list,
763 link = _dbus_list_get_first_link (list);
766 BusPolicyRule *rule = link->data;
767 link = _dbus_list_get_next_link (list, link);
771 case BUS_POLICY_RULE_USER:
772 case BUS_POLICY_RULE_GROUP:
773 /* These aren't per-connection policies */
776 case BUS_POLICY_RULE_OWN:
777 case BUS_POLICY_RULE_SEND:
778 case BUS_POLICY_RULE_RECEIVE:
779 /* These are per-connection */
780 if (!bus_policy_append_rule (policy, rule))
790 bus_context_create_connection_policy (BusContext *context,
791 DBusConnection *connection)
797 _dbus_assert (dbus_connection_get_is_authenticated (connection));
799 policy = bus_policy_new ();
803 if (!add_list_to_policy (&context->default_rules,
807 /* we avoid the overhead of looking up user's groups
808 * if we don't have any group rules anyway
810 if (_dbus_hash_table_get_n_entries (context->rules_by_gid) > 0)
812 const unsigned long *groups;
816 if (!bus_connection_get_groups (connection, &groups, &n_groups))
822 list = _dbus_hash_table_lookup_ulong (context->rules_by_gid,
827 if (!add_list_to_policy (list, policy))
835 if (!dbus_connection_get_unix_user (connection, &uid))
838 list = _dbus_hash_table_lookup_ulong (context->rules_by_uid,
841 if (!add_list_to_policy (list, policy))
844 if (!add_list_to_policy (&context->mandatory_rules,
848 bus_policy_optimize (policy);
853 bus_policy_unref (policy);