summaryrefslogtreecommitdiff
path: root/src/xdmcp-server.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xdmcp-server.c')
-rw-r--r--src/xdmcp-server.c246
1 files changed, 139 insertions, 107 deletions
diff --git a/src/xdmcp-server.c b/src/xdmcp-server.c
index f7c66c4c..5ebcacfa 100644
--- a/src/xdmcp-server.c
+++ b/src/xdmcp-server.c
@@ -18,7 +18,6 @@
#include "xdmcp-server.h"
#include "xdmcp-protocol.h"
-#include "xdmcp-session-private.h"
#include "x-authority.h"
enum {
@@ -27,7 +26,7 @@ enum {
};
static guint signals[LAST_SIGNAL] = { 0 };
-struct XDMCPServerPrivate
+typedef struct
{
/* Port to listen on */
guint port;
@@ -47,9 +46,9 @@ struct XDMCPServerPrivate
/* XDM-AUTHENTICATION-1 key */
gchar *key;
- /* Active XDMCP sessions */
+ /* Known XDMCP sessions */
GHashTable *sessions;
-};
+} XDMCPServerPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (XDMCPServer, xdmcp_server, G_TYPE_OBJECT)
@@ -72,104 +71,133 @@ xdmcp_server_new (void)
void
xdmcp_server_set_port (XDMCPServer *server, guint port)
{
+ XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
g_return_if_fail (server != NULL);
- server->priv->port = port;
+ priv->port = port;
}
guint
xdmcp_server_get_port (XDMCPServer *server)
{
+ XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
g_return_val_if_fail (server != NULL, 0);
- return server->priv->port;
+ return priv->port;
}
void
xdmcp_server_set_listen_address (XDMCPServer *server, const gchar *listen_address)
{
+ XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
g_return_if_fail (server != NULL);
-
- g_free (server->priv->listen_address);
- server->priv->listen_address = g_strdup (listen_address);
+ g_free (priv->listen_address);
+ priv->listen_address = g_strdup (listen_address);
}
const gchar *
xdmcp_server_get_listen_address (XDMCPServer *server)
{
+ XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
g_return_val_if_fail (server != NULL, NULL);
- return server->priv->listen_address;
+ return priv->listen_address;
}
void
xdmcp_server_set_hostname (XDMCPServer *server, const gchar *hostname)
{
+ XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
g_return_if_fail (server != NULL);
-
- g_free (server->priv->hostname);
- server->priv->hostname = g_strdup (hostname);
+ g_free (priv->hostname);
+ priv->hostname = g_strdup (hostname);
}
const gchar *
xdmcp_server_get_hostname (XDMCPServer *server)
{
+ XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
g_return_val_if_fail (server != NULL, NULL);
- return server->priv->hostname;
+ return priv->hostname;
}
void
xdmcp_server_set_status (XDMCPServer *server, const gchar *status)
{
+ XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
g_return_if_fail (server != NULL);
-
- g_free (server->priv->status);
- server->priv->status = g_strdup (status);
+ g_free (priv->status);
+ priv->status = g_strdup (status);
}
const gchar *
xdmcp_server_get_status (XDMCPServer *server)
{
+ XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
g_return_val_if_fail (server != NULL, NULL);
- return server->priv->status;
+ return priv->status;
}
void
xdmcp_server_set_key (XDMCPServer *server, const gchar *key)
{
+ XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
g_return_if_fail (server != NULL);
- g_free (server->priv->key);
- server->priv->key = g_strdup (key);
+ g_free (priv->key);
+ priv->key = g_strdup (key);
}
+typedef struct
+{
+ XDMCPServer *server;
+ XDMCPSession *session;
+ guint timeout_source;
+} SessionData;
+
+static void
+session_data_free (SessionData *data)
+{
+ g_object_unref (data->session);
+ if (data->timeout_source != 0)
+ g_source_remove (data->timeout_source);
+ g_free (data);
+}
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (SessionData, session_data_free)
+
static gboolean
-session_timeout_cb (XDMCPSession *session)
+session_timeout_cb (gpointer user_data)
{
- session->priv->inactive_timeout = 0;
+ g_autoptr(SessionData) data = user_data;
+ XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (data->server);
- g_debug ("Timing out unmanaged session %d", session->priv->id);
- g_hash_table_remove (session->priv->server->priv->sessions, GINT_TO_POINTER ((gint) session->priv->id));
- return FALSE;
+ g_debug ("Timing out unmanaged session %d", xdmcp_session_get_id (data->session));
+ g_hash_table_remove (priv->sessions, GINT_TO_POINTER ((gint) xdmcp_session_get_id (data->session)));
+ return G_SOURCE_REMOVE;
}
static XDMCPSession *
-add_session (XDMCPServer *server)
+add_session (XDMCPServer *server, GInetAddress *address, guint16 display_number, XAuthority *authority)
{
+ XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
+
guint16 id;
do
{
id = g_random_int () & 0xFFFFFFFF;
- } while (g_hash_table_lookup (server->priv->sessions, GINT_TO_POINTER ((gint) id)));
+ } while (g_hash_table_lookup (priv->sessions, GINT_TO_POINTER ((gint) id)));
- XDMCPSession *session = xdmcp_session_new (id);
- session->priv->server = server;
- g_hash_table_insert (server->priv->sessions, GINT_TO_POINTER ((gint) id), session);
- session->priv->inactive_timeout = g_timeout_add (MANAGE_TIMEOUT, (GSourceFunc) session_timeout_cb, session);
+ SessionData *data = g_malloc0 (sizeof (SessionData));
+ data->server = server;
+ data->session = xdmcp_session_new (id, address, display_number, authority);
+ data->timeout_source = g_timeout_add (MANAGE_TIMEOUT, session_timeout_cb, data);
+ g_hash_table_insert (priv->sessions, GINT_TO_POINTER ((gint) id), data);
- return session;
+ return data->session;
}
-static XDMCPSession *
-get_session (XDMCPServer *server, guint16 id)
+static SessionData *
+get_session_data (XDMCPServer *server, guint16 id)
{
- return g_hash_table_lookup (server->priv->sessions, GINT_TO_POINTER ((gint) id));
+ XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
+ return g_hash_table_lookup (priv->sessions, GINT_TO_POINTER ((gint) id));
}
static gchar *
@@ -201,7 +229,8 @@ send_packet (GSocket *socket, GSocketAddress *address, XDMCPPacket *packet)
static const gchar *
get_authentication_name (XDMCPServer *server)
{
- if (server->priv->key)
+ XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
+ if (priv->key)
return "XDM-AUTHENTICATION-1";
else
return "";
@@ -210,14 +239,16 @@ get_authentication_name (XDMCPServer *server)
static void
handle_query (XDMCPServer *server, GSocket *socket, GSocketAddress *address, gchar **authentication_names)
{
+ XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
+
/* If no authentication requested and we are configured for none then allow */
const gchar *authentication_name = NULL;
- if (authentication_names[0] == NULL && server->priv->key == NULL)
+ if (authentication_names[0] == NULL && priv->key == NULL)
authentication_name = "";
for (gchar **i = authentication_names; *i; i++)
{
- if (strcmp (*i, get_authentication_name (server)) == 0 && server->priv->key != NULL)
+ if (strcmp (*i, get_authentication_name (server)) == 0 && priv->key != NULL)
{
authentication_name = *i;
break;
@@ -229,14 +260,14 @@ handle_query (XDMCPServer *server, GSocket *socket, GSocketAddress *address, gch
{
response = xdmcp_packet_alloc (XDMCP_Willing);
response->Willing.authentication_name = g_strdup (authentication_name);
- response->Willing.hostname = g_strdup (server->priv->hostname);
- response->Willing.status = g_strdup (server->priv->status);
+ response->Willing.hostname = g_strdup (priv->hostname);
+ response->Willing.status = g_strdup (priv->status);
}
else
{
response = xdmcp_packet_alloc (XDMCP_Unwilling);
- response->Unwilling.hostname = g_strdup (server->priv->hostname);
- if (server->priv->key)
+ response->Unwilling.hostname = g_strdup (priv->hostname);
+ if (priv->key)
response->Unwilling.status = g_strdup_printf ("No matching authentication, server requires %s", get_authentication_name (server));
else
response->Unwilling.status = g_strdup ("No matching authentication");
@@ -428,6 +459,8 @@ has_string (gchar **list, const gchar *text)
static void
handle_request (XDMCPServer *server, GSocket *socket, GSocketAddress *address, XDMCPPacket *packet)
{
+ XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
+
/* Check authentication */
g_autofree gchar *authentication_name = NULL;
g_autofree guint8 *authentication_data = NULL;
@@ -436,7 +469,7 @@ handle_request (XDMCPServer *server, GSocket *socket, GSocketAddress *address, X
XdmAuthKeyRec rho;
if (strcmp (packet->Request.authentication_name, "") == 0)
{
- if (!server->priv->key)
+ if (!priv->key)
{
if (!has_string (packet->Request.authorization_names, "MIT-MAGIC-COOKIE-1"))
decline_status = g_strdup ("No matching authorization, server requires MIT-MAGIC-COOKIE-1");
@@ -444,7 +477,7 @@ handle_request (XDMCPServer *server, GSocket *socket, GSocketAddress *address, X
else
decline_status = g_strdup ("No matching authentication, server requires XDM-AUTHENTICATION-1");
}
- else if (strcmp (packet->Request.authentication_name, "XDM-AUTHENTICATION-1") == 0 && server->priv->key)
+ else if (strcmp (packet->Request.authentication_name, "XDM-AUTHENTICATION-1") == 0 && priv->key)
{
if (packet->Request.authentication_data.length == 8)
{
@@ -453,7 +486,7 @@ handle_request (XDMCPServer *server, GSocket *socket, GSocketAddress *address, X
memcpy (input, packet->Request.authentication_data.data, packet->Request.authentication_data.length);
/* Setup key */
- decode_key (server->priv->key, key);
+ decode_key (priv->key, key);
/* Decode message from server */
authentication_name = g_strdup ("XDM-AUTHENTICATION-1");
@@ -474,7 +507,7 @@ handle_request (XDMCPServer *server, GSocket *socket, GSocketAddress *address, X
{
if (strcmp (packet->Request.authentication_name, "") == 0)
decline_status = g_strdup_printf ("No matching authentication, server does not support unauthenticated connections");
- else if (server->priv->key)
+ else if (priv->key)
decline_status = g_strdup ("No matching authentication, server requires XDM-AUTHENTICATION-1");
else
decline_status = g_strdup ("No matching authentication, server only supports unauthenticated connections");
@@ -507,11 +540,11 @@ handle_request (XDMCPServer *server, GSocket *socket, GSocketAddress *address, X
gsize authorization_data_length = 0;
g_autofree guint8 *session_authorization_data = NULL;
gsize session_authorization_data_length = 0;
- if (server->priv->key)
+ if (priv->key)
{
/* Setup key */
guint8 key[8];
- decode_key (server->priv->key, key);
+ decode_key (priv->key, key);
/* Generate a private session key */
// FIXME: Pick a good DES key?
@@ -544,35 +577,35 @@ handle_request (XDMCPServer *server, GSocket *socket, GSocketAddress *address, X
session_authorization_data_length = x_authority_get_authorization_data_length (auth);
}
- XDMCPSession *session = add_session (server);
- session->priv->address = connection_to_address (connection);
- session->priv->display_number = packet->Request.display_number;
- g_autofree gchar *display_number = g_strdup_printf ("%d", packet->Request.display_number);
-
/* We need to check if this is the loopback address and set the authority
* for a local connection if this is so as XCB treats "127.0.0.1" as local
* always */
- if (g_inet_address_get_is_loopback (session->priv->address))
+ g_autoptr(GInetAddress) session_address = connection_to_address (connection);
+ g_autofree gchar *display_number = g_strdup_printf ("%d", packet->Request.display_number);
+ g_autoptr(XAuthority) authority = NULL;
+ if (g_inet_address_get_is_loopback (session_address))
{
gchar hostname[1024];
gethostname (hostname, 1024);
- session->priv->authority = x_authority_new (XAUTH_FAMILY_LOCAL,
- (guint8 *) hostname,
- strlen (hostname),
- display_number,
- authorization_name,
- session_authorization_data,
- session_authorization_data_length);
+ authority = x_authority_new (XAUTH_FAMILY_LOCAL,
+ (guint8 *) hostname,
+ strlen (hostname),
+ display_number,
+ authorization_name,
+ session_authorization_data,
+ session_authorization_data_length);
}
else
- session->priv->authority = x_authority_new (connection->type,
- connection->address.data,
- connection->address.length,
- display_number,
- authorization_name,
- session_authorization_data,
- session_authorization_data_length);
+ authority = x_authority_new (connection->type,
+ connection->address.data,
+ connection->address.length,
+ display_number,
+ authorization_name,
+ session_authorization_data,
+ session_authorization_data_length);
+
+ XDMCPSession *session = add_session (server, session_address, packet->Request.display_number, authority);
XDMCPPacket *response = xdmcp_packet_alloc (XDMCP_Accept);
response->Accept.session_id = xdmcp_session_get_id (session);
@@ -589,8 +622,8 @@ handle_request (XDMCPServer *server, GSocket *socket, GSocketAddress *address, X
static void
handle_manage (XDMCPServer *server, GSocket *socket, GSocketAddress *address, XDMCPPacket *packet)
{
- XDMCPSession *session = get_session (server, packet->Manage.session_id);
- if (!session)
+ SessionData *data = get_session_data (server, packet->Manage.session_id);
+ if (!data->session)
{
XDMCPPacket *response = xdmcp_packet_alloc (XDMCP_Refuse);
response->Refuse.session_id = packet->Manage.session_id;
@@ -600,37 +633,36 @@ handle_manage (XDMCPServer *server, GSocket *socket, GSocketAddress *address, XD
}
/* Ignore duplicate requests */
- if (session->priv->started)
+ if (data->timeout_source == 0)
{
- if (session->priv->display_number != packet->Manage.display_number ||
- strcmp (session->priv->display_class, packet->Manage.display_class) != 0)
+ if (xdmcp_session_get_display_number (data->session) != packet->Manage.display_number ||
+ strcmp (xdmcp_session_get_display_class (data->session), packet->Manage.display_class) != 0)
g_debug ("Ignoring duplicate Manage with different data");
return;
}
/* Reject if has changed display number */
- if (packet->Manage.display_number != session->priv->display_number)
+ if (packet->Manage.display_number != xdmcp_session_get_display_number (data->session))
{
XDMCPPacket *response;
- g_debug ("Received Manage for display number %d, but Request was %d", packet->Manage.display_number, session->priv->display_number);
+ g_debug ("Received Manage for display number %d, but Request was %d", packet->Manage.display_number, xdmcp_session_get_display_number (data->session));
response = xdmcp_packet_alloc (XDMCP_Refuse);
response->Refuse.session_id = packet->Manage.session_id;
send_packet (socket, address, response);
xdmcp_packet_free (response);
}
- session->priv->display_class = g_strdup (packet->Manage.display_class);
+ xdmcp_session_set_display_class (data->session, packet->Manage.display_class);
gboolean result = FALSE;
- g_signal_emit (server, signals[NEW_SESSION], 0, session, &result);
+ g_signal_emit (server, signals[NEW_SESSION], 0, data->session, &result);
if (result)
{
/* Cancel the inactive timer */
- if (session->priv->inactive_timeout)
- g_source_remove (session->priv->inactive_timeout);
-
- session->priv->started = TRUE;
+ if (data->timeout_source != 0)
+ g_source_remove (data->timeout_source);
+ data->timeout_source = 0;
}
else
{
@@ -647,15 +679,12 @@ handle_manage (XDMCPServer *server, GSocket *socket, GSocketAddress *address, XD
static void
handle_keep_alive (XDMCPServer *server, GSocket *socket, GSocketAddress *address, XDMCPPacket *packet)
{
- XDMCPPacket *response;
- XDMCPSession *session;
+ SessionData *data = get_session_data (server, packet->KeepAlive.session_id);
gboolean alive = FALSE;
-
- session = get_session (server, packet->KeepAlive.session_id);
- if (session)
+ if (data)
alive = TRUE; // FIXME: xdmcp_session_get_alive (session);
- response = xdmcp_packet_alloc (XDMCP_Alive);
+ XDMCPPacket *response = xdmcp_packet_alloc (XDMCP_Alive);
response->Alive.session_running = alive;
response->Alive.session_id = alive ? packet->KeepAlive.session_id : 0;
send_packet (socket, address, response);
@@ -752,33 +781,35 @@ open_udp_socket (GSocketFamily family, guint port, const gchar *listen_address,
gboolean
xdmcp_server_start (XDMCPServer *server)
{
+ XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
+
g_return_val_if_fail (server != NULL, FALSE);
g_autoptr(GError) ipv4_error = NULL;
- server->priv->socket = open_udp_socket (G_SOCKET_FAMILY_IPV4, server->priv->port, server->priv->listen_address, &ipv4_error);
+ priv->socket = open_udp_socket (G_SOCKET_FAMILY_IPV4, priv->port, priv->listen_address, &ipv4_error);
if (ipv4_error)
g_warning ("Failed to create IPv4 XDMCP socket: %s", ipv4_error->message);
- if (server->priv->socket)
+ if (priv->socket)
{
- GSource *source = g_socket_create_source (server->priv->socket, G_IO_IN, NULL);
+ GSource *source = g_socket_create_source (priv->socket, G_IO_IN, NULL);
g_source_set_callback (source, (GSourceFunc) read_cb, server, NULL);
g_source_attach (source, NULL);
}
g_autoptr(GError) ipv6_error = NULL;
- server->priv->socket6 = open_udp_socket (G_SOCKET_FAMILY_IPV6, server->priv->port, server->priv->listen_address, &ipv6_error);
+ priv->socket6 = open_udp_socket (G_SOCKET_FAMILY_IPV6, priv->port, priv->listen_address, &ipv6_error);
if (ipv6_error)
g_warning ("Failed to create IPv6 XDMCP socket: %s", ipv6_error->message);
- if (server->priv->socket6)
+ if (priv->socket6)
{
- GSource *source = g_socket_create_source (server->priv->socket6, G_IO_IN, NULL);
+ GSource *source = g_socket_create_source (priv->socket6, G_IO_IN, NULL);
g_source_set_callback (source, (GSourceFunc) read_cb, server, NULL);
g_source_attach (source, NULL);
}
- if (!server->priv->socket && !server->priv->socket6)
+ if (!priv->socket && !priv->socket6)
return FALSE;
return TRUE;
@@ -787,26 +818,27 @@ xdmcp_server_start (XDMCPServer *server)
static void
xdmcp_server_init (XDMCPServer *server)
{
- server->priv = G_TYPE_INSTANCE_GET_PRIVATE (server, XDMCP_SERVER_TYPE, XDMCPServerPrivate);
+ XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
- server->priv->port = XDM_UDP_PORT;
- server->priv->hostname = g_strdup ("");
- server->priv->status = g_strdup ("");
- server->priv->sessions = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
+ priv->port = XDM_UDP_PORT;
+ priv->hostname = g_strdup ("");
+ priv->status = g_strdup ("");
+ priv->sessions = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) session_data_free);
}
static void
xdmcp_server_finalize (GObject *object)
{
XDMCPServer *self = XDMCP_SERVER (object);
-
- g_clear_object (&self->priv->socket);
- g_clear_object (&self->priv->socket6);
- g_clear_pointer (&self->priv->listen_address, g_free);
- g_clear_pointer (&self->priv->hostname, g_free);
- g_clear_pointer (&self->priv->status, g_free);
- g_clear_pointer (&self->priv->key, g_free);
- g_clear_pointer (&self->priv->sessions, g_hash_table_unref);
+ XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (self);
+
+ g_clear_object (&priv->socket);
+ g_clear_object (&priv->socket6);
+ g_clear_pointer (&priv->listen_address, g_free);
+ g_clear_pointer (&priv->hostname, g_free);
+ g_clear_pointer (&priv->status, g_free);
+ g_clear_pointer (&priv->key, g_free);
+ g_clear_pointer (&priv->sessions, g_hash_table_unref);
G_OBJECT_CLASS (xdmcp_server_parent_class)->finalize (object);
}