summaryrefslogtreecommitdiffstats
path: root/dbus/dbus-auth.c
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2003-01-04 07:28:54 +0000
committerHavoc Pennington <hp@redhat.com>2003-01-04 07:28:54 +0000
commit01af5ff4101e540a6456bca01d56272e701bea78 (patch)
treea5b0fc81b99e3b0564d0b2cc2ac4c20196a051f0 /dbus/dbus-auth.c
parent1ed128b52484d95e30f7437bf87f34d85371f1f8 (diff)
2003-01-04 Havoc Pennington <hp@pobox.com>
* test/watch.c (error_handler): make it safe if the error handler is called multiple times (if we s/error handler/disconnect handler/ we should just guarantee it's called only once) * dbus/dbus-transport.c (_dbus_transport_disconnect): call the error handler on disconnect (it's quite possible we should just change the error handler to a "disconnect handler," I'm not sure we have any other meaningful errors) * configure.in: check for getpwnam_r * dbus/dbus-transport.c, dbus/dbus-transport-unix.c, dbus/dbus-auth.c: add credentials support, add EXTERNAL auth mechanism as in SASL spec, using socket credentials * dbus/dbus-sysdeps.c (_dbus_read_credentials_unix_socket): new function (_dbus_send_credentials_unix_socket): new function * dbus/dbus-sysdeps.c (_dbus_accept_unix_socket): rename just dbus_accept() (_dbus_write): only check errno if <0 returned (_dbus_write_two): ditto
Diffstat (limited to 'dbus/dbus-auth.c')
-rw-r--r--dbus/dbus-auth.c268
1 files changed, 263 insertions, 5 deletions
diff --git a/dbus/dbus-auth.c b/dbus/dbus-auth.c
index d39a7770..032e49a8 100644
--- a/dbus/dbus-auth.c
+++ b/dbus/dbus-auth.c
@@ -65,6 +65,12 @@ typedef struct
} DBusAuthCommandHandler;
/**
+ * This function appends an initial client response to the given string
+ */
+typedef dbus_bool_t (* DBusInitialResponseFunction) (DBusAuth *auth,
+ DBusString *response);
+
+/**
* This function processes a block of data received from the peer.
* i.e. handles a DATA command.
*/
@@ -97,6 +103,7 @@ typedef struct
DBusAuthEncodeFunction server_encode_func;
DBusAuthDecodeFunction server_decode_func;
DBusAuthShutdownFunction server_shutdown_func;
+ DBusInitialResponseFunction client_initial_response_func;
DBusAuthDataFunction client_data_func;
DBusAuthEncodeFunction client_encode_func;
DBusAuthDecodeFunction client_decode_func;
@@ -116,6 +123,14 @@ struct DBusAuth
const DBusAuthCommandHandler *handlers; /**< Handlers for commands */
const DBusAuthMechanismHandler *mech; /**< Current auth mechanism */
+
+ DBusString identity; /**< Current identity we're authorizing
+ * as.
+ */
+
+ DBusCredentials credentials; /**< Credentials, fields may be -1 */
+
+ DBusCredentials authorized_identity; /**< Credentials that are authorized */
unsigned int needed_memory : 1; /**< We needed memory to continue since last
* successful getting something done
@@ -125,6 +140,7 @@ struct DBusAuth
unsigned int authenticated_pending_output : 1; /**< Authenticated once we clear outgoing buffer */
unsigned int authenticated_pending_begin : 1; /**< Authenticated once we get BEGIN */
unsigned int already_got_mechanisms : 1; /**< Client already got mech list */
+ unsigned int already_asked_for_initial_response : 1; /**< Already sent a blank challenge to get an initial response */
};
typedef struct
@@ -228,6 +244,14 @@ _dbus_auth_new (int size)
auth->refcount = 1;
+ auth->credentials.pid = -1;
+ auth->credentials.uid = -1;
+ auth->credentials.gid = -1;
+
+ auth->authorized_identity.pid = -1;
+ auth->authorized_identity.uid = -1;
+ auth->authorized_identity.gid = -1;
+
/* note that we don't use the max string length feature,
* because you can't use that feature if you're going to
* try to recover from out-of-memory (it creates
@@ -244,6 +268,14 @@ _dbus_auth_new (int size)
if (!_dbus_string_init (&auth->outgoing, _DBUS_INT_MAX))
{
+ _dbus_string_free (&auth->incoming);
+ dbus_free (auth);
+ return NULL;
+ }
+
+ if (!_dbus_string_init (&auth->identity, _DBUS_INT_MAX))
+ {
+ _dbus_string_free (&auth->incoming);
_dbus_string_free (&auth->outgoing);
dbus_free (auth);
return NULL;
@@ -278,6 +310,11 @@ shutdown_mech (DBusAuth *auth)
/* Cancel any auth */
auth->authenticated_pending_begin = FALSE;
auth->authenticated = FALSE;
+ auth->already_asked_for_initial_response = FALSE;
+ _dbus_string_set_length (&auth->identity, 0);
+ auth->authorized_identity.pid = -1;
+ auth->authorized_identity.uid = -1;
+ auth->authorized_identity.gid = -1;
if (auth->mech != NULL)
{
@@ -353,6 +390,163 @@ handle_decode_stupid_test_mech (DBusAuth *auth,
return TRUE;
}
+static dbus_bool_t
+do_rejection (DBusAuth *auth)
+{
+ if (_dbus_string_append (&auth->outgoing,
+ "REJECTED\r\n"))
+ {
+ shutdown_mech (auth);
+ _dbus_verbose ("rejected client auth\n");
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+static dbus_bool_t
+handle_server_data_external_mech (DBusAuth *auth,
+ const DBusString *data)
+{
+ DBusCredentials desired_identity;
+
+ if (auth->credentials.uid < 0)
+ {
+ _dbus_verbose ("no credentials, mechanism EXTERNAL can't authenticate\n");
+ return do_rejection (auth);
+ }
+
+ if (_dbus_string_get_length (data) > 0)
+ {
+ if (_dbus_string_get_length (&auth->identity) > 0)
+ {
+ /* Tried to send two auth identities, wtf */
+ return do_rejection (auth);
+ }
+ else
+ {
+ /* this is our auth identity */
+ if (!_dbus_string_copy (data, 0, &auth->identity, 0))
+ return FALSE;
+ }
+ }
+
+ /* Poke client for an auth identity, if none given */
+ if (_dbus_string_get_length (&auth->identity) == 0 &&
+ !auth->already_asked_for_initial_response)
+ {
+ if (_dbus_string_append (&auth->outgoing,
+ "DATA\r\n"))
+ {
+ _dbus_verbose ("sending empty challenge asking client for auth identity\n");
+ auth->already_asked_for_initial_response = TRUE;
+ return TRUE;
+ }
+ else
+ return FALSE;
+ }
+
+ desired_identity.pid = -1;
+ desired_identity.uid = -1;
+ desired_identity.gid = -1;
+
+ /* If auth->identity is still empty here, then client
+ * responded with an empty string after we poked it for
+ * an initial response. This means to try to auth the
+ * identity provided in the credentials.
+ */
+ if (_dbus_string_get_length (&auth->identity) == 0)
+ {
+ desired_identity.uid = auth->credentials.uid;
+ }
+ else
+ {
+ if (!_dbus_credentials_from_uid_string (&auth->identity,
+ &desired_identity))
+ return do_rejection (auth);
+ }
+
+ if (desired_identity.uid < 0)
+ {
+ _dbus_verbose ("desired UID %d is no good\n", desired_identity.uid);
+ return do_rejection (auth);
+ }
+
+ if (_dbus_credentials_match (&auth->credentials,
+ &desired_identity))
+ {
+ /* client has authenticated */
+ _dbus_verbose ("authenticated client with UID %d matching socket credentials UID %d\n",
+ desired_identity.uid,
+ auth->credentials.uid);
+
+ if (!_dbus_string_append (&auth->outgoing,
+ "OK\r\n"))
+ return FALSE;
+
+ auth->authorized_identity.uid = desired_identity.uid;
+
+ auth->authenticated_pending_begin = TRUE;
+
+ return TRUE;
+ }
+ else
+ {
+ return do_rejection (auth);
+ }
+}
+
+static void
+handle_server_shutdown_external_mech (DBusAuth *auth)
+{
+
+}
+
+static dbus_bool_t
+handle_client_initial_response_external_mech (DBusAuth *auth,
+ DBusString *response)
+{
+ /* We always append our UID as an initial response, so the server
+ * doesn't have to send back an empty challenge to check whether we
+ * want to specify an identity. i.e. this avoids a round trip that
+ * the spec for the EXTERNAL mechanism otherwise requires.
+ */
+ DBusString plaintext;
+
+ if (!_dbus_string_init (&plaintext, _DBUS_INT_MAX))
+ return FALSE;
+
+ if (!_dbus_string_append_our_uid (&plaintext))
+ goto failed;
+
+ if (!_dbus_string_base64_encode (&plaintext, 0,
+ response,
+ _dbus_string_get_length (response)))
+ goto failed;
+
+ _dbus_string_free (&plaintext);
+
+ return TRUE;
+
+ failed:
+ _dbus_string_free (&plaintext);
+ return FALSE;
+}
+
+static dbus_bool_t
+handle_client_data_external_mech (DBusAuth *auth,
+ const DBusString *data)
+{
+
+ return TRUE;
+}
+
+static void
+handle_client_shutdown_external_mech (DBusAuth *auth)
+{
+
+}
+
/* Put mechanisms here in order of preference.
* What I eventually want to have is:
*
@@ -364,11 +558,21 @@ handle_decode_stupid_test_mech (DBusAuth *auth,
*/
static const DBusAuthMechanismHandler
all_mechanisms[] = {
+ { "EXTERNAL",
+ handle_server_data_external_mech,
+ NULL, NULL,
+ handle_server_shutdown_external_mech,
+ handle_client_initial_response_external_mech,
+ handle_client_data_external_mech,
+ NULL, NULL,
+ handle_client_shutdown_external_mech },
+ /* Obviously this has to die for production use */
{ "DBUS_STUPID_TEST_MECH",
handle_server_data_stupid_test_mech,
handle_encode_stupid_test_mech,
handle_decode_stupid_test_mech,
handle_server_shutdown_stupid_test_mech,
+ NULL,
handle_client_data_stupid_test_mech,
handle_encode_stupid_test_mech,
handle_decode_stupid_test_mech,
@@ -496,8 +700,9 @@ process_auth (DBusAuth *auth,
auth->mech = find_mech (&mech);
if (auth->mech != NULL)
{
- _dbus_verbose ("Trying mechanism %s\n",
- auth->mech->mechanism);
+ _dbus_verbose ("Trying mechanism %s with initial response of %d bytes\n",
+ auth->mech->mechanism,
+ _dbus_string_get_length (&decoded_response));
if (!(* auth->mech->server_data_func) (auth,
&decoded_response))
@@ -702,15 +907,30 @@ client_try_next_mechanism (DBusAuth *auth)
{
_dbus_string_free (&auth_command);
return FALSE;
- }
-
+ }
+
if (!_dbus_string_append (&auth_command,
mech->mechanism))
{
_dbus_string_free (&auth_command);
return FALSE;
}
-
+
+ if (mech->client_initial_response_func != NULL)
+ {
+ if (!_dbus_string_append (&auth_command, " "))
+ {
+ _dbus_string_free (&auth_command);
+ return FALSE;
+ }
+
+ if (!(* mech->client_initial_response_func) (auth, &auth_command))
+ {
+ _dbus_string_free (&auth_command);
+ return FALSE;
+ }
+ }
+
if (!_dbus_string_append (&auth_command,
"\r\n"))
{
@@ -1327,4 +1547,42 @@ _dbus_auth_decode_data (DBusAuth *auth,
}
}
+/**
+ * Sets credentials received via reliable means from the operating
+ * system.
+ *
+ * @param auth the auth conversation
+ * @param credentials the credentials received
+ */
+void
+_dbus_auth_set_credentials (DBusAuth *auth,
+ const DBusCredentials *credentials)
+{
+ auth->credentials = *credentials;
+}
+
+/**
+ * Gets the identity we authorized the client as. Apps may have
+ * different policies as to what identities they allow.
+ *
+ * @param auth the auth conversation
+ * @param credentials the credentials we've authorized
+ */
+void
+_dbus_auth_get_identity (DBusAuth *auth,
+ DBusCredentials *credentials)
+{
+ if (auth->authenticated)
+ {
+ *credentials = auth->authorized_identity;
+ }
+ else
+ {
+ credentials->pid = -1;
+ credentials->uid = -1;
+ credentials->gid = -1;
+ }
+}
+
+
/** @} */