summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2003-03-21 02:38:40 +0000
committerHavoc Pennington <hp@redhat.com>2003-03-21 02:38:40 +0000
commitb6ffea177fccb6cc4e65992da7d8b390054277f7 (patch)
tree5194ad93d495c110c88b7730f05b9265dd6ce73d
parent056d76d809dc341b0dce160d3f79062604565c77 (diff)
2003-03-20 Havoc Pennington <hp@redhat.com>
* dbus/dbus-connection.c (dbus_connection_set_unix_user_function): new function (dbus_connection_get_unix_user): new function
-rw-r--r--ChangeLog6
-rw-r--r--bus/bus.c47
-rw-r--r--dbus/dbus-connection.c58
-rw-r--r--dbus/dbus-connection.h12
-rw-r--r--dbus/dbus-sysdeps.c16
-rw-r--r--dbus/dbus-transport-protected.h5
-rw-r--r--dbus/dbus-transport.c111
-rw-r--r--dbus/dbus-transport.h60
-rw-r--r--doc/config-file.txt28
9 files changed, 296 insertions, 47 deletions
diff --git a/ChangeLog b/ChangeLog
index 4688cdb7..a96b97ff 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2003-03-20 Havoc Pennington <hp@redhat.com>
+
+ * dbus/dbus-connection.c (dbus_connection_set_unix_user_function):
+ new function
+ (dbus_connection_get_unix_user): new function
+
2003-03-20 Havoc Pennington <hp@pobox.com>
* bus/connection.c (bus_connection_send_oom_error): assert that
diff --git a/bus/bus.c b/bus/bus.c
index a1bc6622..4b5b23b5 100644
--- a/bus/bus.c
+++ b/bus/bus.c
@@ -27,16 +27,23 @@
#include "connection.h"
#include "services.h"
#include "utils.h"
+#include "policy.h"
+#include <dbus/dbus-list.h>
+#include <dbus/dbus-hash.h>
#include <dbus/dbus-internals.h>
struct BusContext
{
int refcount;
- char *address;
+ char *address;
DBusServer *server;
BusConnections *connections;
BusActivation *activation;
BusRegistry *registry;
+ DBusList *default_rules; /**< Default policy rules */
+ DBusList *override_rules; /**< Override policy rules */
+ DBusHashTable *rules_by_uid; /**< per-UID policy rules */
+ DBusHashTable *rules_by_gid; /**< per-GID policy rules */
};
static dbus_bool_t
@@ -109,6 +116,14 @@ new_connection_callback (DBusServer *server,
/* on OOM, we won't have ref'd the connection so it will die. */
}
+static void
+free_rule_func (void *data)
+{
+ BusPolicyRule *rule = data;
+
+ bus_policy_rule_unref (rule);
+}
+
BusContext*
bus_context_new (const char *address,
const char **service_dirs,
@@ -164,6 +179,24 @@ bus_context_new (const char *address,
goto failed;
}
+ context->rules_by_uid = _dbus_hash_table_new (DBUS_HASH_INT,
+ NULL,
+ free_rule_func);
+ if (context->rules_by_uid == NULL)
+ {
+ BUS_SET_OOM (error);
+ goto failed;
+ }
+
+ context->rules_by_gid = _dbus_hash_table_new (DBUS_HASH_INT,
+ NULL,
+ free_rule_func);
+ if (context->rules_by_gid == NULL)
+ {
+ BUS_SET_OOM (error);
+ goto failed;
+ }
+
dbus_server_set_new_connection_function (context->server,
new_connection_callback,
context, NULL);
@@ -260,6 +293,18 @@ bus_context_unref (BusContext *context)
dbus_server_unref (context->server);
context->server = NULL;
}
+
+ if (context->rules_by_uid)
+ {
+ _dbus_hash_table_unref (context->rules_by_uid);
+ context->rules_by_uid = NULL;
+ }
+
+ if (context->rules_by_gid)
+ {
+ _dbus_hash_table_unref (context->rules_by_gid);
+ context->rules_by_gid = NULL;
+ }
dbus_free (context->address);
dbus_free (context);
diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c
index d70ff716..db621405 100644
--- a/dbus/dbus-connection.c
+++ b/dbus/dbus-connection.c
@@ -2211,6 +2211,64 @@ dbus_connection_handle_watch (DBusConnection *connection,
}
/**
+ * Gets the UNIX user ID of the connection if any.
+ * Returns #TRUE if the uid is filled in.
+ * Always returns #FALSE on non-UNIX platforms.
+ *
+ * @param connection the connection
+ * @param uid return location for the user ID
+ * @returns #TRUE if uid is filled in with a valid user ID
+ */
+dbus_bool_t
+dbus_connection_get_unix_user (DBusConnection *connection,
+ unsigned long *uid)
+{
+ dbus_bool_t result;
+
+ dbus_mutex_lock (connection->mutex);
+ result = _dbus_transport_get_unix_user (connection->transport,
+ uid);
+ dbus_mutex_unlock (connection->mutex);
+
+ return result;
+}
+
+/**
+ * Sets a predicate function used to determine whether a given user ID
+ * is allowed to connect. When an incoming connection has
+ * authenticated with a particular user ID, this function is called;
+ * if it returns #TRUE, the connection is allowed to proceed,
+ * otherwise the connection is disconnected.
+ *
+ * If the function is set to #NULL (as it is by default), then
+ * only the same UID as the server process will be allowed to
+ * connect.
+ *
+ * @param connection the connection
+ * @param function the predicate
+ * @param data data to pass to the predicate
+ * @param free_data_function function to free the data
+ */
+void
+dbus_connection_set_unix_user_function (DBusConnection *connection,
+ DBusAllowUnixUserFunction function,
+ void *data,
+ DBusFreeFunction free_data_function)
+{
+ void *old_data = NULL;
+ DBusFreeFunction old_free_function = NULL;
+
+ dbus_mutex_lock (connection->mutex);
+ _dbus_transport_set_unix_user_function (connection->transport,
+ function, data, free_data_function,
+ &old_data, &old_free_function);
+ dbus_mutex_unlock (connection->mutex);
+
+ if (old_free_function != NULL)
+ (* old_free_function) (old_data);
+}
+
+/**
* Adds a message filter. Filters are handlers that are run on
* all incoming messages, prior to the normal handlers
* registered with dbus_connection_register_handler().
diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h
index 9b135a5d..21a4a15a 100644
--- a/dbus/dbus-connection.h
+++ b/dbus/dbus-connection.h
@@ -69,13 +69,16 @@ typedef void (* DBusWatchToggledFunction) (DBusWatch *watch,
void *data);
typedef void (* DBusRemoveWatchFunction) (DBusWatch *watch,
void *data);
-typedef void (* DBusWakeupMainFunction) (void *data);
typedef dbus_bool_t (* DBusAddTimeoutFunction) (DBusTimeout *timeout,
void *data);
typedef void (* DBusTimeoutToggledFunction) (DBusTimeout *timeout,
void *data);
typedef void (* DBusRemoveTimeoutFunction) (DBusTimeout *timeout,
void *data);
+typedef void (* DBusWakeupMainFunction) (void *data);
+typedef dbus_bool_t (* DBusAllowUnixUserFunction) (DBusConnection *connection,
+ unsigned long uid,
+ void *data);
DBusConnection* dbus_connection_open (const char *address,
DBusResultCode *result);
@@ -123,7 +126,12 @@ void dbus_connection_set_wakeup_main_function (DBusConnection
dbus_bool_t dbus_connection_handle_watch (DBusConnection *connection,
DBusWatch *watch,
unsigned int condition);
-
+dbus_bool_t dbus_connection_get_unix_user (DBusConnection *connection,
+ unsigned long *uid);
+void dbus_connection_set_unix_user_function (DBusConnection *connection,
+ DBusAllowUnixUserFunction function,
+ void *data,
+ DBusFreeFunction free_data_function);
int dbus_watch_get_fd (DBusWatch *watch);
unsigned int dbus_watch_get_flags (DBusWatch *watch);
diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c
index d653b868..cd4a82a5 100644
--- a/dbus/dbus-sysdeps.c
+++ b/dbus/dbus-sysdeps.c
@@ -651,6 +651,14 @@ _dbus_read_credentials_unix_socket (int client_fd,
struct cmsghdr *cmsg = (struct cmsghdr *) cmsgmem;
#endif
+ /* The POSIX spec certainly doesn't promise this, but
+ * we need these assertions to fail as soon as we're wrong about
+ * it so we can do the porting fixups
+ */
+ _dbus_assert (sizeof (pid_t) <= sizeof (credentials->pid));
+ _dbus_assert (sizeof (uid_t) <= sizeof (credentials->uid));
+ _dbus_assert (sizeof (gid_t) <= sizeof (credentials->gid));
+
credentials->pid = -1;
credentials->uid = -1;
credentials->gid = -1;
@@ -1353,6 +1361,14 @@ _dbus_credentials_from_uid_string (const DBusString *uid_str,
void
_dbus_credentials_from_current_process (DBusCredentials *credentials)
{
+ /* The POSIX spec certainly doesn't promise this, but
+ * we need these assertions to fail as soon as we're wrong about
+ * it so we can do the porting fixups
+ */
+ _dbus_assert (sizeof (pid_t) <= sizeof (credentials->pid));
+ _dbus_assert (sizeof (uid_t) <= sizeof (credentials->uid));
+ _dbus_assert (sizeof (gid_t) <= sizeof (credentials->gid));
+
credentials->pid = getpid ();
credentials->uid = getuid ();
credentials->gid = getgid ();
diff --git a/dbus/dbus-transport-protected.h b/dbus/dbus-transport-protected.h
index 8ee605c0..31668389 100644
--- a/dbus/dbus-transport-protected.h
+++ b/dbus/dbus-transport-protected.h
@@ -86,6 +86,11 @@ struct DBusTransport
long max_live_messages_size; /**< Max total size of received messages. */
DBusCounter *live_messages_size; /**< Counter for size of all live messages. */
+
+
+ DBusAllowUnixUserFunction unix_user_function; /**< Function for checking whether a user is authorized. */
+ void *unix_user_data; /**< Data for unix_user_function */
+ DBusFreeFunction free_unix_user_data; /**< Function to free unix_user_data */
unsigned int disconnected : 1; /**< #TRUE if we are disconnected. */
unsigned int authenticated : 1; /**< Cache of auth state; use _dbus_transport_get_is_authenticated() to query value */
diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c
index 8087f5b0..b6ab8c0a 100644
--- a/dbus/dbus-transport.c
+++ b/dbus/dbus-transport.c
@@ -127,6 +127,10 @@ _dbus_transport_init_base (DBusTransport *transport,
transport->receive_credentials_pending = server;
transport->is_server = server;
+ transport->unix_user_function = NULL;
+ transport->unix_user_data = NULL;
+ transport->free_unix_user_data = NULL;
+
/* Try to default to something that won't totally hose the system,
* but doesn't impose too much of a limitation.
*/
@@ -155,6 +159,9 @@ _dbus_transport_finalize_base (DBusTransport *transport)
{
if (!transport->disconnected)
_dbus_transport_disconnect (transport);
+
+ if (transport->free_unix_user_data != NULL)
+ (* transport->free_unix_user_data) (transport->unix_user_data);
_dbus_message_loader_unref (transport->loader);
_dbus_auth_unref (transport->auth);
@@ -334,6 +341,8 @@ _dbus_transport_get_is_connected (DBusTransport *transport)
* Returns #TRUE if we have been authenticated. Will return #TRUE
* even if the transport is disconnected.
*
+ * @todo needs to drop connection->mutex when calling the unix_user_function
+ *
* @param transport the transport
* @returns whether we're authenticated
*/
@@ -363,23 +372,45 @@ _dbus_transport_get_is_authenticated (DBusTransport *transport)
if (transport->authenticated && transport->is_server)
{
DBusCredentials auth_identity;
- DBusCredentials our_identity;
- _dbus_credentials_from_current_process (&our_identity);
_dbus_auth_get_identity (transport->auth, &auth_identity);
-
- if (!_dbus_credentials_match (&our_identity,
- &auth_identity))
+
+ if (transport->unix_user_function != NULL)
{
- _dbus_verbose ("Client authorized as UID %d but our UID is %d, disconnecting\n",
- auth_identity.uid, our_identity.uid);
- _dbus_transport_disconnect (transport);
- return FALSE;
+ /* FIXME we hold the connection lock here and should drop it */
+ if (!(* transport->unix_user_function) (transport->connection,
+ auth_identity.uid,
+ transport->unix_user_data))
+ {
+ _dbus_verbose ("Client UID %d was rejected, disconnecting\n",
+ auth_identity.uid);
+ _dbus_transport_disconnect (transport);
+ return FALSE;
+ }
+ else
+ {
+ _dbus_verbose ("Client UID %d authorized\n", auth_identity.uid);
+ }
}
else
{
- _dbus_verbose ("Client authorized as UID %d matching our UID %d\n",
- auth_identity.uid, our_identity.uid);
+ DBusCredentials our_identity;
+
+ _dbus_credentials_from_current_process (&our_identity);
+
+ if (!_dbus_credentials_match (&our_identity,
+ &auth_identity))
+ {
+ _dbus_verbose ("Client authorized as UID %d but our UID is %d, disconnecting\n",
+ auth_identity.uid, our_identity.uid);
+ _dbus_transport_disconnect (transport);
+ return FALSE;
+ }
+ else
+ {
+ _dbus_verbose ("Client authorized as UID %d matching our UID %d\n",
+ auth_identity.uid, our_identity.uid);
+ }
}
}
@@ -737,4 +768,62 @@ _dbus_transport_get_max_live_messages_size (DBusTransport *transport)
return transport->max_live_messages_size;
}
+/**
+ * See dbus_connection_get_unix_user().
+ *
+ * @param transport the transport
+ * @param uid return location for the user ID
+ * @returns #TRUE if uid is filled in with a valid user ID
+ */
+dbus_bool_t
+_dbus_transport_get_unix_user (DBusTransport *transport,
+ unsigned long *uid)
+{
+ DBusCredentials auth_identity;
+
+ *uid = _DBUS_INT_MAX; /* better than some root or system user in
+ * case of bugs in the caller. Caller should
+ * never use this value on purpose, however.
+ */
+
+ if (!transport->authenticated)
+ return FALSE;
+
+ _dbus_auth_get_identity (transport->auth, &auth_identity);
+
+ if (auth_identity.uid >= 0)
+ {
+ *uid = auth_identity.uid;
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+/**
+ * See dbus_connection_set_unix_user_function().
+ *
+ * @param transport the transport
+ * @param function the predicate
+ * @param data data to pass to the predicate
+ * @param free_data_function function to free the data
+ * @param old_data the old user data to be freed
+ * @param old_free_data_function old free data function to free it with
+ */
+void
+_dbus_transport_set_unix_user_function (DBusTransport *transport,
+ DBusAllowUnixUserFunction function,
+ void *data,
+ DBusFreeFunction free_data_function,
+ void **old_data,
+ DBusFreeFunction *old_free_data_function)
+{
+ *old_data = transport->unix_user_data;
+ *old_free_data_function = transport->free_unix_user_data;
+
+ transport->unix_user_function = function;
+ transport->unix_user_data = data;
+ transport->free_unix_user_data = free_data_function;
+}
+
/** @} */
diff --git a/dbus/dbus-transport.h b/dbus/dbus-transport.h
index 639a7d50..c016412f 100644
--- a/dbus/dbus-transport.h
+++ b/dbus/dbus-transport.h
@@ -30,31 +30,41 @@ DBUS_BEGIN_DECLS;
typedef struct DBusTransport DBusTransport;
-DBusTransport* _dbus_transport_open (const char *address,
- DBusResultCode *result);
-void _dbus_transport_ref (DBusTransport *transport);
-void _dbus_transport_unref (DBusTransport *transport);
-void _dbus_transport_disconnect (DBusTransport *transport);
-dbus_bool_t _dbus_transport_get_is_connected (DBusTransport *transport);
-dbus_bool_t _dbus_transport_get_is_authenticated (DBusTransport *transport);
-dbus_bool_t _dbus_transport_handle_watch (DBusTransport *transport,
- DBusWatch *watch,
- unsigned int condition);
-dbus_bool_t _dbus_transport_set_connection (DBusTransport *transport,
- DBusConnection *connection);
-void _dbus_transport_messages_pending (DBusTransport *transport,
- int queue_length);
-void _dbus_transport_do_iteration (DBusTransport *transport,
- unsigned int flags,
- int timeout_milliseconds);
-DBusDispatchStatus _dbus_transport_get_dispatch_status (DBusTransport *transport);
-dbus_bool_t _dbus_transport_queue_messages (DBusTransport *transport);
-void _dbus_transport_set_max_message_size (DBusTransport *transport,
- long size);
-long _dbus_transport_get_max_message_size (DBusTransport *transport);
-void _dbus_transport_set_max_live_messages_size (DBusTransport *transport,
- long size);
-long _dbus_transport_get_max_live_messages_size (DBusTransport *transport);
+DBusTransport* _dbus_transport_open (const char *address,
+ DBusResultCode *result);
+void _dbus_transport_ref (DBusTransport *transport);
+void _dbus_transport_unref (DBusTransport *transport);
+void _dbus_transport_disconnect (DBusTransport *transport);
+dbus_bool_t _dbus_transport_get_is_connected (DBusTransport *transport);
+dbus_bool_t _dbus_transport_get_is_authenticated (DBusTransport *transport);
+dbus_bool_t _dbus_transport_handle_watch (DBusTransport *transport,
+ DBusWatch *watch,
+ unsigned int condition);
+dbus_bool_t _dbus_transport_set_connection (DBusTransport *transport,
+ DBusConnection *connection);
+void _dbus_transport_messages_pending (DBusTransport *transport,
+ int queue_length);
+void _dbus_transport_do_iteration (DBusTransport *transport,
+ unsigned int flags,
+ int timeout_milliseconds);
+DBusDispatchStatus _dbus_transport_get_dispatch_status (DBusTransport *transport);
+dbus_bool_t _dbus_transport_queue_messages (DBusTransport *transport);
+void _dbus_transport_set_max_message_size (DBusTransport *transport,
+ long size);
+long _dbus_transport_get_max_message_size (DBusTransport *transport);
+void _dbus_transport_set_max_live_messages_size (DBusTransport *transport,
+ long size);
+long _dbus_transport_get_max_live_messages_size (DBusTransport *transport);
+dbus_bool_t _dbus_transport_get_unix_user (DBusTransport *transport,
+ unsigned long *uid);
+void _dbus_transport_set_unix_user_function (DBusTransport *transport,
+ DBusAllowUnixUserFunction function,
+ void *data,
+ DBusFreeFunction free_data_function,
+ void **old_data,
+ DBusFreeFunction *old_free_data_function);
+
+
DBUS_END_DECLS;
diff --git a/doc/config-file.txt b/doc/config-file.txt
index c10cd7ad..ae581924 100644
--- a/doc/config-file.txt
+++ b/doc/config-file.txt
@@ -94,6 +94,8 @@ Elements:
own="servicename"
send_to="servicename"
receive_from="servicename"
+ user="username"
+ group="groupname"
Examples:
<deny send="org.freedesktop.System.Reboot"/>
@@ -101,6 +103,8 @@ Elements:
<deny own="org.freedesktop.System"/>
<deny send_to="org.freedesktop.System"/>
<deny receive_from="org.freedesktop.System"/>
+ <deny user="john"/>
+ <deny group="enemies"/>
send_to and receive_from mean that messages may not be sent to
or received from the *owner* of the given service, not that
@@ -108,24 +112,32 @@ Elements:
a connection owns services A, B, C, and sending to A is denied,
sending to B or C will not work either.
- For "servicename" or "messagename" the character "*" can be
- substituted, meaning "any." Complex globs like "foo.bar.*" aren't
- allowed for now because they'd be work to implement and maybe
- encourage sloppy security anyway.
+ user and group denials mean that the given user or group may
+ not connect to the message bus.
- FIXME should we allow send/send_to and receive/receive_from
- to both be specified, in which case they would be ANDed together?
+ For "servicename" or "messagename" or "username" or "groupname"
+ the character "*" can be substituted, meaning "any." Complex globs
+ like "foo.bar.*" aren't allowed for now because they'd be work to
+ implement and maybe encourage sloppy security anyway.
+
+ It does not make sense to deny a user or group inside a <policy>
+ for a user or group; user/group denials can only be inside
+ context="default" or context="required" policies.
+
+ A single <deny> rule may specify both send and send_to, OR both
+ receive and receive_from. In this case, the denial applies only if
+ both attributes match the message being denied.
e.g. <deny send="foo.bar" send_to="foo.blah"/> would deny
messages of the given name AND to the given service.
- Probably need to see how hard/slow all this will be to implement.
-
<allow>
send="messagename"
receive="messagename"
own="servicename"
send_to="servicename"
receive_from="servicename"
+ user="username"
+ group="groupname"
Makes an exception to previous <deny> statements. Works
just like <deny> but with the inverse meaning.