summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Zeuthen <davidz@redhat.com>2010-04-26 10:30:43 -0400
committerDavid Zeuthen <davidz@redhat.com>2010-04-26 10:30:43 -0400
commitad152a2affc1ceff9c9a35c1c21355291509e1db (patch)
treeb29ac195cfb8abcf0bb1001e21f8caf4a5804889
parent1179123968b8072b1d3539b346e3c766472621b0 (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.txt2
-rw-r--r--gdbus/gdbusauth.c113
-rw-r--r--gdbus/gdbusauth.h5
-rw-r--r--gdbus/gdbusconnection.c66
-rw-r--r--gdbus/gdbusconnection.h2
-rw-r--r--gdbus/gdbusenums.h13
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.