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
14 #include "xdmcp-protocol.h"
24 read_card8 (PacketReader *reader)
28 if (reader->remaining < 1)
30 reader->overflow = TRUE;
34 value = reader->data[0];
42 read_card16 (PacketReader *reader)
44 return read_card8 (reader) << 8 | read_card8 (reader);
48 read_card32 (PacketReader *reader)
50 return read_card8 (reader) << 24 | read_card8 (reader) << 16 | read_card8 (reader) << 8 | read_card8 (reader);
54 read_data (PacketReader *reader, XDMCPData *data)
58 data->length = read_card16 (reader);
59 data->data = g_malloc (sizeof (guint8) * data->length);
60 for (i = 0; i < data->length; i++)
61 data->data[i] = read_card8 (reader);
65 read_string (PacketReader *reader)
70 length = read_card16 (reader);
71 string = g_malloc (sizeof (gchar) * (length + 1));
72 for (i = 0; i < length; i++)
73 string[i] = (gchar) read_card8 (reader);
80 read_string_array (PacketReader *reader)
85 n_strings = read_card8 (reader);
86 strings = g_malloc (sizeof (gchar *) * (n_strings + 1));
87 for (i = 0; i < n_strings; i++)
88 strings[i] = read_string (reader);
102 write_card8 (PacketWriter *writer, guint8 value)
104 if (writer->remaining < 1)
106 writer->overflow = TRUE;
110 writer->data[0] = value;
116 write_card16 (PacketWriter *writer, guint16 value)
118 write_card8 (writer, value >> 8);
119 write_card8 (writer, value & 0xFF);
123 write_card32 (PacketWriter *writer, guint32 value)
125 write_card8 (writer, (value >> 24) & 0xFF);
126 write_card8 (writer, (value >> 16) & 0xFF);
127 write_card8 (writer, (value >> 8) & 0xFF);
128 write_card8 (writer, value & 0xFF);
132 write_data (PacketWriter *writer, const XDMCPData *value)
136 write_card16 (writer, value->length);
137 for (i = 0; i < value->length; i++)
138 write_card8 (writer, value->data[i]);
142 write_string (PacketWriter *writer, const gchar *value)
146 write_card16 (writer, strlen (value));
147 for (c = value; *c; c++)
148 write_card8 (writer, *c);
152 write_string_array (PacketWriter *writer, gchar **values)
156 write_card8 (writer, g_strv_length (values));
157 for (value = values; *value; value++)
158 write_string (writer, *value);
162 xdmcp_packet_alloc (XDMCPOpcode opcode)
166 packet = g_malloc0 (sizeof (XDMCPPacket));
167 packet->opcode = opcode;
173 xdmcp_packet_decode (const guint8 *data, gsize data_length)
176 guint16 version, opcode, length;
179 gboolean failed = FALSE;
182 reader.remaining = data_length;
183 reader.overflow = FALSE;
185 version = read_card16 (&reader);
186 opcode = read_card16 (&reader);
187 length = read_card16 (&reader);
191 g_warning ("Ignoring short packet"); // FIXME: Use GError
194 if (version != XDMCP_VERSION)
196 g_warning ("Ignoring packet from unknown version %d", version);
199 if (length != reader.remaining)
201 g_warning ("Ignoring packet of wrong length. Opcode %d expected %d octets, got %d", opcode, length, reader.remaining);
205 packet = xdmcp_packet_alloc (opcode);
206 switch (packet->opcode)
208 case XDMCP_BroadcastQuery:
210 case XDMCP_IndirectQuery:
211 packet->Query.authentication_names = read_string_array (&reader);
213 case XDMCP_ForwardQuery:
214 packet->ForwardQuery.client_address = read_string (&reader);
215 packet->ForwardQuery.client_port = read_string (&reader);
216 packet->ForwardQuery.authentication_names = read_string_array (&reader);
219 packet->Willing.authentication_name = read_string (&reader);
220 packet->Willing.hostname = read_string (&reader);
221 packet->Willing.status = read_string (&reader);
223 case XDMCP_Unwilling:
224 packet->Unwilling.hostname = read_string (&reader);
225 packet->Unwilling.status = read_string (&reader);
228 packet->Request.display_number = read_card16 (&reader);
229 packet->Request.n_connections = read_card8 (&reader);
230 packet->Request.connections = g_malloc (sizeof (XDMCPConnection) * packet->Request.n_connections);
231 for (i = 0; i < packet->Request.n_connections; i++)
232 packet->Request.connections[i].type = read_card16 (&reader);
233 if (read_card8 (&reader) != packet->Request.n_connections)
235 g_warning ("Number of connection types does not match number of connection addresses");
238 for (i = 0; i < packet->Request.n_connections; i++)
239 read_data (&reader, &packet->Request.connections[i].address);
240 packet->Request.authentication_name = read_string (&reader);
241 read_data (&reader, &packet->Request.authentication_data);
242 packet->Request.authorization_names = read_string_array (&reader);
243 packet->Request.manufacturer_display_id = read_string (&reader);
246 packet->Accept.session_id = read_card32 (&reader);
247 packet->Accept.authentication_name = read_string (&reader);
248 read_data (&reader, &packet->Accept.authentication_data);
249 packet->Accept.authorization_name = read_string (&reader);
250 read_data (&reader, &packet->Accept.authorization_data);
253 packet->Decline.status = read_string (&reader);
254 packet->Decline.authentication_name = read_string (&reader);
255 read_data (&reader, &packet->Decline.authentication_data);
258 packet->Manage.session_id = read_card32 (&reader);
259 packet->Manage.display_number = read_card16 (&reader);
260 packet->Manage.display_class = read_string (&reader);
263 packet->Refuse.session_id = read_card32 (&reader);
266 packet->Failed.session_id = read_card32 (&reader);
267 packet->Failed.status = read_string (&reader);
269 case XDMCP_KeepAlive:
270 packet->KeepAlive.display_number = read_card16 (&reader);
271 packet->KeepAlive.session_id = read_card32 (&reader);
274 packet->Alive.session_running = read_card8 (&reader) == 0 ? FALSE : TRUE;
275 packet->Alive.session_id = read_card32 (&reader);
278 g_warning ("Unable to encode unknown opcode %d", packet->opcode);
287 g_warning ("Short packet received");
290 else if (reader.remaining != 0)
292 g_warning ("Extra data on end of message");
298 xdmcp_packet_free (packet);
306 xdmcp_packet_encode (XDMCPPacket *packet, guint8 *data, gsize max_length)
315 writer.data = data + 6;
316 writer.remaining = max_length - 6;
317 writer.overflow = FALSE;
319 switch (packet->opcode)
321 case XDMCP_BroadcastQuery:
323 case XDMCP_IndirectQuery:
324 write_string_array (&writer, packet->Query.authentication_names);
326 case XDMCP_ForwardQuery:
327 write_string (&writer, packet->ForwardQuery.client_address);
328 write_string (&writer, packet->ForwardQuery.client_port);
329 write_string_array (&writer, packet->ForwardQuery.authentication_names);
332 write_string (&writer, packet->Willing.authentication_name);
333 write_string (&writer, packet->Willing.hostname);
334 write_string (&writer, packet->Willing.status);
336 case XDMCP_Unwilling:
337 write_string (&writer, packet->Unwilling.hostname);
338 write_string (&writer, packet->Unwilling.status);
341 write_card16 (&writer, packet->Request.display_number);
342 write_card8 (&writer, packet->Request.n_connections);
343 for (i = 0; i < packet->Request.n_connections; i++)
344 write_card16 (&writer, packet->Request.connections[i].type);
345 write_card8 (&writer, packet->Request.n_connections);
346 for (i = 0; i < packet->Request.n_connections; i++)
347 write_data (&writer, &packet->Request.connections[i].address);
348 write_string (&writer, packet->Request.authentication_name);
349 write_data (&writer, &packet->Request.authentication_data);
350 write_string_array (&writer, packet->Request.authorization_names);
351 write_string (&writer, packet->Request.manufacturer_display_id);
354 write_card32 (&writer, packet->Accept.session_id);
355 write_string (&writer, packet->Accept.authentication_name);
356 write_data (&writer, &packet->Accept.authentication_data);
357 write_string (&writer, packet->Accept.authorization_name);
358 write_data (&writer, &packet->Accept.authorization_data);
361 write_string (&writer, packet->Decline.status);
362 write_string (&writer, packet->Decline.authentication_name);
363 write_data (&writer, &packet->Decline.authentication_data);
366 write_card32 (&writer, packet->Manage.session_id);
367 write_card16 (&writer, packet->Manage.display_number);
368 write_string (&writer, packet->Manage.display_class);
371 write_card32 (&writer, packet->Refuse.session_id);
374 write_card32 (&writer, packet->Failed.session_id);
375 write_string (&writer, packet->Failed.status);
377 case XDMCP_KeepAlive:
378 write_card16 (&writer, packet->KeepAlive.display_number);
379 write_card32 (&writer, packet->KeepAlive.session_id);
382 write_card8 (&writer, packet->Alive.session_running ? 1 : 0);
383 write_card32 (&writer, packet->Alive.session_id);
387 length = max_length - 6 - writer.remaining;
391 writer.remaining = 6;
392 writer.overflow = FALSE;
393 write_card16(&writer, XDMCP_VERSION);
394 write_card16(&writer, packet->opcode);
395 write_card16(&writer, length);
399 g_warning ("Overflow writing response");
407 data_tostring (XDMCPData *data)
413 s = g_string_new ("");
414 for (i = 0; i < data->length; i++)
415 g_string_append_printf (s, "%02X", data->data[i]);
417 g_string_free (s, FALSE);
423 string_list_tostring (gchar **strings)
429 s = g_string_new ("");
430 for (i = strings; *i; i++)
433 g_string_append (s, " ");
434 g_string_append_printf (s, "'%s'", *i);
437 g_string_free (s, FALSE);
443 xdmcp_packet_tostring (XDMCPPacket *packet)
445 gchar *string, *t, *t2;
449 switch (packet->opcode)
451 case XDMCP_BroadcastQuery:
452 t = string_list_tostring (packet->Query.authentication_names);
453 string = g_strdup_printf ("BroadcastQuery(authentication_names=[%s])", t);
457 t = string_list_tostring (packet->Query.authentication_names);
458 string = g_strdup_printf ("Query(authentication_names=[%s])", t);
461 case XDMCP_IndirectQuery:
462 t = string_list_tostring (packet->Query.authentication_names);
463 string = g_strdup_printf ("IndirectQuery(authentication_names=[%s])", t);
466 case XDMCP_ForwardQuery:
467 t = string_list_tostring (packet->ForwardQuery.authentication_names);
468 string = g_strdup_printf ("ForwardQuery(client_address='%s' client_port='%s' authentication_names=[%s])",
469 packet->ForwardQuery.client_address, packet->ForwardQuery.client_port, t);
473 return g_strdup_printf ("Willing(authentication_name='%s' hostname='%s' status='%s')",
474 packet->Willing.authentication_name, packet->Willing.hostname, packet->Willing.status);
475 case XDMCP_Unwilling:
476 return g_strdup_printf ("Unwilling(hostname='%s' status='%s')",
477 packet->Unwilling.hostname, packet->Unwilling.status);
479 t = string_list_tostring (packet->Request.authorization_names);
480 t2 = data_tostring (&packet->Request.authentication_data);
481 t3 = g_string_new ("");
482 for (i = 0; i < packet->Request.n_connections; i++)
487 g_string_append (t3, " ");
488 t4 = data_tostring (&packet->Request.connections[i].address);
489 g_string_append_printf (t3, "(%d, %s)", packet->Request.connections[i].type, t4);
492 string = g_strdup_printf ("Request(display_number=%d connections=[%s] authentication_name='%s' authentication_data=%s authorization_names=[%s] manufacturer_display_id='%s')",
493 packet->Request.display_number, t3->str, packet->Request.authentication_name, t2,
494 t, packet->Request.manufacturer_display_id);
497 g_string_free (t3, TRUE);
500 t = data_tostring (&packet->Accept.authentication_data);
501 t2 = data_tostring (&packet->Accept.authorization_data);
502 string = g_strdup_printf ("Accept(session_id=%d authentication_name='%s' authentication_data=%s authorization_name='%s' authorization_data=%s)",
503 packet->Accept.session_id, packet->Accept.authentication_name, t,
504 packet->Accept.authorization_name, t2);
509 t = data_tostring (&packet->Decline.authentication_data);
510 string = g_strdup_printf ("Decline(status='%s' authentication_name='%s' authentication_data=%s)",
511 packet->Decline.status, packet->Decline.authentication_name, t);
515 return g_strdup_printf ("Manage(session_id=%d display_number=%d display_class='%s')",
516 packet->Manage.session_id, packet->Manage.display_number, packet->Manage.display_class);
518 return g_strdup_printf ("Refuse(session_id=%d)", packet->Refuse.session_id);
520 return g_strdup_printf ("Failed(session_id=%d status='%s')", packet->Failed.session_id, packet->Failed.status);
521 case XDMCP_KeepAlive:
522 return g_strdup_printf ("KeepAlive(display_number=%d session_id=%d)",
523 packet->KeepAlive.display_number, packet->KeepAlive.session_id);
525 return g_strdup_printf ("Alive(session_running=%s session_id=%d)",
526 packet->Alive.session_running ? "true" : "false", packet->Alive.session_id);
528 return g_strdup_printf ("XDMCPPacket(opcode=%d)", packet->opcode);
533 xdmcp_packet_free (XDMCPPacket *packet)
540 switch (packet->opcode)
542 case XDMCP_BroadcastQuery:
544 case XDMCP_IndirectQuery:
545 g_strfreev (packet->Query.authentication_names);
547 case XDMCP_ForwardQuery:
548 g_free (packet->ForwardQuery.client_address);
549 g_free (packet->ForwardQuery.client_port);
550 g_strfreev (packet->ForwardQuery.authentication_names);
553 g_free (packet->Willing.authentication_name);
554 g_free (packet->Willing.hostname);
555 g_free (packet->Willing.status);
557 case XDMCP_Unwilling:
558 g_free (packet->Unwilling.hostname);
559 g_free (packet->Unwilling.status);
562 for (i = 0; i < packet->Request.n_connections; i++)
563 g_free (packet->Request.connections[i].address.data);
564 g_free (packet->Request.connections);
565 g_free (packet->Request.authentication_name);
566 g_free (packet->Request.authentication_data.data);
567 g_strfreev (packet->Request.authorization_names);
568 g_free (packet->Request.manufacturer_display_id);
571 g_free (packet->Accept.authentication_name);
572 g_free (packet->Accept.authentication_data.data);
573 g_free (packet->Accept.authorization_name);
574 g_free (packet->Accept.authorization_data.data);
577 g_free (packet->Decline.status);
578 g_free (packet->Decline.authentication_name);
579 g_free (packet->Decline.authentication_data.data);
582 g_free (packet->Manage.display_class);
587 g_free (packet->Failed.status);
589 case XDMCP_KeepAlive: