diff options
author | David Zeuthen <davidz@redhat.com> | 2010-04-26 10:30:43 -0400 |
---|---|---|
committer | David Zeuthen <davidz@redhat.com> | 2010-04-26 10:30:43 -0400 |
commit | ad152a2affc1ceff9c9a35c1c21355291509e1db (patch) | |
tree | b29ac195cfb8abcf0bb1001e21f8caf4a5804889 | |
parent | 1179123968b8072b1d3539b346e3c766472621b0 (diff) |
Negotiate UNIX file descriptor passing
We actually don't support this yet, this commit is only the authentication bits.
-rw-r--r-- | docs/reference/gdbus/gdbus-standalone-sections.txt | 2 | ||||
-rw-r--r-- | gdbus/gdbusauth.c | 113 | ||||
-rw-r--r-- | gdbus/gdbusauth.h | 5 | ||||
-rw-r--r-- | gdbus/gdbusconnection.c | 66 | ||||
-rw-r--r-- | gdbus/gdbusconnection.h | 2 | ||||
-rw-r--r-- | gdbus/gdbusenums.h | 13 |
6 files changed, 188 insertions, 13 deletions
diff --git a/docs/reference/gdbus/gdbus-standalone-sections.txt b/docs/reference/gdbus/gdbus-standalone-sections.txt index 783499e..a2d0819 100644 --- a/docs/reference/gdbus/gdbus-standalone-sections.txt +++ b/docs/reference/gdbus/gdbus-standalone-sections.txt @@ -88,6 +88,8 @@ g_dbus_connection_new_sync g_dbus_connection_new_for_address g_dbus_connection_new_for_address_finish g_dbus_connection_new_for_address_sync +GDBusConnectionCapabilityFlags +g_dbus_connection_get_capabilities g_dbus_connection_close g_dbus_connection_is_closed g_dbus_connection_get_exit_on_close diff --git a/gdbus/gdbusauth.c b/gdbus/gdbusauth.c index 9d361e9..6ccae42 100644 --- a/gdbus/gdbusauth.c +++ b/gdbus/gdbusauth.c @@ -347,11 +347,14 @@ typedef enum { CLIENT_STATE_WAITING_FOR_DATA, CLIENT_STATE_WAITING_FOR_OK, - CLIENT_STATE_WAITING_FOR_REJECT + CLIENT_STATE_WAITING_FOR_REJECT, + CLIENT_STATE_WAITING_FOR_AGREE_UNIX_FD } ClientState; gchar * _g_dbus_auth_run_client (GDBusAuth *auth, + GDBusConnectionCapabilityFlags offered_capabilities, + GDBusConnectionCapabilityFlags *out_negotiated_capabilities, GCancellable *cancellable, GError **error) { @@ -364,11 +367,13 @@ _g_dbus_auth_run_client (GDBusAuth *auth, GPtrArray *attempted_auth_mechs; GDBusAuthMechanism *mech; ClientState state; + GDBusConnectionCapabilityFlags negotiated_capabilities; ret_guid = NULL; supported_auth_mechs = NULL; attempted_auth_mechs = g_ptr_array_new (); mech = NULL; + negotiated_capabilities = 0; dis = G_DATA_INPUT_STREAM (g_data_input_stream_new (g_io_stream_get_input_stream (auth->priv->stream))); dos = G_DATA_OUTPUT_STREAM (g_data_output_stream_new (g_io_stream_get_output_stream (auth->priv->stream))); @@ -447,10 +452,19 @@ _g_dbus_auth_run_client (GDBusAuth *auth, ret_guid = g_strdup (line + 3); g_free (line); - if (!g_data_output_stream_put_string (dos, "BEGIN\r\n", cancellable, error)) - goto out; - - goto out; + if (offered_capabilities & G_DBUS_CONNECTION_CAPABILITY_FLAGS_UNIX_FD_PASSING) + { + if (!g_data_output_stream_put_string (dos, "NEGOTIATE_UNIX_FD\r\n", cancellable, error)) + goto out; + state = CLIENT_STATE_WAITING_FOR_AGREE_UNIX_FD; + } + else + { + if (!g_data_output_stream_put_string (dos, "BEGIN\r\n", cancellable, error)) + goto out; + /* and we're done! */ + goto out; + } } else if (g_str_has_prefix (line, "REJECTED ")) { @@ -469,6 +483,40 @@ _g_dbus_auth_run_client (GDBusAuth *auth, } break; + case CLIENT_STATE_WAITING_FOR_AGREE_UNIX_FD: + line = g_data_input_stream_read_line (dis, &line_length, cancellable, error); + if (line == NULL) + goto out; + if (g_strcmp0 (line, "AGREE_UNIX_FD") == 0) + { + negotiated_capabilities |= G_DBUS_CONNECTION_CAPABILITY_FLAGS_UNIX_FD_PASSING; + if (!g_data_output_stream_put_string (dos, "BEGIN\r\n", cancellable, error)) + goto out; + /* and we're done! */ + goto out; + } + else if (g_str_has_prefix (line, "ERROR") && (line[5] == 0 || g_ascii_isspace (line[5]))) + { + //g_strstrip (line + 5); g_debug ("bah, no unix_fd: `%s'", line + 5); + g_free (line); + if (!g_data_output_stream_put_string (dos, "BEGIN\r\n", cancellable, error)) + goto out; + /* and we're done! */ + goto out; + } + else + { + /* TODO: handle other valid responses */ + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "In WaitingForAgreeUnixFd: unexpected response `%s'", + line); + g_free (line); + goto out; + } + break; + case CLIENT_STATE_WAITING_FOR_DATA: /* TODO: handle */ g_assert_not_reached (); @@ -488,6 +536,20 @@ _g_dbus_auth_run_client (GDBusAuth *auth, g_strfreev (supported_auth_mechs); g_object_ref (dis); g_object_ref (dos); + + /* ensure return value is NULL if error is set */ + if (error != NULL && *error != NULL) + { + g_free (ret_guid); + ret_guid = NULL; + } + + if (ret_guid != NULL) + { + if (out_negotiated_capabilities != NULL) + *out_negotiated_capabilities = negotiated_capabilities; + } + return ret_guid; } @@ -538,6 +600,8 @@ gboolean _g_dbus_auth_run_server (GDBusAuth *auth, const gchar *guid, gboolean allow_anonymous, + GDBusConnectionCapabilityFlags offered_capabilities, + GDBusConnectionCapabilityFlags *out_negotiated_capabilities, GCancellable *cancellable, GError **error) { @@ -551,11 +615,13 @@ _g_dbus_auth_run_server (GDBusAuth *auth, gsize line_length; GDBusAuthMechanism *mech; gchar *s; + GDBusConnectionCapabilityFlags negotiated_capabilities; ret = FALSE; dis = NULL; dos = NULL; mech = NULL; + negotiated_capabilities = 0; if (!g_dbus_is_guid (guid)) { @@ -760,16 +826,28 @@ _g_dbus_auth_run_server (GDBusAuth *auth, g_free (line); goto out; } + else if (g_strcmp0 (line, "NEGOTIATE_UNIX_FD") == 0) + { + if (offered_capabilities & G_DBUS_CONNECTION_CAPABILITY_FLAGS_UNIX_FD_PASSING) + { + negotiated_capabilities |= G_DBUS_CONNECTION_CAPABILITY_FLAGS_UNIX_FD_PASSING; + if (!g_data_output_stream_put_string (dos, "AGREE_UNIX_FD\r\n", cancellable, error)) + goto out; + } + else + { + if (!g_data_output_stream_put_string (dos, "ERROR \"fd passing not offered\"\r\n", cancellable, error)) + goto out; + } + } else { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "Unexpected line `%s' while in WaitingForBegin state", - line); + g_debug ("Unexpected line `%s' while in WaitingForBegin state", line); g_free (line); + if (!g_data_output_stream_put_string (dos, "ERROR \"Unknown Command\"\r\n", cancellable, error)) + goto out; } - goto out; + break; default: g_assert_not_reached (); @@ -790,6 +868,19 @@ _g_dbus_auth_run_server (GDBusAuth *auth, g_object_ref (dis); if (dis != NULL) g_object_ref (dos); + + /* ensure return value is FALSE if error is set */ + if (error != NULL && *error != NULL) + { + ret = FALSE; + } + + if (ret) + { + if (out_negotiated_capabilities != NULL) + *out_negotiated_capabilities = negotiated_capabilities; + } + return ret; } diff --git a/gdbus/gdbusauth.h b/gdbus/gdbusauth.h index ce8d33f..d91e413 100644 --- a/gdbus/gdbusauth.h +++ b/gdbus/gdbusauth.h @@ -76,14 +76,17 @@ GDBusAuth *_g_dbus_auth_new (GIOStream *stream); gboolean _g_dbus_auth_run_server (GDBusAuth *auth, const gchar *guid, gboolean allow_anonymous, + GDBusConnectionCapabilityFlags offered_capabilities, + GDBusConnectionCapabilityFlags *out_negotiated_capabilities, GCancellable *cancellable, GError **error); gchar *_g_dbus_auth_run_client (GDBusAuth *auth, + GDBusConnectionCapabilityFlags offered_capabilities, + GDBusConnectionCapabilityFlags *out_negotiated_capabilities, GCancellable *cancellable, GError **error); - G_END_DECLS #endif /* __G_DBUS_AUTH_H__ */ diff --git a/gdbus/gdbusconnection.c b/gdbus/gdbusconnection.c index 19a49d7..bc6f028 100644 --- a/gdbus/gdbusconnection.c +++ b/gdbus/gdbusconnection.c @@ -26,6 +26,10 @@ #include <glib/gi18n.h> +#ifdef G_OS_UNIX +#include <gio/gunixconnection.h> +#endif + #include <unistd.h> #include <sys/types.h> #include <stdlib.h> @@ -183,6 +187,9 @@ struct _GDBusConnectionPrivate /* Whether to exit on close */ gboolean exit_on_close; + + /* Capabilities negotiated during authentication */ + GDBusConnectionCapabilityFlags capabilities; }; typedef struct ExportedObject ExportedObject; @@ -207,6 +214,7 @@ enum PROP_UNIQUE_NAME, PROP_CLOSED, PROP_EXIT_ON_CLOSE, + PROP_CAPABILITY_FLAGS, }; static void distribute_signals (GDBusConnection *connection, @@ -352,6 +360,10 @@ g_dbus_connection_get_property (GObject *object, g_value_set_boolean (value, g_dbus_connection_get_exit_on_close (connection)); break; + case PROP_CAPABILITY_FLAGS: + g_value_set_flags (value, g_dbus_connection_get_capabilities (connection)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -558,6 +570,23 @@ g_dbus_connection_class_init (GDBusConnectionClass *klass) G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); + /** + * GDBusConnection:capabilities: + * + * Flags from the #GDBusConnectionCapabilityFlags enumeration + * representing connection features negotiated with the other peer. + */ + g_object_class_install_property (gobject_class, + PROP_CAPABILITY_FLAGS, + g_param_spec_flags ("capabilities", + _("Capabilities"), + _("Capabilities"), + G_TYPE_DBUS_CONNECTION_CAPABILITY_FLAGS, + G_DBUS_CONNECTION_CAPABILITY_FLAGS_NONE, + G_PARAM_READABLE | + G_PARAM_STATIC_NAME | + G_PARAM_STATIC_BLURB | + G_PARAM_STATIC_NICK)); /** * GDBusConnection::closed: @@ -668,6 +697,21 @@ g_dbus_connection_is_closed (GDBusConnection *connection) return connection->priv->closed; } +/** + * g_dbus_connection_get_capabilities: + * @connection: A #GDBusConnection. + * + * Gets the capabilities negotiated with the remote peer + * + * Returns: One or more flags from the #GDBusConnectionCapabilityFlags. + */ +GDBusConnectionCapabilityFlags +g_dbus_connection_get_capabilities (GDBusConnection *connection) +{ + return connection->priv->capabilities; +} + + /* ---------------------------------------------------------------------------------------------------- */ typedef struct @@ -1407,6 +1451,22 @@ on_worker_closed (GDBusWorker *worker, /* ---------------------------------------------------------------------------------------------------- */ +/* Determines the biggest set of capabilities we can support on this connection */ +static GDBusConnectionCapabilityFlags +get_offered_capabilities_max (GDBusConnection *connection) +{ + GDBusConnectionCapabilityFlags ret; + ret = G_DBUS_CONNECTION_CAPABILITY_FLAGS_NONE; +#ifdef G_OS_UNIX + if (G_IS_UNIX_CONNECTION (connection->priv->stream)) + { + ret |= G_DBUS_CONNECTION_CAPABILITY_FLAGS_UNIX_FD_PASSING; + } +#endif + return ret; +} + + static gboolean initable_init (GInitable *initable, GCancellable *cancellable, @@ -1475,6 +1535,8 @@ initable_init (GInitable *initable, if (!_g_dbus_auth_run_server (connection->priv->auth, connection->priv->guid, (connection->priv->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS), + get_offered_capabilities_max (connection), + &connection->priv->capabilities, cancellable, &connection->priv->initialization_error)) goto out; @@ -1485,12 +1547,16 @@ initable_init (GInitable *initable, g_assert (connection->priv->guid == NULL); connection->priv->auth = _g_dbus_auth_new (connection->priv->stream); connection->priv->guid = _g_dbus_auth_run_client (connection->priv->auth, + get_offered_capabilities_max (connection), + &connection->priv->capabilities, cancellable, &connection->priv->initialization_error); if (connection->priv->guid == NULL) goto out; } + //g_debug ("haz unix fd passing powers: %d", connection->priv->capabilities & G_DBUS_CONNECTION_CAPABILITY_FLAGS_UNIX_FD_PASSING); + /* Hack used until * * https://bugzilla.gnome.org/show_bug.cgi?id=616458 diff --git a/gdbus/gdbusconnection.h b/gdbus/gdbusconnection.h index bc6a86b..aa868b4 100644 --- a/gdbus/gdbusconnection.h +++ b/gdbus/gdbusconnection.h @@ -136,7 +136,7 @@ const gchar *g_dbus_connection_get_unique_name (GDBusConnection gboolean g_dbus_connection_get_exit_on_close (GDBusConnection *connection); void g_dbus_connection_set_exit_on_close (GDBusConnection *connection, gboolean exit_on_close); - +GDBusConnectionCapabilityFlags g_dbus_connection_get_capabilities (GDBusConnection *connection); /* ---------------------------------------------------------------------------------------------------- */ gboolean g_dbus_connection_send_message (GDBusConnection *connection, diff --git a/gdbus/gdbusenums.h b/gdbus/gdbusenums.h index 4641b05..4d15ed2 100644 --- a/gdbus/gdbusenums.h +++ b/gdbus/gdbusenums.h @@ -256,6 +256,19 @@ typedef enum { } GDBusConnectionFlags; /** + * GDBusConnectionCapabilityFlags: + * @G_DBUS_CONNECTION_CAPABILITY_FLAGS_NONE: No flags set. + * @G_DBUS_CONNECTION_CAPABILITY_FLAGS_UNIX_FD_PASSING: The connection + * supports exchanging UNIX file descriptors with the remote peer. + * + * Capabilities negotiated with the remote peer. + */ +typedef enum { + G_DBUS_CONNECTION_CAPABILITY_FLAGS_NONE = 0, + G_DBUS_CONNECTION_CAPABILITY_FLAGS_UNIX_FD_PASSING = (1<<0), +} GDBusConnectionCapabilityFlags; + +/** * GDBusMessageType: * @G_DBUS_MESSAGE_TYPE_INVALID: Message is of invalid type. * @G_DBUS_MESSAGE_TYPE_METHOD_CALL: Method call. |