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