2 * Copyright (C) 2010-2011 Robert Ancell.
3 * Author: Robert Ancell <robert.ancell@canonical.com>
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
15 #include "xdmcp-protocol.h"
16 #include "x-authority.h"
26 read_card8 (PacketReader *reader)
30 if (reader->remaining < 1)
32 reader->overflow = TRUE;
36 value = reader->data[0];
44 read_card16 (PacketReader *reader)
46 return read_card8 (reader) << 8 | read_card8 (reader);
50 read_card32 (PacketReader *reader)
52 return read_card8 (reader) << 24 | read_card8 (reader) << 16 | read_card8 (reader) << 8 | read_card8 (reader);
56 read_data (PacketReader *reader, XDMCPData *data)
60 data->length = read_card16 (reader);
61 data->data = g_malloc (sizeof (guint8) * data->length);
62 for (i = 0; i < data->length; i++)
63 data->data[i] = read_card8 (reader);
67 read_string (PacketReader *reader)
72 length = read_card16 (reader);
73 string = g_malloc (sizeof (gchar) * (length + 1));
74 for (i = 0; i < length; i++)
75 string[i] = (gchar) read_card8 (reader);
82 read_string_array (PacketReader *reader)
87 n_strings = read_card8 (reader);
88 strings = g_malloc (sizeof (gchar *) * (n_strings + 1));
89 for (i = 0; i < n_strings; i++)
90 strings[i] = read_string (reader);
104 write_card8 (PacketWriter *writer, guint8 value)
106 if (writer->remaining < 1)
108 writer->overflow = TRUE;
112 writer->data[0] = value;
118 write_card16 (PacketWriter *writer, guint16 value)
120 write_card8 (writer, value >> 8);
121 write_card8 (writer, value & 0xFF);
125 write_card32 (PacketWriter *writer, guint32 value)
127 write_card8 (writer, (value >> 24) & 0xFF);
128 write_card8 (writer, (value >> 16) & 0xFF);
129 write_card8 (writer, (value >> 8) & 0xFF);
130 write_card8 (writer, value & 0xFF);
134 write_data (PacketWriter *writer, const XDMCPData *value)
138 write_card16 (writer, value->length);
139 for (i = 0; i < value->length; i++)
140 write_card8 (writer, value->data[i]);
144 write_string (PacketWriter *writer, const gchar *value)
148 write_card16 (writer, strlen (value));
149 for (c = value; *c; c++)
150 write_card8 (writer, *c);
154 write_string_array (PacketWriter *writer, gchar **values)
158 write_card8 (writer, g_strv_length (values));
159 for (value = values; *value; value++)
160 write_string (writer, *value);
164 xdmcp_packet_alloc (XDMCPOpcode opcode)
168 packet = g_malloc0 (sizeof (XDMCPPacket));
169 packet->opcode = opcode;
175 xdmcp_packet_decode (const guint8 *data, gsize data_length)
178 guint16 version, opcode, length;
181 gboolean failed = FALSE;
184 reader.remaining = data_length;
185 reader.overflow = FALSE;
187 version = read_card16 (&reader);
188 opcode = read_card16 (&reader);
189 length = read_card16 (&reader);
193 g_warning ("Ignoring short packet"); // FIXME: Use GError
196 if (version != XDMCP_VERSION)
198 g_warning ("Ignoring packet from unknown version %d", version);
201 if (length != reader.remaining)
203 g_warning ("Ignoring packet of wrong length. Opcode %d expected %d octets, got %d", opcode, length, reader.remaining);
207 packet = xdmcp_packet_alloc (opcode);
208 switch (packet->opcode)
210 case XDMCP_BroadcastQuery:
212 case XDMCP_IndirectQuery:
213 packet->Query.authentication_names = read_string_array (&reader);
215 case XDMCP_ForwardQuery:
216 packet->ForwardQuery.client_address = read_string (&reader);
217 packet->ForwardQuery.client_port = read_string (&reader);
218 packet->ForwardQuery.authentication_names = read_string_array (&reader);
221 packet->Willing.authentication_name = read_string (&reader);
222 packet->Willing.hostname = read_string (&reader);
223 packet->Willing.status = read_string (&reader);
225 case XDMCP_Unwilling:
226 packet->Unwilling.hostname = read_string (&reader);
227 packet->Unwilling.status = read_string (&reader);
230 packet->Request.display_number = read_card16 (&reader);
231 packet->Request.n_connections = read_card8 (&reader);
232 packet->Request.connections = g_malloc (sizeof (XDMCPConnection) * packet->Request.n_connections);
233 for (i = 0; i < packet->Request.n_connections; i++)
234 packet->Request.connections[i].type = read_card16 (&reader);
235 if (read_card8 (&reader) != packet->Request.n_connections)
237 g_warning ("Number of connection types does not match number of connection addresses");
240 for (i = 0; i < packet->Request.n_connections; i++)
241 read_data (&reader, &packet->Request.connections[i].address);
242 packet->Request.authentication_name = read_string (&reader);
243 read_data (&reader, &packet->Request.authentication_data);
244 packet->Request.authorization_names = read_string_array (&reader);
245 packet->Request.manufacturer_display_id = read_string (&reader);
248 packet->Accept.session_id = read_card32 (&reader);
249 packet->Accept.authentication_name = read_string (&reader);
250 read_data (&reader, &packet->Accept.authentication_data);
251 packet->Accept.authorization_name = read_string (&reader);
252 read_data (&reader, &packet->Accept.authorization_data);
255 packet->Decline.status = read_string (&reader);
256 packet->Decline.authentication_name = read_string (&reader);
257 read_data (&reader, &packet->Decline.authentication_data);
260 packet->Manage.session_id = read_card32 (&reader);
261 packet->Manage.display_number = read_card16 (&reader);
262 packet->Manage.display_class = read_string (&reader);
265 packet->Refuse.session_id = read_card32 (&reader);
268 packet->Failed.session_id = read_card32 (&reader);
269 packet->Failed.status = read_string (&reader);
271 case XDMCP_KeepAlive:
272 packet->KeepAlive.display_number = read_card16 (&reader);
273 packet->KeepAlive.session_id = read_card32 (&reader);
276 packet->Alive.session_running = read_card8 (&reader) == 0 ? FALSE : TRUE;
277 packet->Alive.session_id = read_card32 (&reader);
280 g_warning ("Unable to encode unknown opcode %d", packet->opcode);
289 g_warning ("Short packet received");
292 else if (reader.remaining != 0)
294 g_warning ("Extra data on end of message");
300 xdmcp_packet_free (packet);
308 xdmcp_packet_encode (XDMCPPacket *packet, guint8 *data, gsize max_length)
317 writer.data = data + 6;
318 writer.remaining = max_length - 6;
319 writer.overflow = FALSE;
321 switch (packet->opcode)
323 case XDMCP_BroadcastQuery:
325 case XDMCP_IndirectQuery:
326 write_string_array (&writer, packet->Query.authentication_names);
328 case XDMCP_ForwardQuery:
329 write_string (&writer, packet->ForwardQuery.client_address);
330 write_string (&writer, packet->ForwardQuery.client_port);
331 write_string_array (&writer, packet->ForwardQuery.authentication_names);
334 write_string (&writer, packet->Willing.authentication_name);
335 write_string (&writer, packet->Willing.hostname);
336 write_string (&writer, packet->Willing.status);
338 case XDMCP_Unwilling:
339 write_string (&writer, packet->Unwilling.hostname);
340 write_string (&writer, packet->Unwilling.status);
343 write_card16 (&writer, packet->Request.display_number);
344 write_card8 (&writer, packet->Request.n_connections);
345 for (i = 0; i < packet->Request.n_connections; i++)
346 write_card16 (&writer, packet->Request.connections[i].type);
347 write_card8 (&writer, packet->Request.n_connections);
348 for (i = 0; i < packet->Request.n_connections; i++)
349 write_data (&writer, &packet->Request.connections[i].address);
350 write_string (&writer, packet->Request.authentication_name);
351 write_data (&writer, &packet->Request.authentication_data);
352 write_string_array (&writer, packet->Request.authorization_names);
353 write_string (&writer, packet->Request.manufacturer_display_id);
356 write_card32 (&writer, packet->Accept.session_id);
357 write_string (&writer, packet->Accept.authentication_name);
358 write_data (&writer, &packet->Accept.authentication_data);
359 write_string (&writer, packet->Accept.authorization_name);
360 write_data (&writer, &packet->Accept.authorization_data);
363 write_string (&writer, packet->Decline.status);
364 write_string (&writer, packet->Decline.authentication_name);
365 write_data (&writer, &packet->Decline.authentication_data);
368 write_card32 (&writer, packet->Manage.session_id);
369 write_card16 (&writer, packet->Manage.display_number);
370 write_string (&writer, packet->Manage.display_class);
373 write_card32 (&writer, packet->Refuse.session_id);
376 write_card32 (&writer, packet->Failed.session_id);
377 write_string (&writer, packet->Failed.status);
379 case XDMCP_KeepAlive:
380 write_card16 (&writer, packet->KeepAlive.display_number);
381 write_card32 (&writer, packet->KeepAlive.session_id);
384 write_card8 (&writer, packet->Alive.session_running ? 1 : 0);
385 write_card32 (&writer, packet->Alive.session_id);
389 length = max_length - 6 - writer.remaining;
393 writer.remaining = 6;
394 writer.overflow = FALSE;
395 write_card16(&writer, XDMCP_VERSION);
396 write_card16(&writer, packet->opcode);
397 write_card16(&writer, length);
401 g_warning ("Overflow writing response");
409 data_tostring (XDMCPData *data)
415 s = g_string_new ("");
416 for (i = 0; i < data->length; i++)
417 g_string_append_printf (s, "%02X", data->data[i]);
419 g_string_free (s, FALSE);
425 string_list_tostring (gchar **strings)
431 s = g_string_new ("");
432 for (i = strings; *i; i++)
435 g_string_append (s, " ");
436 g_string_append_printf (s, "'%s'", *i);
439 g_string_free (s, FALSE);
445 xdmcp_packet_tostring (XDMCPPacket *packet)
447 gchar *string, *t, *t2;
451 switch (packet->opcode)
453 case XDMCP_BroadcastQuery:
454 t = string_list_tostring (packet->Query.authentication_names);
455 string = g_strdup_printf ("BroadcastQuery(authentication_names=[%s])", t);
459 t = string_list_tostring (packet->Query.authentication_names);
460 string = g_strdup_printf ("Query(authentication_names=[%s])", t);
463 case XDMCP_IndirectQuery:
464 t = string_list_tostring (packet->Query.authentication_names);
465 string = g_strdup_printf ("IndirectQuery(authentication_names=[%s])", t);
468 case XDMCP_ForwardQuery:
469 t = string_list_tostring (packet->ForwardQuery.authentication_names);
470 string = g_strdup_printf ("ForwardQuery(client_address='%s' client_port='%s' authentication_names=[%s])",
471 packet->ForwardQuery.client_address, packet->ForwardQuery.client_port, t);
475 return g_strdup_printf ("Willing(authentication_name='%s' hostname='%s' status='%s')",
476 packet->Willing.authentication_name, packet->Willing.hostname, packet->Willing.status);
477 case XDMCP_Unwilling:
478 return g_strdup_printf ("Unwilling(hostname='%s' status='%s')",
479 packet->Unwilling.hostname, packet->Unwilling.status);
481 t = string_list_tostring (packet->Request.authorization_names);
482 t2 = data_tostring (&packet->Request.authentication_data);
483 t3 = g_string_new ("");
484 for (i = 0; i < packet->Request.n_connections; i++)
486 XDMCPConnection *connection = &packet->Request.connections[i];
487 GSocketFamily family = G_SOCKET_FAMILY_INVALID;
490 g_string_append (t3, " ");
492 if (connection->type == XAUTH_FAMILY_INTERNET && connection->address.length == 4)
493 family = G_SOCKET_FAMILY_IPV4;
494 else if (connection->type == XAUTH_FAMILY_INTERNET6 && connection->address.length == 16)
495 family = G_SOCKET_FAMILY_IPV6;
497 if (family != G_SOCKET_FAMILY_INVALID)
499 GInetAddress *address = g_inet_address_new_from_bytes (connection->address.data, family);
500 gchar *t4 = g_inet_address_to_string (address);
501 g_string_append (t3, t4);
503 g_object_unref (address);
507 gchar *t4 = data_tostring (&connection->address);
508 g_string_append_printf (t3, "(%d, %s)", connection->type, t4);
512 string = g_strdup_printf ("Request(display_number=%d connections=[%s] authentication_name='%s' authentication_data=%s authorization_names=[%s] manufacturer_display_id='%s')",
513 packet->Request.display_number, t3->str, packet->Request.authentication_name, t2,
514 t, packet->Request.manufacturer_display_id);
517 g_string_free (t3, TRUE);
520 t = data_tostring (&packet->Accept.authentication_data);
521 t2 = data_tostring (&packet->Accept.authorization_data);
522 string = g_strdup_printf ("Accept(session_id=%d authentication_name='%s' authentication_data=%s authorization_name='%s' authorization_data=%s)",
523 packet->Accept.session_id, packet->Accept.authentication_name, t,
524 packet->Accept.authorization_name, t2);
529 t = data_tostring (&packet->Decline.authentication_data);
530 string = g_strdup_printf ("Decline(status='%s' authentication_name='%s' authentication_data=%s)",
531 packet->Decline.status, packet->Decline.authentication_name, t);
535 return g_strdup_printf ("Manage(session_id=%d display_number=%d display_class='%s')",
536 packet->Manage.session_id, packet->Manage.display_number, packet->Manage.display_class);
538 return g_strdup_printf ("Refuse(session_id=%d)", packet->Refuse.session_id);
540 return g_strdup_printf ("Failed(session_id=%d status='%s')", packet->Failed.session_id, packet->Failed.status);
541 case XDMCP_KeepAlive:
542 return g_strdup_printf ("KeepAlive(display_number=%d session_id=%d)",
543 packet->KeepAlive.display_number, packet->KeepAlive.session_id);
545 return g_strdup_printf ("Alive(session_running=%s session_id=%d)",
546 packet->Alive.session_running ? "true" : "false", packet->Alive.session_id);
548 return g_strdup_printf ("XDMCPPacket(opcode=%d)", packet->opcode);
553 xdmcp_packet_free (XDMCPPacket *packet)
560 switch (packet->opcode)
562 case XDMCP_BroadcastQuery:
564 case XDMCP_IndirectQuery:
565 g_strfreev (packet->Query.authentication_names);
567 case XDMCP_ForwardQuery:
568 g_free (packet->ForwardQuery.client_address);
569 g_free (packet->ForwardQuery.client_port);
570 g_strfreev (packet->ForwardQuery.authentication_names);
573 g_free (packet->Willing.authentication_name);
574 g_free (packet->Willing.hostname);
575 g_free (packet->Willing.status);
577 case XDMCP_Unwilling:
578 g_free (packet->Unwilling.hostname);
579 g_free (packet->Unwilling.status);
582 for (i = 0; i < packet->Request.n_connections; i++)
583 g_free (packet->Request.connections[i].address.data);
584 g_free (packet->Request.connections);
585 g_free (packet->Request.authentication_name);
586 g_free (packet->Request.authentication_data.data);
587 g_strfreev (packet->Request.authorization_names);
588 g_free (packet->Request.manufacturer_display_id);
591 g_free (packet->Accept.authentication_name);
592 g_free (packet->Accept.authentication_data.data);
593 g_free (packet->Accept.authorization_name);
594 g_free (packet->Accept.authorization_data.data);
597 g_free (packet->Decline.status);
598 g_free (packet->Decline.authentication_name);
599 g_free (packet->Decline.authentication_data.data);
602 g_free (packet->Manage.display_class);
607 g_free (packet->Failed.status);
609 case XDMCP_KeepAlive: