diff options
author | David Zeuthen <davidz@redhat.com> | 2007-03-25 15:37:29 -0400 |
---|---|---|
committer | David Zeuthen <davidz@redhat.com> | 2007-03-25 15:37:29 -0400 |
commit | f7cb7e7828ae6d54f06dad49b63b0f8c0a553a41 (patch) | |
tree | d569dbd93ffb4ec9da5dbcc5a30682196a4e811b | |
parent | 77770b83f17122ba6ddb6b4cd484291a90d647d1 (diff) |
refactor access control checks into separate files
-rw-r--r-- | hald/Makefile.am | 3 | ||||
-rw-r--r-- | hald/access-check.c | 171 | ||||
-rw-r--r-- | hald/access-check.h | 40 | ||||
-rw-r--r-- | hald/hald_dbus.c | 330 |
4 files changed, 325 insertions, 219 deletions
diff --git a/hald/Makefile.am b/hald/Makefile.am index f6e7751c..1ca01aca 100644 --- a/hald/Makefile.am +++ b/hald/Makefile.am @@ -61,7 +61,8 @@ hald_SOURCES = \ ids.h ids.c \ rule.h mmap_cache.c \ mmap_cache.h \ - ci-tracker.h ci-tracker.c + ci-tracker.h ci-tracker.c \ + access-check.h access-check.c if HAVE_CONKIT hald_SOURCES += ck-tracker.h ck-tracker.c diff --git a/hald/access-check.c b/hald/access-check.c new file mode 100644 index 00000000..b001eeaa --- /dev/null +++ b/hald/access-check.c @@ -0,0 +1,171 @@ +/*************************************************************************** + * CVSID: $Id$ + * + * access-check.c : Checks whether a D-Bus caller have access + * + * Copyright (C) 2007 David Zeuthen, <david@fubar.dk> + * + * Licensed under the Academic Free License version 2.1 + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + **************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <stdarg.h> +#include <stdint.h> +#include <sys/time.h> + +#include <dbus/dbus.h> +#include <glib.h> + +#include "logger.h" +#include "access-check.h" + +/** + * access_check_caller_is_root_or_hal: + * @cit: the CITracker object + * @caller_unique_sysbus_name: The unique system bus connection name (e.g. ":1.43") of the caller + * + * Check if the caller has uid 0 (root) or the uid of the hal user. + * + * Returns: TRUE iff the caller has uid 0 (root) or the uid of the hal user. + */ +gboolean +access_check_caller_is_root_or_hal (CITracker *cit, const char *caller_unique_sysbus_name) +{ + gboolean ret; + CICallerInfo *ci; + + ret = FALSE; + + ci = ci_tracker_get_info (cit, caller_unique_sysbus_name); + if (ci == NULL) { + goto out; + } + + HAL_INFO (("uid for caller is %ld", ci_tracker_caller_get_uid (ci))); + + if (ci_tracker_caller_get_uid (ci) != 0 && ci_tracker_caller_get_uid (ci) != geteuid ()) { + HAL_WARNING (("uid %d is not privileged", ci_tracker_caller_get_uid (ci))); + goto out; + } + + ret = TRUE; + +out: + return ret; +} + +/** + * access_check_message_caller_is_root_or_hal: + * @cit: the CITracker object + * @message: the message from the caller + * + * Check if the sender of the message has uid 0 (root) or the uid of the hal user. + * + * Returns: TRUE iff the sender of the message has uid 0 (root) or the uid of the hal user. + */ +gboolean +access_check_message_caller_is_root_or_hal (CITracker *cit, DBusMessage *message) +{ + gboolean ret; + const char *user_base_svc; + + ret = FALSE; + + user_base_svc = dbus_message_get_sender (message); + if (user_base_svc == NULL) { + HAL_WARNING (("Cannot determine base service of caller")); + goto out; + } + + ret = access_check_caller_is_root_or_hal (cit, user_base_svc); + +out: + return ret; +} + +/** + * access_check_caller_have_access_to_device: + * @device: The device to check for + * @caller_unique_sysbus_name: The unique system bus connection name (e.g. ":1.43") of the caller + * + * Determine if a given caller should have access to a device. This + * depends on how the security is set up and may change according to + * how the system is configured. + * + * If ConsoleKit is used this function currently will return TRUE if, + * and only if, the caller is in an active session. TODO: once + * multi-seat is properly supported it will also depend on what seat + * the device belongs to and what seat the caller's session belongs + * to. + * + * If ConsoleKit is not used, this function will just return TRUE; the + * OS vendor is supposed to have locked down access to HAL through OS + * specific mechanisms and/or D-Bus security configuration directives. + * + * By convention uid 0 and the hal user will have access to all + * devices. + * + * Returns: TRUE iff the caller have access to the device. + */ +gboolean +access_check_caller_have_access_to_device (CITracker *cit, HalDevice *device, const char *caller_unique_sysbus_name) +#ifdef HAVE_CONKIT +{ + gboolean ret; + CICallerInfo *ci; + + ret = FALSE; + + ci = ci_tracker_get_info (cit, caller_unique_sysbus_name); + if (ci == NULL) { + HAL_ERROR (("Cannot get caller info for %s", caller_unique_sysbus_name)); + goto out; + } + + if (ci_tracker_caller_get_uid (ci) == 0 || + ci_tracker_caller_get_uid (ci) == geteuid ()) { + ret = TRUE; + goto out; + } + + if (ci_tracker_caller_get_ck_session_path (ci) == NULL) { + goto out; + } + + + if (!ci_tracker_caller_in_active_session (ci)) { + goto out; + } + + ret = TRUE; +out: + return ret; + +} +#else /* HAVE_CONKIT */ +{ + return TRUE; +} +#endif diff --git a/hald/access-check.h b/hald/access-check.h new file mode 100644 index 00000000..8514824a --- /dev/null +++ b/hald/access-check.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * CVSID: $Id$ + * + * access-check.h : Checks whether a D-Bus caller have access + * + * Copyright (C) 2007 David Zeuthen, <david@fubar.dk> + * + * Licensed under the Academic Free License version 2.1 + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + **************************************************************************/ + +#ifndef ACCESS_CHECK_H +#define ACCESS_CHECK_H + +#include "device.h" +#include "ci-tracker.h" + +gboolean access_check_caller_is_root_or_hal (CITracker *cit, + const char *caller_unique_sysbus_name); +gboolean access_check_message_caller_is_root_or_hal (CITracker *cit, + DBusMessage *message); +gboolean access_check_caller_have_access_to_device (CITracker *cit, + HalDevice *device, + const char *caller_unique_sysbus_name); + +#endif /* ACCESS_CHECK_H */ diff --git a/hald/hald_dbus.c b/hald/hald_dbus.c index 6c97862c..798e093e 100644 --- a/hald/hald_dbus.c +++ b/hald/hald_dbus.c @@ -47,8 +47,8 @@ #include "osspec.h" #include "util.h" #include "hald_runner.h" - #include "ci-tracker.h" +#include "access-check.h" #ifdef HAVE_CONKIT #include "ck-tracker.h" @@ -933,43 +933,7 @@ device_get_all_properties (DBusConnection * connection, return DBUS_HANDLER_RESULT_HANDLED; } -static dbus_bool_t -sender_has_privileges (DBusConnection *connection, DBusMessage *message) -{ - const char *user_base_svc; - dbus_bool_t ret; - CICallerInfo *ci; - - ret = FALSE; - - user_base_svc = dbus_message_get_sender (message); - if (user_base_svc == NULL) { - HAL_WARNING (("Cannot determine base service of caller")); - goto out; - } - - HAL_DEBUG (("base_svc = %s", user_base_svc)); - - ci = ci_tracker_get_info (ci_tracker, user_base_svc); - if (ci == NULL) { - goto out; - } - - HAL_INFO (("uid for caller is %ld", ci_tracker_caller_get_uid (ci))); - - if (ci_tracker_caller_get_uid (ci) != 0 && ci_tracker_caller_get_uid (ci) != geteuid()) { - HAL_WARNING (("uid %d is not privileged", ci_tracker_caller_get_uid (ci))); - goto out; - } - - ret = TRUE; - -out: - return ret; -} - - -/** * +/** * device_set_multiple_properties: * @connection: D-BUS connection * @message: Message @@ -1007,7 +971,7 @@ device_set_multiple_properties (DBusConnection *connection, DBusMessage *message return DBUS_HANDLER_RESULT_HANDLED; } - if (!local_interface && !sender_has_privileges (connection, message)) { + if (!local_interface && !access_check_message_caller_is_root_or_hal (ci_tracker, message)) { raise_permission_denied (connection, message, "SetProperty: not privileged"); return DBUS_HANDLER_RESULT_HANDLED; } @@ -1377,7 +1341,7 @@ device_set_property (DBusConnection * connection, DBusMessage * message, dbus_bo } dbus_message_iter_get_basic (&iter, &key); - if (!local_interface && !sender_has_privileges (connection, message)) { + if (!local_interface && !access_check_message_caller_is_root_or_hal (ci_tracker, message)) { raise_permission_denied (connection, message, "SetProperty: not privileged"); return DBUS_HANDLER_RESULT_HANDLED; } @@ -1497,7 +1461,7 @@ device_add_capability (DBusConnection * connection, DBusMessage * message, dbus_ HAL_TRACE (("entering")); - if (!local_interface && !sender_has_privileges (connection, message)) { + if (!local_interface && !access_check_message_caller_is_root_or_hal (ci_tracker, message)) { raise_permission_denied (connection, message, "AddCapability: not privileged"); return DBUS_HANDLER_RESULT_HANDLED; } @@ -1673,7 +1637,7 @@ device_remove_property (DBusConnection * connection, DBusMessage * message, dbus udi = dbus_message_get_path (message); - if (!local_interface && !sender_has_privileges (connection, message)) { + if (!local_interface && !access_check_message_caller_is_root_or_hal (ci_tracker, message)) { raise_permission_denied (connection, message, "RemoveProperty: not privileged"); return DBUS_HANDLER_RESULT_HANDLED; } @@ -2457,7 +2421,7 @@ device_rescan (DBusConnection * connection, DBusMessage * message, dbus_bool_t l udi = dbus_message_get_path (message); - if (!local_interface && !sender_has_privileges (connection, message)) { + if (!local_interface && !access_check_message_caller_is_root_or_hal (ci_tracker, message)) { raise_permission_denied (connection, message, "Rescan: not privileged"); return DBUS_HANDLER_RESULT_HANDLED; } @@ -2501,7 +2465,7 @@ device_reprobe (DBusConnection * connection, DBusMessage * message, dbus_bool_t udi = dbus_message_get_path (message); - if (!local_interface && !sender_has_privileges (connection, message)) { + if (!local_interface && !access_check_message_caller_is_root_or_hal (ci_tracker, message)) { raise_permission_denied (connection, message, "Reprobe: not privileged"); return DBUS_HANDLER_RESULT_HANDLED; } @@ -2752,7 +2716,7 @@ manager_new_device (DBusConnection * connection, DBusMessage * message, dbus_boo dbus_error_init (&error); - if (!local_interface && !sender_has_privileges (connection, message)) { + if (!local_interface && !access_check_message_caller_is_root_or_hal (ci_tracker, message)) { raise_permission_denied (connection, message, "NewDevice: not privileged"); return DBUS_HANDLER_RESULT_HANDLED; } @@ -2821,7 +2785,7 @@ manager_remove (DBusConnection * connection, DBusMessage * message, dbus_bool_t dbus_error_init (&error); - if (!local_interface && !sender_has_privileges (connection, message)) { + if (!local_interface && !access_check_message_caller_is_root_or_hal (ci_tracker, message)) { raise_permission_denied (connection, message, "Remove: not privileged"); return DBUS_HANDLER_RESULT_HANDLED; } @@ -2922,7 +2886,7 @@ manager_commit_to_gdl (DBusConnection * connection, DBusMessage * message, dbus_ dbus_error_init (&error); - if (!local_interface && !sender_has_privileges (connection, message)) { + if (!local_interface && !access_check_message_caller_is_root_or_hal (ci_tracker, message)) { raise_permission_denied (connection, message, "CommitToGdl: not privileged"); return DBUS_HANDLER_RESULT_HANDLED; } @@ -3266,42 +3230,6 @@ hald_exec_method (HalDevice *d, CICallerInfo *ci, DBusConnection *connection, db extra_env[0] = "HAL_METHOD_INVOKED_BY_UID=0"; extra_env[1] = "HAL_METHOD_INVOKED_BY_SYSTEMBUS_CONNECTION_NAME=0"; } else { - -#ifdef HAVE_CONKIT - /* TODO: we probably should let the handler itself decide if it wants - * to service the session... by e.g. exporting some env variables - * set from the CICallerInfo object - */ - if (ci_tracker_caller_get_uid (ci) != 0) { - if (ci_tracker_caller_get_ck_session_path (ci) == NULL) { - HAL_INFO (("Caller %s (uid %d, pid %d) for interface %s on exec'ed method %s for %s " - "is not in any session; refusing service", - dbus_message_get_sender (message), - ci_tracker_caller_get_uid (ci), - ci_tracker_caller_get_pid (ci), - dbus_message_get_interface (message), - dbus_message_get_member (message), - dbus_message_get_path (message))); - raise_permission_denied (connection, message, "Not in active session"); - goto out; - } - - if (!ci_tracker_caller_in_active_session (ci)) { - HAL_INFO (("Caller %s (uid %d, pid %d) for interface %s on exec'ed method %s for %s " - "is not in an active session (%s); refusing service", - dbus_message_get_sender (message), - ci_tracker_caller_get_uid (ci), - ci_tracker_caller_get_pid (ci), - dbus_message_get_interface (message), - dbus_message_get_member (message), - dbus_message_get_path (message), - ci_tracker_caller_get_ck_session_path (ci))); - raise_permission_denied (connection, message, "Not in active session"); - goto out; - } - } -#endif /* HAVE_CONKIT */ - sprintf (uid_export, "HAL_METHOD_INVOKED_BY_UID=%u", ci_tracker_caller_get_uid (ci)); extra_env[0] = uid_export; snprintf (sender_export, sizeof (sender_export), @@ -3431,9 +3359,6 @@ hald_exec_method (HalDevice *d, CICallerInfo *ci, DBusConnection *connection, db dbus_message_ref (message); g_string_free (stdin_str, TRUE); -#ifdef HAVE_CONKIT -out: -#endif return DBUS_HANDLER_RESULT_HANDLED; error: @@ -4033,8 +3958,10 @@ hald_dbus_filter_handle_methods (DBusConnection *connection, DBusMessage *messag const char *method; const char *signature; const char *caller; - CICallerInfo *ci; HalDevice *d; + GSList *i; + HalDeviceStrListIter if_iter; + CICallerInfo *ci; /* check for device-specific interfaces that individual objects may support */ @@ -4043,6 +3970,9 @@ hald_dbus_filter_handle_methods (DBusConnection *connection, DBusMessage *messag method = dbus_message_get_member (message); signature = dbus_message_get_signature (message); + if (udi == NULL || method == NULL || signature == NULL || interface == NULL) + goto out; + caller = dbus_message_get_sender (message); if (local_interface) { ci = NULL; @@ -4050,141 +3980,105 @@ hald_dbus_filter_handle_methods (DBusConnection *connection, DBusMessage *messag ci = ci_tracker_get_info (ci_tracker, caller); if (ci == NULL) { HAL_ERROR (("Cannot get caller info for %s", caller)); - goto no_caller; + goto out; } } d = NULL; - - if (udi != NULL) { - d = hal_device_store_find (hald_get_gdl (), udi); - if (d == NULL) - d = hal_device_store_find (hald_get_tdl (), udi); - } - - if (d != NULL && interface != NULL) { - GSList *i; - - for (i = helper_interface_handlers; i != NULL; i = g_slist_next (i)) { - HelperInterfaceHandler *hih = i->data; - if (strcmp (hih->udi, udi) == 0 && - strcmp (hih->interface_name, interface) == 0) { - DBusPendingCall *pending_call; - DBusMessage *copy; - -#ifdef HAVE_CONKIT - /* TODO: we probably should let the add-on itself decide if it wants - * to service the session... - */ - if (!local_interface && ci_tracker_caller_get_uid (ci) != 0) { - if (ci_tracker_caller_get_ck_session_path (ci) == NULL) { - HAL_INFO (("Caller %s (uid %d, pid %d) for interface %s on " - "add-on method %s for %s is not in any session; " - "refusing service", - caller, - ci_tracker_caller_get_uid (ci), - ci_tracker_caller_get_pid (ci), - interface, - method, - udi, - ci_tracker_caller_get_ck_session_path (ci))); - raise_permission_denied (connection, message, "Not in active session"); - return DBUS_HANDLER_RESULT_HANDLED; - } - - if (!ci_tracker_caller_in_active_session (ci)) { - HAL_INFO (("Caller %s (uid %d, pid %d) for interface %s on " - "add-on method %s for %s is not in an active " - "session (%s); refusing service", - caller, - ci_tracker_caller_get_uid (ci), - ci_tracker_caller_get_pid (ci), - interface, - method, - udi, - ci_tracker_caller_get_ck_session_path (ci))); - raise_permission_denied (connection, message, "Not in active session"); - return DBUS_HANDLER_RESULT_HANDLED; - } - } -#endif /* HAVE_CONKIT */ - - /*HAL_INFO (("forwarding method to connection 0x%x", hih->connection));*/ - - dbus_message_ref (message); - - /* send a copy of the message */ - copy = dbus_message_copy (message); - if (!dbus_connection_send_with_reply (hih->connection, - copy, - &pending_call, - /*-1*/ 8000)) { - /* TODO: handle error */ - } else { - /*HAL_INFO (("connection=%x message=%x", connection, message));*/ - dbus_pending_call_set_notify (pending_call, - reply_from_fwd_message, - (void *) message, - NULL); - } - - dbus_message_unref (copy); - - return DBUS_HANDLER_RESULT_HANDLED; - } - } - } - - if (d != NULL && interface != NULL && method != NULL && signature != NULL) { - HalDeviceStrListIter if_iter; - - for (hal_device_property_strlist_iter_init (d, "info.interfaces", &if_iter); - hal_device_property_strlist_iter_is_valid (&if_iter); - hal_device_property_strlist_iter_next (&if_iter)) { - const char *ifname = hal_device_property_strlist_iter_get_value (&if_iter); - - if (strcmp (ifname, interface) == 0) { - guint num; - HalDeviceStrListIter name_iter; - char *s; - - s = g_strdup_printf ("%s.method_names", interface); - hal_device_property_strlist_iter_init (d, s, &name_iter); - g_free (s); - for (num = 0; - hal_device_property_strlist_iter_is_valid (&name_iter); - hal_device_property_strlist_iter_next (&name_iter), num++) { - const char *methodname; - methodname = hal_device_property_strlist_iter_get_value (&name_iter); - if (strcmp (methodname, method) == 0) { - const char *execpath; - const char *sig; - - s = g_strdup_printf ("%s.method_execpaths", interface); - execpath = hal_device_property_get_strlist_elem (d, s, num); - g_free (s); - s = g_strdup_printf ("%s.method_signatures", interface); - sig = hal_device_property_get_strlist_elem (d, s, num); - g_free (s); - - if (execpath != NULL && sig != NULL && - strcmp (sig, signature) == 0) { - - HAL_INFO (("OK for method '%s' with signature '%s' on interface '%s' for UDI '%s' and execpath '%s'", method, signature, interface, udi, execpath)); - - return hald_exec_method (d, ci, connection, - local_interface, - message, execpath); - } - - } - } - } - } - - } - } -no_caller: + d = hal_device_store_find (hald_get_gdl (), udi); + if (d == NULL) + d = hal_device_store_find (hald_get_tdl (), udi); + if (d == NULL) + goto out; + + /* bypass security checks on direct connections */ + if (!local_interface) { + if (!access_check_caller_have_access_to_device (ci_tracker, d, caller)) { + HAL_INFO (("Caller '%s' does not have access to device '%s'", caller, udi)); + /* TODO: need to fix up reason */ + raise_permission_denied (connection, message, "Not in active session"); + return DBUS_HANDLER_RESULT_HANDLED; + } + } + + /* first see if an addon grabbed the interface */ + for (i = helper_interface_handlers; i != NULL; i = g_slist_next (i)) { + HelperInterfaceHandler *hih = i->data; + if (strcmp (hih->udi, udi) == 0 && + strcmp (hih->interface_name, interface) == 0) { + DBusPendingCall *pending_call; + DBusMessage *copy; + + /*HAL_INFO (("forwarding method to connection 0x%x", hih->connection));*/ + + dbus_message_ref (message); + + /* send a copy of the message */ + copy = dbus_message_copy (message); + if (!dbus_connection_send_with_reply (hih->connection, + copy, + &pending_call, + /*-1*/ 8000)) { + /* TODO: handle error */ + } else { + /*HAL_INFO (("connection=%x message=%x", connection, message));*/ + dbus_pending_call_set_notify (pending_call, + reply_from_fwd_message, + (void *) message, + NULL); + } + + dbus_message_unref (copy); + return DBUS_HANDLER_RESULT_HANDLED; + } + } + + /* nope, see if we have a program to run.. */ + for (hal_device_property_strlist_iter_init (d, "info.interfaces", &if_iter); + hal_device_property_strlist_iter_is_valid (&if_iter); + hal_device_property_strlist_iter_next (&if_iter)) { + const char *ifname = hal_device_property_strlist_iter_get_value (&if_iter); + + if (strcmp (ifname, interface) == 0) { + guint num; + HalDeviceStrListIter name_iter; + char *s; + + s = g_strdup_printf ("%s.method_names", interface); + hal_device_property_strlist_iter_init (d, s, &name_iter); + g_free (s); + for (num = 0; + hal_device_property_strlist_iter_is_valid (&name_iter); + hal_device_property_strlist_iter_next (&name_iter), num++) { + const char *methodname; + methodname = hal_device_property_strlist_iter_get_value (&name_iter); + if (strcmp (methodname, method) == 0) { + const char *execpath; + const char *sig; + + s = g_strdup_printf ("%s.method_execpaths", interface); + execpath = hal_device_property_get_strlist_elem (d, s, num); + g_free (s); + s = g_strdup_printf ("%s.method_signatures", interface); + sig = hal_device_property_get_strlist_elem (d, s, num); + g_free (s); + + if (execpath != NULL && sig != NULL && + strcmp (sig, signature) == 0) { + + HAL_INFO (("OK for method '%s' with signature '%s' on interface '%s' for UDI '%s' and execpath '%s'", method, signature, interface, udi, execpath)); + + return hald_exec_method (d, ci, connection, + local_interface, + message, execpath); + } + + } + } + } + } + } +out: return osspec_filter_function (connection, message, user_data); } |