2
2
* Copyright (C) 2010-2011 Robert Ancell.
3
3
* Author: Robert Ancell <robert.ancell@canonical.com>
5
5
* This program is free software: you can redistribute it and/or modify it under
6
6
* the terms of the GNU General Public License as published by the Free Software
7
7
* Foundation, either version 3 of the License, or (at your option) any later
80
xdmcp_server_set_listen_address (XDMCPServer *server, const gchar *listen_address)
82
g_return_if_fail (server != NULL);
84
g_free (server->priv->listen_address);
85
server->priv->listen_address = g_strdup (listen_address);
89
xdmcp_server_get_listen_address (XDMCPServer *server)
91
g_return_val_if_fail (server != NULL, NULL);
92
return server->priv->listen_address;
77
96
xdmcp_server_set_hostname (XDMCPServer *server, const gchar *hostname)
79
98
g_return_if_fail (server != NULL);
117
136
session_timeout_cb (XDMCPSession *session)
138
session->priv->inactive_timeout = 0;
119
140
g_debug ("Timing out unmanaged session %d", session->priv->id);
120
141
g_hash_table_remove (session->priv->server->priv->sessions, GINT_TO_POINTER ((gint) session->priv->id));
153
174
gssize n_written;
155
176
g_debug ("Send %s", xdmcp_packet_tostring (packet));
157
178
n_written = xdmcp_packet_encode (packet, data, 1024);
158
179
if (n_written < 0)
159
180
g_critical ("Failed to encode XDMCP packet");
280
static GInetAddress *
281
connection_to_address (XDMCPConnection *connection)
283
switch (connection->type)
285
case XAUTH_FAMILY_INTERNET:
286
if (connection->address.length == 4)
287
return g_inet_address_new_from_bytes (connection->address.data, G_SOCKET_FAMILY_IPV4);
290
case XAUTH_FAMILY_INTERNET6:
291
if (connection->address.length == 16)
292
return g_inet_address_new_from_bytes (connection->address.data, G_SOCKET_FAMILY_IPV6);
301
find_address (GInetAddress **addresses, gsize length, GSocketFamily family)
305
for (i = 0; i < length; i++)
307
GInetAddress *address = addresses[i];
308
if (address && g_inet_address_get_family (address) == family)
315
static XDMCPConnection *
316
choose_connection (XDMCPPacket *packet, GInetAddress *source_address)
318
GInetAddress **addresses;
319
gsize addresses_length, i;
322
addresses_length = packet->Request.n_connections;
323
addresses = malloc (sizeof (GInetAddress *) * addresses_length);
324
for (i = 0; i < addresses_length; i++)
325
addresses[i] = connection_to_address (&packet->Request.connections[i]);
327
/* Use the address the request came in on as this is the least likely to have firewall / routing issues */
328
for (i = 0; i < addresses_length && index < 0; i++)
329
if (g_inet_address_equal (source_address, addresses[i]))
332
/* Otherwise try and find an address that matches the incoming type */
334
index = find_address (addresses, addresses_length, g_inet_address_get_family (source_address));
336
/* Otherwise use the first available */
337
if (index < 0 && addresses_length > 0)
340
for (i = 0; i < addresses_length; i++)
341
g_object_unref (addresses[i]);
344
return &packet->Request.connections[index];
260
348
handle_request (XDMCPServer *server, GSocket *socket, GSocketAddress *address, XDMCPPacket *packet)
263
350
XDMCPPacket *response;
264
351
XDMCPSession *session;
265
352
guint8 *authentication_data = NULL;
271
358
guint8 *session_authorization_data = NULL;
272
359
gsize session_authorization_data_length = 0;
275
GInetAddress *x_server_address = NULL;
361
XDMCPConnection *connection;
276
362
gchar *display_number;
277
363
XdmAuthKeyRec rho;
279
/* Try and find an IPv6 address */
280
for (i = 0; i < packet->Request.n_connections; i++)
282
XDMCPConnection *connection = &packet->Request.connections[i];
283
if (connection->type == XAUTH_FAMILY_INTERNET6 && connection->address.length == 16)
285
family = connection->type;
286
x_server_address = g_inet_address_new_from_bytes (connection->address.data, G_SOCKET_FAMILY_IPV6);
288
/* We can't use link-local addresses, as we need to know what interface it is on */
289
if (g_inet_address_get_is_link_local (x_server_address))
291
g_object_unref (x_server_address);
292
x_server_address = NULL;
299
/* If no IPv6 address, then try and find an IPv4 one */
300
if (!x_server_address)
302
for (i = 0; i < packet->Request.n_connections; i++)
304
XDMCPConnection *connection = &packet->Request.connections[i];
305
if (connection->type == XAUTH_FAMILY_INTERNET && connection->address.length == 4)
307
family = connection->type;
308
x_server_address = g_inet_address_new_from_bytes (connection->address.data, G_SOCKET_FAMILY_IPV4);
365
/* Choose an address to connect back on */
366
connection = choose_connection (packet, g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (address)));
314
368
/* Decline if haven't got an address we can connect on */
315
if (!x_server_address)
317
371
response = xdmcp_packet_alloc (XDMCP_Decline);
318
372
response->Decline.status = g_strdup ("No valid address found");
430
484
session = add_session (server);
431
session->priv->address = x_server_address;
485
session->priv->address = connection_to_address (connection);
432
486
session->priv->display_number = packet->Request.display_number;
433
487
display_number = g_strdup_printf ("%d", packet->Request.display_number);
435
489
/* We need to check if this is the loopback address and set the authority
436
490
* for a local connection if this is so as XCB treats "127.0.0.1" as local
438
if (g_inet_address_get_is_loopback (x_server_address))
492
if (g_inet_address_get_is_loopback (session->priv->address))
440
494
gchar hostname[1024];
441
495
gethostname (hostname, 1024);
443
497
session->priv->authority = x_authority_new (XAUTH_FAMILY_LOCAL,
448
session_authorization_data,
449
session_authorization_data_length);
502
session_authorization_data,
503
session_authorization_data_length);
452
session->priv->authority = x_authority_new (family,
453
g_inet_address_to_bytes (G_INET_ADDRESS (x_server_address)),
454
g_inet_address_get_native_size (G_INET_ADDRESS (x_server_address)),
457
session_authorization_data,
458
session_authorization_data_length);
506
session->priv->authority = x_authority_new (connection->type,
507
connection->address.data,
508
connection->address.length,
511
session_authorization_data,
512
session_authorization_data_length);
459
513
g_free (display_number);
461
515
response = xdmcp_packet_alloc (XDMCP_Accept);
518
572
/* Cancel the inactive timer */
519
g_source_remove (session->priv->inactive_timeout);
573
if (session->priv->inactive_timeout)
574
g_source_remove (session->priv->inactive_timeout);
521
576
session->priv->started = TRUE;
583
638
handle_request (server, socket, address, packet);
585
640
case XDMCP_Manage:
586
handle_manage (server, socket, address, packet);
641
handle_manage (server, socket, address, packet);
588
643
case XDMCP_KeepAlive:
589
644
handle_keep_alive (server, socket, address, packet);
604
open_udp_socket (GSocketFamily family, guint port, GError **error)
659
open_udp_socket (GSocketFamily family, guint port, const gchar *listen_address, GError **error)
607
662
GSocketAddress *address;
610
665
socket = g_socket_new (family, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, error);
614
address = g_inet_socket_address_new (g_inet_address_new_any (family), port);
673
addresses = g_resolver_lookup_by_name (g_resolver_get_default (), listen_address, NULL, error);
676
g_object_unref (socket);
679
address = g_inet_socket_address_new (addresses->data, port);
680
g_resolver_free_addresses (addresses);
683
address = g_inet_socket_address_new (g_inet_address_new_any (family), port);
615
684
result = g_socket_bind (socket, address, TRUE, error);
629
698
GError *error = NULL;
631
700
g_return_val_if_fail (server != NULL, FALSE);
633
server->priv->socket = open_udp_socket (G_SOCKET_FAMILY_IPV4, server->priv->port, &error);
702
server->priv->socket = open_udp_socket (G_SOCKET_FAMILY_IPV4, server->priv->port, server->priv->listen_address, &error);
635
704
g_warning ("Failed to create IPv4 XDMCP socket: %s", error->message);
636
705
g_clear_error (&error);
638
707
if (server->priv->socket)
640
709
source = g_socket_create_source (server->priv->socket, G_IO_IN, NULL);
641
710
g_source_set_callback (source, (GSourceFunc) read_cb, server, NULL);
642
711
g_source_attach (source, NULL);
645
server->priv->socket6 = open_udp_socket (G_SOCKET_FAMILY_IPV6, server->priv->port, &error);
714
server->priv->socket6 = open_udp_socket (G_SOCKET_FAMILY_IPV6, server->priv->port, server->priv->listen_address, &error);
647
716
g_warning ("Failed to create IPv6 XDMCP socket: %s", error->message);
648
717
g_clear_error (&error);
677
746
XDMCPServer *self;
679
748
self = XDMCP_SERVER (object);
681
750
if (self->priv->socket)
682
751
g_object_unref (self->priv->socket);
683
752
if (self->priv->socket6)
684
753
g_object_unref (self->priv->socket6);
754
g_free (self->priv->listen_address);
685
755
g_free (self->priv->hostname);
686
756
g_free (self->priv->status);
687
757
g_free (self->priv->key);
688
758
g_hash_table_unref (self->priv->sessions);
690
G_OBJECT_CLASS (xdmcp_server_parent_class)->finalize (object);
760
G_OBJECT_CLASS (xdmcp_server_parent_class)->finalize (object);
696
766
GObjectClass *object_class = G_OBJECT_CLASS (klass);
698
object_class->finalize = xdmcp_server_finalize;
768
object_class->finalize = xdmcp_server_finalize;
700
770
g_type_class_add_private (klass, sizeof (XDMCPServerPrivate));
702
772
signals[NEW_SESSION] =
703
g_signal_new ("new-session",
773
g_signal_new (XDMCP_SERVER_SIGNAL_NEW_SESSION,
704
774
G_TYPE_FROM_CLASS (klass),
705
775
G_SIGNAL_RUN_LAST,
706
776
G_STRUCT_OFFSET (XDMCPServerClass, new_session),