1 /*
2  * Copyright (C) 2010-2011 Robert Ancell.
3  * Author: Robert Ancell <robert.ancell@canonical.com>
4  *
5  * This program is free software: you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License as published by the Free Software
7  * Foundation, either version 3 of the License, or (at your option) any later
8  * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
9  * license.
10  */
11 
12 #include <stdlib.h>
13 #include <string.h>
14 #include <X11/X.h>
15 #define HASXDMAUTH
16 #include <X11/Xdmcp.h>
17 #include <gio/gio.h>
18 
19 #include "xdmcp-server.h"
20 #include "xdmcp-protocol.h"
21 #include "x-authority.h"
22 
23 enum {
24     NEW_SESSION,
25     LAST_SIGNAL
26 };
27 static guint signals[LAST_SIGNAL] = { 0 };
28 
29 typedef struct
30 {
31     /* Port to listen on */
32     guint port;
33 
34     /* Address to listen on */
35     gchar *listen_address;
36 
37     /* Listening sockets */
38     GSocket *socket, *socket6;
39 
40     /* Hostname to report to client */
41     gchar *hostname;
42 
43     /* Status to report to clients */
44     gchar *status;
45 
46     /* XDM-AUTHENTICATION-1 key */
47     gchar *key;
48 
49     /* Known XDMCP sessions */
50     GHashTable *sessions;
51 } XDMCPServerPrivate;
52 
53 G_DEFINE_TYPE_WITH_PRIVATE (XDMCPServer, xdmcp_server, G_TYPE_OBJECT)
54 
55 /* Maximum number of milliseconds client will resend manage requests before giving up */
56 #define MANAGE_TIMEOUT 126000
57 
58 /* Address sort support structure */
59 typedef struct
60 {
61     gsize index;
62     GInetAddress *address;
63 } AddrSortItem;
64 
65 XDMCPServer *
xdmcp_server_new(void)66 xdmcp_server_new (void)
67 {
68     return g_object_new (XDMCP_SERVER_TYPE, NULL);
69 }
70 
71 void
xdmcp_server_set_port(XDMCPServer * server,guint port)72 xdmcp_server_set_port (XDMCPServer *server, guint port)
73 {
74     XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
75     g_return_if_fail (server != NULL);
76     priv->port = port;
77 }
78 
79 guint
xdmcp_server_get_port(XDMCPServer * server)80 xdmcp_server_get_port (XDMCPServer *server)
81 {
82     XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
83     g_return_val_if_fail (server != NULL, 0);
84     return priv->port;
85 }
86 
87 void
xdmcp_server_set_listen_address(XDMCPServer * server,const gchar * listen_address)88 xdmcp_server_set_listen_address (XDMCPServer *server, const gchar *listen_address)
89 {
90     XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
91     g_return_if_fail (server != NULL);
92     g_free (priv->listen_address);
93     priv->listen_address = g_strdup (listen_address);
94 }
95 
96 const gchar *
xdmcp_server_get_listen_address(XDMCPServer * server)97 xdmcp_server_get_listen_address (XDMCPServer *server)
98 {
99     XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
100     g_return_val_if_fail (server != NULL, NULL);
101     return priv->listen_address;
102 }
103 
104 void
xdmcp_server_set_hostname(XDMCPServer * server,const gchar * hostname)105 xdmcp_server_set_hostname (XDMCPServer *server, const gchar *hostname)
106 {
107     XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
108     g_return_if_fail (server != NULL);
109     g_free (priv->hostname);
110     priv->hostname = g_strdup (hostname);
111 }
112 
113 const gchar *
xdmcp_server_get_hostname(XDMCPServer * server)114 xdmcp_server_get_hostname (XDMCPServer *server)
115 {
116     XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
117     g_return_val_if_fail (server != NULL, NULL);
118     return priv->hostname;
119 }
120 
121 void
xdmcp_server_set_status(XDMCPServer * server,const gchar * status)122 xdmcp_server_set_status (XDMCPServer *server, const gchar *status)
123 {
124     XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
125     g_return_if_fail (server != NULL);
126     g_free (priv->status);
127     priv->status = g_strdup (status);
128 }
129 
130 const gchar *
xdmcp_server_get_status(XDMCPServer * server)131 xdmcp_server_get_status (XDMCPServer *server)
132 {
133     XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
134     g_return_val_if_fail (server != NULL, NULL);
135     return priv->status;
136 }
137 
138 void
xdmcp_server_set_key(XDMCPServer * server,const gchar * key)139 xdmcp_server_set_key (XDMCPServer *server, const gchar *key)
140 {
141     XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
142     g_return_if_fail (server != NULL);
143     g_free (priv->key);
144     priv->key = g_strdup (key);
145 }
146 
147 typedef struct
148 {
149     XDMCPServer *server;
150     XDMCPSession *session;
151     guint timeout_source;
152 } SessionData;
153 
154 static void
session_data_free(SessionData * data)155 session_data_free (SessionData *data)
156 {
157     g_object_unref (data->session);
158     if (data->timeout_source != 0)
159         g_source_remove (data->timeout_source);
160     g_free (data);
161 }
162 
G_DEFINE_AUTOPTR_CLEANUP_FUNC(SessionData,session_data_free)163 G_DEFINE_AUTOPTR_CLEANUP_FUNC (SessionData, session_data_free)
164 
165 static gboolean
166 session_timeout_cb (gpointer user_data)
167 {
168     g_autoptr(SessionData) data = user_data;
169     XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (data->server);
170 
171     g_debug ("Timing out unmanaged session %d", xdmcp_session_get_id (data->session));
172     g_hash_table_remove (priv->sessions, GINT_TO_POINTER ((gint) xdmcp_session_get_id (data->session)));
173     return G_SOURCE_REMOVE;
174 }
175 
176 static XDMCPSession *
add_session(XDMCPServer * server,GInetAddress * address,guint16 display_number,XAuthority * authority)177 add_session (XDMCPServer *server, GInetAddress *address, guint16 display_number, XAuthority *authority)
178 {
179     XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
180 
181     guint16 id;
182     do
183     {
184         id = g_random_int () & 0xFFFFFFFF;
185     } while (g_hash_table_lookup (priv->sessions, GINT_TO_POINTER ((gint) id)));
186 
187     SessionData *data = g_malloc0 (sizeof (SessionData));
188     data->server = server;
189     data->session = xdmcp_session_new (id, address, display_number, authority);
190     data->timeout_source = g_timeout_add (MANAGE_TIMEOUT, session_timeout_cb, data);
191     g_hash_table_insert (priv->sessions, GINT_TO_POINTER ((gint) id), data);
192 
193     return data->session;
194 }
195 
196 static SessionData *
get_session_data(XDMCPServer * server,guint16 id)197 get_session_data (XDMCPServer *server, guint16 id)
198 {
199     XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
200     return g_hash_table_lookup (priv->sessions, GINT_TO_POINTER ((gint) id));
201 }
202 
203 static gchar *
socket_address_to_string(GSocketAddress * address)204 socket_address_to_string (GSocketAddress *address)
205 {
206     g_autofree gchar *inet_text = g_inet_address_to_string (g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (address)));
207     return g_strdup_printf ("%s:%d", inet_text, g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (address)));
208 }
209 
210 static void
send_packet(GSocket * socket,GSocketAddress * address,XDMCPPacket * packet)211 send_packet (GSocket *socket, GSocketAddress *address, XDMCPPacket *packet)
212 {
213     g_autofree gchar *address_string = socket_address_to_string (address);
214     g_debug ("Send %s to %s", xdmcp_packet_tostring (packet), address_string);
215 
216     guint8 data[1024];
217     gssize n_written = xdmcp_packet_encode (packet, data, 1024);
218     if (n_written < 0)
219         g_critical ("Failed to encode XDMCP packet");
220     else
221     {
222         g_autoptr(GError) error = NULL;
223         g_socket_send_to (socket, address, (gchar *) data, n_written, NULL, &error);
224         if (error)
225             g_warning ("Error sending packet: %s", error->message);
226     }
227 }
228 
229 static const gchar *
get_authentication_name(XDMCPServer * server)230 get_authentication_name (XDMCPServer *server)
231 {
232     XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
233     if (priv->key)
234         return "XDM-AUTHENTICATION-1";
235     else
236         return "";
237 }
238 
239 static void
handle_query(XDMCPServer * server,GSocket * socket,GSocketAddress * address,gchar ** authentication_names)240 handle_query (XDMCPServer *server, GSocket *socket, GSocketAddress *address, gchar **authentication_names)
241 {
242     XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
243 
244     /* If no authentication requested and we are configured for none then allow */
245     const gchar *authentication_name = NULL;
246     if (authentication_names[0] == NULL && priv->key == NULL)
247         authentication_name = "";
248 
249     for (gchar **i = authentication_names; *i; i++)
250     {
251         if (strcmp (*i, get_authentication_name (server)) == 0 && priv->key != NULL)
252         {
253             authentication_name = *i;
254             break;
255         }
256     }
257 
258     XDMCPPacket *response;
259     if (authentication_name)
260     {
261         response = xdmcp_packet_alloc (XDMCP_Willing);
262         response->Willing.authentication_name = g_strdup (authentication_name);
263         response->Willing.hostname = g_strdup (priv->hostname);
264         response->Willing.status = g_strdup (priv->status);
265     }
266     else
267     {
268         response = xdmcp_packet_alloc (XDMCP_Unwilling);
269         response->Unwilling.hostname = g_strdup (priv->hostname);
270         if (priv->key)
271             response->Unwilling.status = g_strdup_printf ("No matching authentication, server requires %s", get_authentication_name (server));
272         else
273             response->Unwilling.status = g_strdup ("No matching authentication");
274     }
275 
276     send_packet (socket, address, response);
277 
278     xdmcp_packet_free (response);
279 }
280 
281 static void
handle_forward_query(XDMCPServer * server,GSocket * socket,GSocketAddress * address,XDMCPPacket * packet)282 handle_forward_query (XDMCPServer *server, GSocket *socket, GSocketAddress *address, XDMCPPacket *packet)
283 {
284     GSocketFamily family = g_socket_get_family (socket);
285     switch (family)
286     {
287     case G_SOCKET_FAMILY_IPV4:
288         if (packet->ForwardQuery.client_address.length != 4)
289         {
290             g_warning ("Ignoring IPv4 XDMCP ForwardQuery with client address of length %d", packet->ForwardQuery.client_address.length);
291             return;
292         }
293         break;
294     case G_SOCKET_FAMILY_IPV6:
295         if (packet->ForwardQuery.client_address.length != 16)
296         {
297             g_warning ("Ignoring IPv6 XDMCP ForwardQuery with client address of length %d", packet->ForwardQuery.client_address.length);
298             return;
299         }
300         break;
301     default:
302         g_warning ("Unknown socket family %d", family);
303         return;
304     }
305 
306     guint16 port = 0;
307     for (int i = 0; i < packet->ForwardQuery.client_port.length; i++)
308         port = port << 8 | packet->ForwardQuery.client_port.data[i];
309 
310     g_autoptr(GInetAddress) client_inet_address = g_inet_address_new_from_bytes (packet->ForwardQuery.client_address.data, family);
311     g_autoptr(GSocketAddress) client_address = g_inet_socket_address_new (client_inet_address, port);
312 
313     handle_query (server, socket, client_address, packet->ForwardQuery.authentication_names);
314 }
315 
316 static guint8
atox(char c)317 atox (char c)
318 {
319     if (c >= '0' && c <= '9')
320         return c - '0';
321     if (c >= 'a' && c <= 'f')
322         return c - 'a' + 10;
323     if (c >= 'A' && c <= 'F')
324         return c - 'A' + 10;
325     return 0;
326 }
327 
328 static void
decode_key(const gchar * key,guint8 * data)329 decode_key (const gchar *key, guint8 *data)
330 {
331     memset (data, 0, 8);
332     if (strncmp (key, "0x", 2) == 0 || strncmp (key, "0X", 2) == 0)
333     {
334         for (gint i = 0; i < 8; i++)
335         {
336             if (key[i*2] == '\0')
337                 break;
338             data[i] |= atox (key[i*2]) << 8;
339             if (key[i*2+1] == '\0')
340                 break;
341             data[i] |= atox (key[i*2+1]);
342         }
343     }
344     else
345     {
346         for (gint i = 1; i < 8 && key[i-1]; i++)
347            data[i] = key[i-1];
348     }
349 }
350 
351 static GInetAddress *
connection_to_address(XDMCPConnection * connection)352 connection_to_address (XDMCPConnection *connection)
353 {
354     switch (connection->type)
355     {
356     case XAUTH_FAMILY_INTERNET:
357         if (connection->address.length == 4)
358             return g_inet_address_new_from_bytes (connection->address.data, G_SOCKET_FAMILY_IPV4);
359         else
360             return NULL;
361     case XAUTH_FAMILY_INTERNET6:
362         if (connection->address.length == 16)
363             return g_inet_address_new_from_bytes (connection->address.data, G_SOCKET_FAMILY_IPV6);
364         else
365             return NULL;
366     default:
367         return NULL;
368     }
369 }
370 
371 /* Sort function to order XDMCP addresses by which is best to connect to */
372 static gint
compare_addresses(gconstpointer a,gconstpointer b,gpointer user_data)373 compare_addresses (gconstpointer a, gconstpointer b, gpointer user_data)
374 {
375     const AddrSortItem *item_a = a;
376     const AddrSortItem *item_b = b;
377     GInetAddress *source_address = user_data;
378 
379     /* Prefer non link-local addresses */
380     gboolean is_link_local = g_inet_address_get_is_link_local (item_a->address);
381     if (is_link_local != g_inet_address_get_is_link_local (item_b->address))
382         return is_link_local ? 1 : -1;
383 
384     /* Prefer the source address family */
385     GSocketFamily family_a = g_inet_address_get_family (item_a->address);
386     GSocketFamily family_b = g_inet_address_get_family (item_b->address);
387     if (family_a != family_b)
388     {
389         GSocketFamily family = g_inet_address_get_family (source_address);
390         if (family_a == family)
391             return -1;
392         if (family_b == family)
393             return 1;
394         return family_a < family_b ? -1 : 1;
395     }
396 
397     /* Check equality */
398     if (g_inet_address_equal (item_a->address, item_b->address))
399         return 0;
400 
401     /* Prefer the source address */
402     if (g_inet_address_equal (source_address, item_a->address))
403         return -1;
404     if (g_inet_address_equal (source_address, item_b->address))
405         return 1;
406 
407     /* Addresses are not equal, but preferences are: order is undefined */
408     return 0;
409 }
410 
411 static XDMCPConnection *
choose_connection(XDMCPPacket * packet,GInetAddress * source_address)412 choose_connection (XDMCPPacket *packet, GInetAddress *source_address)
413 {
414     gsize addresses_length = packet->Request.n_connections;
415     if (addresses_length == 0)
416         return NULL;
417 
418     AddrSortItem addr;
419     GArray *addresses = g_array_sized_new (FALSE, FALSE, sizeof addr, addresses_length);
420     if (!addresses)
421         return NULL;
422 
423     for (gsize i = 0; i < addresses_length; i++)
424     {
425         addr.address = connection_to_address (&packet->Request.connections[i]);
426         if (addr.address)
427         {
428             addr.index = i;
429             g_array_append_val (addresses, addr);
430         }
431     }
432 
433     /* Sort the addresses according to our preferences */
434     g_array_sort_with_data (addresses, compare_addresses, source_address);
435 
436     /* Use the best address */
437     gssize index = -1;
438     if (addresses->len)
439         index = g_array_index (addresses, AddrSortItem, 0).index;
440 
441     /* Free the local sort array and items */
442     for (gsize i = 0; i < addresses->len; i++)
443         g_object_unref (g_array_index (addresses, AddrSortItem, i).address);
444     g_array_unref (addresses);
445 
446     return index >= 0 ? &packet->Request.connections[index] : NULL;
447 }
448 
449 static gboolean
has_string(gchar ** list,const gchar * text)450 has_string (gchar **list, const gchar *text)
451 {
452     for (gchar **i = list; *i; i++)
453         if (strcmp (*i, text) == 0)
454             return TRUE;
455 
456     return FALSE;
457 }
458 
459 static void
handle_request(XDMCPServer * server,GSocket * socket,GSocketAddress * address,XDMCPPacket * packet)460 handle_request (XDMCPServer *server, GSocket *socket, GSocketAddress *address, XDMCPPacket *packet)
461 {
462     XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
463 
464     /* Check authentication */
465     g_autofree gchar *authentication_name = NULL;
466     g_autofree guint8 *authentication_data = NULL;
467     gsize authentication_data_length = 0;
468     g_autofree gchar *decline_status = NULL;
469     XdmAuthKeyRec rho;
470     if (strcmp (packet->Request.authentication_name, "") == 0)
471     {
472         if (!priv->key)
473         {
474             if (!has_string (packet->Request.authorization_names, "MIT-MAGIC-COOKIE-1"))
475                 decline_status = g_strdup ("No matching authorization, server requires MIT-MAGIC-COOKIE-1");
476         }
477         else
478             decline_status = g_strdup ("No matching authentication, server requires XDM-AUTHENTICATION-1");
479     }
480     else if (strcmp (packet->Request.authentication_name, "XDM-AUTHENTICATION-1") == 0 && priv->key)
481     {
482         if (packet->Request.authentication_data.length == 8)
483         {
484             guint8 input[8], key[8];
485 
486             memcpy (input, packet->Request.authentication_data.data, packet->Request.authentication_data.length);
487 
488             /* Setup key */
489             decode_key (priv->key, key);
490 
491             /* Decode message from server */
492             authentication_name = g_strdup ("XDM-AUTHENTICATION-1");
493             authentication_data = g_malloc (sizeof (guint8) * 8);
494             authentication_data_length = 8;
495 
496             XdmcpUnwrap (input, key, rho.data, authentication_data_length);
497             XdmcpIncrementKey (&rho);
498             XdmcpWrap (rho.data, key, authentication_data, authentication_data_length);
499 
500             if (!has_string (packet->Request.authorization_names, "XDM-AUTHORIZATION-1"))
501                 decline_status = g_strdup ("No matching authorization, server requires XDM-AUTHORIZATION-1");
502         }
503         else
504             decline_status = g_strdup ("Invalid XDM-AUTHENTICATION-1 data provided");
505     }
506     else
507     {
508         if (strcmp (packet->Request.authentication_name, "") == 0)
509             decline_status = g_strdup_printf ("No matching authentication, server does not support unauthenticated connections");
510         else if (priv->key)
511             decline_status = g_strdup ("No matching authentication, server requires XDM-AUTHENTICATION-1");
512         else
513             decline_status = g_strdup ("No matching authentication, server only supports unauthenticated connections");
514     }
515 
516     /* Choose an address to connect back on */
517     XDMCPConnection *connection = choose_connection (packet, g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (address)));
518     if (!connection && !decline_status)
519         decline_status = g_strdup ("No valid address found");
520 
521     if (!authentication_name)
522         authentication_name = g_strdup ("");
523 
524     /* Decline if request was not valid */
525     if (decline_status)
526     {
527         XDMCPPacket *response = xdmcp_packet_alloc (XDMCP_Decline);
528         response->Decline.status = g_steal_pointer (&decline_status);
529         response->Decline.authentication_name = g_steal_pointer (&authentication_name);
530         response->Decline.authentication_data.data = g_steal_pointer (&authentication_data);
531         response->Decline.authentication_data.length = authentication_data_length;
532         send_packet (socket, address, response);
533         xdmcp_packet_free (response);
534         return;
535     }
536 
537     /* Generate authorization data */
538     g_autofree gchar *authorization_name = NULL;
539     g_autofree guint8 *authorization_data = NULL;
540     gsize authorization_data_length = 0;
541     g_autofree guint8 *session_authorization_data = NULL;
542     gsize session_authorization_data_length = 0;
543     if (priv->key)
544     {
545         /* Setup key */
546         guint8 key[8];
547         decode_key (priv->key, key);
548 
549         /* Generate a private session key */
550         // FIXME: Pick a good DES key?
551         guint8 session_key[8];
552         session_key[0] = 0;
553         for (gint i = 1; i < 8; i++)
554             session_key[i] = g_random_int () & 0xFF;
555 
556         /* Encrypt the session key and send it to the server */
557         authorization_data = g_malloc (8);
558         authorization_data_length = 8;
559         XdmcpWrap (session_key, key, authorization_data, authorization_data_length);
560 
561         /* Authorization data is the number received from the client followed by the private session key */
562         authorization_name = g_strdup ("XDM-AUTHORIZATION-1");
563         session_authorization_data = g_malloc (16);
564         session_authorization_data_length = 16;
565         XdmcpDecrementKey (&rho);
566         memcpy (session_authorization_data, rho.data, 8);
567         memcpy (session_authorization_data + 8, session_key, 8);
568     }
569     else
570     {
571         /* Data is the cookie */
572         g_autoptr(XAuthority) auth = x_authority_new_cookie (XAUTH_FAMILY_WILD, NULL, 0, "");
573         authorization_data = x_authority_copy_authorization_data (auth);
574         authorization_data_length = x_authority_get_authorization_data_length (auth);
575         authorization_name = g_strdup ("MIT-MAGIC-COOKIE-1");
576         session_authorization_data = x_authority_copy_authorization_data (auth);
577         session_authorization_data_length = x_authority_get_authorization_data_length (auth);
578     }
579 
580     /* We need to check if this is the loopback address and set the authority
581      * for a local connection if this is so as XCB treats "127.0.0.1" as local
582      * always */
583     g_autoptr(GInetAddress) session_address = connection_to_address (connection);
584     g_autofree gchar *display_number = g_strdup_printf ("%d", packet->Request.display_number);
585     g_autoptr(XAuthority) authority = NULL;
586     if (g_inet_address_get_is_loopback (session_address))
587     {
588         gchar hostname[1024];
589         gethostname (hostname, 1024);
590 
591         authority = x_authority_new (XAUTH_FAMILY_LOCAL,
592                                      (guint8 *) hostname,
593                                      strlen (hostname),
594                                      display_number,
595                                      authorization_name,
596                                      session_authorization_data,
597                                      session_authorization_data_length);
598     }
599     else
600         authority = x_authority_new (connection->type,
601                                      connection->address.data,
602                                      connection->address.length,
603                                      display_number,
604                                      authorization_name,
605                                      session_authorization_data,
606                                      session_authorization_data_length);
607 
608     XDMCPSession *session = add_session (server, session_address, packet->Request.display_number, authority);
609 
610     XDMCPPacket *response = xdmcp_packet_alloc (XDMCP_Accept);
611     response->Accept.session_id = xdmcp_session_get_id (session);
612     response->Accept.authentication_name = g_steal_pointer (&authentication_name);
613     response->Accept.authentication_data.data = g_steal_pointer (&authentication_data);
614     response->Accept.authentication_data.length = authentication_data_length;
615     response->Accept.authorization_name = g_steal_pointer (&authorization_name);
616     response->Accept.authorization_data.data = g_steal_pointer (&authorization_data);
617     response->Accept.authorization_data.length = authorization_data_length;
618     send_packet (socket, address, response);
619     xdmcp_packet_free (response);
620 }
621 
622 static void
handle_manage(XDMCPServer * server,GSocket * socket,GSocketAddress * address,XDMCPPacket * packet)623 handle_manage (XDMCPServer *server, GSocket *socket, GSocketAddress *address, XDMCPPacket *packet)
624 {
625     SessionData *data = get_session_data (server, packet->Manage.session_id);
626     if (!data->session)
627     {
628         XDMCPPacket *response = xdmcp_packet_alloc (XDMCP_Refuse);
629         response->Refuse.session_id = packet->Manage.session_id;
630         send_packet (socket, address, response);
631         xdmcp_packet_free (response);
632         return;
633     }
634 
635     /* Ignore duplicate requests */
636     if (data->timeout_source == 0)
637     {
638         if (xdmcp_session_get_display_number (data->session) != packet->Manage.display_number ||
639             strcmp (xdmcp_session_get_display_class (data->session), packet->Manage.display_class) != 0)
640             g_debug ("Ignoring duplicate Manage with different data");
641         return;
642     }
643 
644     /* Reject if has changed display number */
645     if (packet->Manage.display_number != xdmcp_session_get_display_number (data->session))
646     {
647         XDMCPPacket *response;
648 
649         g_debug ("Received Manage for display number %d, but Request was %d", packet->Manage.display_number, xdmcp_session_get_display_number (data->session));
650         response = xdmcp_packet_alloc (XDMCP_Refuse);
651         response->Refuse.session_id = packet->Manage.session_id;
652         send_packet (socket, address, response);
653         xdmcp_packet_free (response);
654     }
655 
656     xdmcp_session_set_display_class (data->session, packet->Manage.display_class);
657 
658     gboolean result = FALSE;
659     g_signal_emit (server, signals[NEW_SESSION], 0, data->session, &result);
660     if (result)
661     {
662         /* Cancel the inactive timer */
663         if (data->timeout_source != 0)
664             g_source_remove (data->timeout_source);
665         data->timeout_source = 0;
666     }
667     else
668     {
669         XDMCPPacket *response;
670 
671         response = xdmcp_packet_alloc (XDMCP_Failed);
672         response->Failed.session_id = packet->Manage.session_id;
673         response->Failed.status = g_strdup_printf ("Failed to connect to display :%d", packet->Manage.display_number);
674         send_packet (socket, address, response);
675         xdmcp_packet_free (response);
676     }
677 }
678 
679 static void
handle_keep_alive(XDMCPServer * server,GSocket * socket,GSocketAddress * address,XDMCPPacket * packet)680 handle_keep_alive (XDMCPServer *server, GSocket *socket, GSocketAddress *address, XDMCPPacket *packet)
681 {
682     SessionData *data = get_session_data (server, packet->KeepAlive.session_id);
683     gboolean alive = FALSE;
684     if (data)
685         alive = TRUE; // FIXME: xdmcp_session_get_alive (session);
686 
687     XDMCPPacket *response = xdmcp_packet_alloc (XDMCP_Alive);
688     response->Alive.session_running = alive;
689     response->Alive.session_id = alive ? packet->KeepAlive.session_id : 0;
690     send_packet (socket, address, response);
691     xdmcp_packet_free (response);
692 }
693 
694 static gboolean
read_cb(GSocket * socket,GIOCondition condition,XDMCPServer * server)695 read_cb (GSocket *socket, GIOCondition condition, XDMCPServer *server)
696 {
697     GSocketAddress *address;
698     gchar data[1024];
699     g_autoptr(GError) error = NULL;
700     gssize n_read;
701 
702     n_read = g_socket_receive_from (socket, &address, data, 1024, NULL, &error);
703     if (error)
704         g_warning ("Failed to read from XDMCP socket: %s", error->message);
705 
706     if (n_read > 0)
707     {
708         XDMCPPacket *packet;
709 
710         packet = xdmcp_packet_decode ((guint8 *)data, n_read);
711         if (packet)
712         {
713             g_autofree gchar *packet_string = NULL;
714             g_autofree gchar *address_string = NULL;
715 
716             packet_string = xdmcp_packet_tostring (packet);
717             address_string = socket_address_to_string (address);
718             g_debug ("Got %s from %s", packet_string, address_string);
719 
720             switch (packet->opcode)
721             {
722             case XDMCP_BroadcastQuery:
723             case XDMCP_Query:
724             case XDMCP_IndirectQuery:
725                 handle_query (server, socket, address, packet->Query.authentication_names);
726                 break;
727             case XDMCP_ForwardQuery:
728                 handle_forward_query (server, socket, address, packet);
729                 break;
730             case XDMCP_Request:
731                 handle_request (server, socket, address, packet);
732                 break;
733             case XDMCP_Manage:
734                 handle_manage (server, socket, address, packet);
735                 break;
736             case XDMCP_KeepAlive:
737                 handle_keep_alive (server, socket, address, packet);
738                 break;
739             default:
740                 g_warning ("Got unexpected XDMCP packet %d", packet->opcode);
741                 break;
742             }
743 
744             xdmcp_packet_free (packet);
745         }
746     }
747 
748     return TRUE;
749 }
750 
751 static GSocket *
open_udp_socket(GSocketFamily family,guint port,const gchar * listen_address,GError ** error)752 open_udp_socket (GSocketFamily family, guint port, const gchar *listen_address, GError **error)
753 {
754     g_autoptr(GSocket) socket = NULL;
755     g_autoptr(GSocketAddress) address = NULL;
756     gboolean result;
757 
758     socket = g_socket_new (family, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, error);
759     if (!socket)
760         return NULL;
761 
762     if (listen_address)
763     {
764         GList *addresses;
765 
766         addresses = g_resolver_lookup_by_name (g_resolver_get_default (), listen_address, NULL, error);
767         if (!addresses)
768             return NULL;
769         address = g_inet_socket_address_new (addresses->data, port);
770         g_resolver_free_addresses (addresses);
771     }
772     else
773         address = g_inet_socket_address_new (g_inet_address_new_any (family), port);
774     result = g_socket_bind (socket, address, TRUE, error);
775     if (!result)
776         return NULL;
777 
778     return g_steal_pointer (&socket);
779 }
780 
781 gboolean
xdmcp_server_start(XDMCPServer * server)782 xdmcp_server_start (XDMCPServer *server)
783 {
784     XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
785 
786     g_return_val_if_fail (server != NULL, FALSE);
787 
788     g_autoptr(GError) ipv4_error = NULL;
789     priv->socket = open_udp_socket (G_SOCKET_FAMILY_IPV4, priv->port, priv->listen_address, &ipv4_error);
790     if (ipv4_error)
791         g_warning ("Failed to create IPv4 XDMCP socket: %s", ipv4_error->message);
792 
793     if (priv->socket)
794     {
795         GSource *source = g_socket_create_source (priv->socket, G_IO_IN, NULL);
796         g_source_set_callback (source, (GSourceFunc) read_cb, server, NULL);
797         g_source_attach (source, NULL);
798     }
799 
800     g_autoptr(GError) ipv6_error = NULL;
801     priv->socket6 = open_udp_socket (G_SOCKET_FAMILY_IPV6, priv->port, priv->listen_address, &ipv6_error);
802     if (ipv6_error)
803         g_warning ("Failed to create IPv6 XDMCP socket: %s", ipv6_error->message);
804 
805     if (priv->socket6)
806     {
807         GSource *source = g_socket_create_source (priv->socket6, G_IO_IN, NULL);
808         g_source_set_callback (source, (GSourceFunc) read_cb, server, NULL);
809         g_source_attach (source, NULL);
810     }
811 
812     if (!priv->socket && !priv->socket6)
813         return FALSE;
814 
815     return TRUE;
816 }
817 
818 static void
xdmcp_server_init(XDMCPServer * server)819 xdmcp_server_init (XDMCPServer *server)
820 {
821     XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (server);
822 
823     priv->port = XDM_UDP_PORT;
824     priv->hostname = g_strdup ("");
825     priv->status = g_strdup ("");
826     priv->sessions = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) session_data_free);
827 }
828 
829 static void
xdmcp_server_finalize(GObject * object)830 xdmcp_server_finalize (GObject *object)
831 {
832     XDMCPServer *self = XDMCP_SERVER (object);
833     XDMCPServerPrivate *priv = xdmcp_server_get_instance_private (self);
834 
835     g_clear_object (&priv->socket);
836     g_clear_object (&priv->socket6);
837     g_clear_pointer (&priv->listen_address, g_free);
838     g_clear_pointer (&priv->hostname, g_free);
839     g_clear_pointer (&priv->status, g_free);
840     g_clear_pointer (&priv->key, g_free);
841     g_clear_pointer (&priv->sessions, g_hash_table_unref);
842 
843     G_OBJECT_CLASS (xdmcp_server_parent_class)->finalize (object);
844 }
845 
846 static void
xdmcp_server_class_init(XDMCPServerClass * klass)847 xdmcp_server_class_init (XDMCPServerClass *klass)
848 {
849     GObjectClass *object_class = G_OBJECT_CLASS (klass);
850 
851     object_class->finalize = xdmcp_server_finalize;
852 
853     signals[NEW_SESSION] =
854         g_signal_new (XDMCP_SERVER_SIGNAL_NEW_SESSION,
855                       G_TYPE_FROM_CLASS (klass),
856                       G_SIGNAL_RUN_LAST,
857                       G_STRUCT_OFFSET (XDMCPServerClass, new_session),
858                       g_signal_accumulator_true_handled,
859                       NULL,
860                       NULL,
861                       G_TYPE_BOOLEAN, 1, XDMCP_SESSION_TYPE);
862 }
863