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 <string.h>
13 #include <gio/gio.h>
14
15 #include "xdmcp-protocol.h"
16 #include "x-authority.h"
17
18 typedef struct
19 {
20 const guint8 *data;
21 guint16 remaining;
22 gboolean overflow;
23 } PacketReader;
24
25 static guint8
read_card8(PacketReader * reader)26 read_card8 (PacketReader *reader)
27 {
28 if (reader->remaining < 1)
29 {
30 reader->overflow = TRUE;
31 return 0;
32 }
33
34 guint8 value = reader->data[0];
35 reader->data++;
36 reader->remaining--;
37
38 return value;
39 }
40
41 static guint16
read_card16(PacketReader * reader)42 read_card16 (PacketReader *reader)
43 {
44 return read_card8 (reader) << 8 | read_card8 (reader);
45 }
46
47 static guint32
read_card32(PacketReader * reader)48 read_card32 (PacketReader *reader)
49 {
50 return read_card8 (reader) << 24 | read_card8 (reader) << 16 | read_card8 (reader) << 8 | read_card8 (reader);
51 }
52
53 static void
read_data(PacketReader * reader,XDMCPData * data)54 read_data (PacketReader *reader, XDMCPData *data)
55 {
56 data->length = read_card16 (reader);
57 data->data = g_malloc (sizeof (guint8) * data->length);
58 for (guint16 i = 0; i < data->length; i++)
59 data->data[i] = read_card8 (reader);
60 }
61
62 static gchar *
read_string(PacketReader * reader)63 read_string (PacketReader *reader)
64 {
65 guint16 length = read_card16 (reader);
66 gchar *string = g_malloc (sizeof (gchar) * (length + 1));
67 guint16 i;
68 for (i = 0; i < length; i++)
69 string[i] = (gchar) read_card8 (reader);
70 string[i] = '\0';
71
72 return string;
73 }
74
75 static gchar **
read_string_array(PacketReader * reader)76 read_string_array (PacketReader *reader)
77 {
78 guint8 n_strings = read_card8 (reader);
79 gchar **strings = g_malloc (sizeof (gchar *) * (n_strings + 1));
80 guint8 i;
81 for (i = 0; i < n_strings; i++)
82 strings[i] = read_string (reader);
83 strings[i] = NULL;
84
85 return strings;
86 }
87
88 typedef struct
89 {
90 guint8 *data;
91 guint16 remaining;
92 gboolean overflow;
93 } PacketWriter;
94
95 static void
write_card8(PacketWriter * writer,guint8 value)96 write_card8 (PacketWriter *writer, guint8 value)
97 {
98 if (writer->remaining < 1)
99 {
100 writer->overflow = TRUE;
101 return;
102 }
103
104 writer->data[0] = value;
105 writer->data++;
106 writer->remaining--;
107 }
108
109 static void
write_card16(PacketWriter * writer,guint16 value)110 write_card16 (PacketWriter *writer, guint16 value)
111 {
112 write_card8 (writer, value >> 8);
113 write_card8 (writer, value & 0xFF);
114 }
115
116 static void
write_card32(PacketWriter * writer,guint32 value)117 write_card32 (PacketWriter *writer, guint32 value)
118 {
119 write_card8 (writer, (value >> 24) & 0xFF);
120 write_card8 (writer, (value >> 16) & 0xFF);
121 write_card8 (writer, (value >> 8) & 0xFF);
122 write_card8 (writer, value & 0xFF);
123 }
124
125 static void
write_data(PacketWriter * writer,const XDMCPData * value)126 write_data (PacketWriter *writer, const XDMCPData *value)
127 {
128 write_card16 (writer, value->length);
129 for (guint16 i = 0; i < value->length; i++)
130 write_card8 (writer, value->data[i]);
131 }
132
133 static void
write_string(PacketWriter * writer,const gchar * value)134 write_string (PacketWriter *writer, const gchar *value)
135 {
136 write_card16 (writer, strlen (value));
137 for (const gchar *c = value; *c; c++)
138 write_card8 (writer, *c);
139 }
140
141 static void
write_string_array(PacketWriter * writer,gchar ** values)142 write_string_array (PacketWriter *writer, gchar **values)
143 {
144 write_card8 (writer, g_strv_length (values));
145 for (gchar **value = values; *value; value++)
146 write_string (writer, *value);
147 }
148
149 XDMCPPacket *
xdmcp_packet_alloc(XDMCPOpcode opcode)150 xdmcp_packet_alloc (XDMCPOpcode opcode)
151 {
152 XDMCPPacket *packet = g_malloc0 (sizeof (XDMCPPacket));
153 packet->opcode = opcode;
154
155 return packet;
156 }
157
158 XDMCPPacket *
xdmcp_packet_decode(const guint8 * data,gsize data_length)159 xdmcp_packet_decode (const guint8 *data, gsize data_length)
160 {
161 PacketReader reader;
162 reader.data = data;
163 reader.remaining = data_length;
164 reader.overflow = FALSE;
165
166 guint16 version = read_card16 (&reader);
167 guint16 opcode = read_card16 (&reader);
168 guint16 length = read_card16 (&reader);
169
170 if (reader.overflow)
171 {
172 g_warning ("Ignoring short packet"); // FIXME: Use GError
173 return NULL;
174 }
175 if (version != XDMCP_VERSION)
176 {
177 g_warning ("Ignoring packet from unknown version %d", version);
178 return NULL;
179 }
180 if (length != reader.remaining)
181 {
182 g_warning ("Ignoring packet of wrong length. Opcode %d expected %d octets, got %d", opcode, length, reader.remaining);
183 return NULL;
184 }
185
186 XDMCPPacket *packet = xdmcp_packet_alloc (opcode);
187 gboolean failed = FALSE;
188 switch (packet->opcode)
189 {
190 case XDMCP_BroadcastQuery:
191 case XDMCP_Query:
192 case XDMCP_IndirectQuery:
193 packet->Query.authentication_names = read_string_array (&reader);
194 break;
195 case XDMCP_ForwardQuery:
196 read_data (&reader, &packet->ForwardQuery.client_address);
197 read_data (&reader, &packet->ForwardQuery.client_port);
198 packet->ForwardQuery.authentication_names = read_string_array (&reader);
199 break;
200 case XDMCP_Willing:
201 packet->Willing.authentication_name = read_string (&reader);
202 packet->Willing.hostname = read_string (&reader);
203 packet->Willing.status = read_string (&reader);
204 break;
205 case XDMCP_Unwilling:
206 packet->Unwilling.hostname = read_string (&reader);
207 packet->Unwilling.status = read_string (&reader);
208 break;
209 case XDMCP_Request:
210 packet->Request.display_number = read_card16 (&reader);
211 packet->Request.n_connections = read_card8 (&reader);
212 packet->Request.connections = g_malloc (sizeof (XDMCPConnection) * packet->Request.n_connections);
213 for (int i = 0; i < packet->Request.n_connections; i++)
214 packet->Request.connections[i].type = read_card16 (&reader);
215 if (read_card8 (&reader) != packet->Request.n_connections)
216 {
217 g_warning ("Number of connection types does not match number of connection addresses");
218 failed = TRUE;
219 }
220 for (int i = 0; i < packet->Request.n_connections; i++)
221 read_data (&reader, &packet->Request.connections[i].address);
222 packet->Request.authentication_name = read_string (&reader);
223 read_data (&reader, &packet->Request.authentication_data);
224 packet->Request.authorization_names = read_string_array (&reader);
225 packet->Request.manufacturer_display_id = read_string (&reader);
226 break;
227 case XDMCP_Accept:
228 packet->Accept.session_id = read_card32 (&reader);
229 packet->Accept.authentication_name = read_string (&reader);
230 read_data (&reader, &packet->Accept.authentication_data);
231 packet->Accept.authorization_name = read_string (&reader);
232 read_data (&reader, &packet->Accept.authorization_data);
233 break;
234 case XDMCP_Decline:
235 packet->Decline.status = read_string (&reader);
236 packet->Decline.authentication_name = read_string (&reader);
237 read_data (&reader, &packet->Decline.authentication_data);
238 break;
239 case XDMCP_Manage:
240 packet->Manage.session_id = read_card32 (&reader);
241 packet->Manage.display_number = read_card16 (&reader);
242 packet->Manage.display_class = read_string (&reader);
243 break;
244 case XDMCP_Refuse:
245 packet->Refuse.session_id = read_card32 (&reader);
246 break;
247 case XDMCP_Failed:
248 packet->Failed.session_id = read_card32 (&reader);
249 packet->Failed.status = read_string (&reader);
250 break;
251 case XDMCP_KeepAlive:
252 packet->KeepAlive.display_number = read_card16 (&reader);
253 packet->KeepAlive.session_id = read_card32 (&reader);
254 break;
255 case XDMCP_Alive:
256 packet->Alive.session_running = read_card8 (&reader) == 0 ? FALSE : TRUE;
257 packet->Alive.session_id = read_card32 (&reader);
258 break;
259 default:
260 g_warning ("Unable to encode unknown opcode %d", packet->opcode);
261 failed = TRUE;
262 break;
263 }
264
265 if (!failed)
266 {
267 if (reader.overflow)
268 {
269 g_warning ("Short packet received");
270 failed = TRUE;
271 }
272 else if (reader.remaining != 0)
273 {
274 g_warning ("Extra data on end of message");
275 failed = TRUE;
276 }
277 }
278 if (failed)
279 {
280 xdmcp_packet_free (packet);
281 return NULL;
282 }
283
284 return packet;
285 }
286
287 gssize
xdmcp_packet_encode(XDMCPPacket * packet,guint8 * data,gsize max_length)288 xdmcp_packet_encode (XDMCPPacket *packet, guint8 *data, gsize max_length)
289 {
290 if (max_length < 6)
291 return -1;
292
293 PacketWriter writer;
294 writer.data = data + 6;
295 writer.remaining = max_length - 6;
296 writer.overflow = FALSE;
297
298 switch (packet->opcode)
299 {
300 case XDMCP_BroadcastQuery:
301 case XDMCP_Query:
302 case XDMCP_IndirectQuery:
303 write_string_array (&writer, packet->Query.authentication_names);
304 break;
305 case XDMCP_ForwardQuery:
306 write_data (&writer, &packet->ForwardQuery.client_address);
307 write_data (&writer, &packet->ForwardQuery.client_port);
308 write_string_array (&writer, packet->ForwardQuery.authentication_names);
309 break;
310 case XDMCP_Willing:
311 write_string (&writer, packet->Willing.authentication_name);
312 write_string (&writer, packet->Willing.hostname);
313 write_string (&writer, packet->Willing.status);
314 break;
315 case XDMCP_Unwilling:
316 write_string (&writer, packet->Unwilling.hostname);
317 write_string (&writer, packet->Unwilling.status);
318 break;
319 case XDMCP_Request:
320 write_card16 (&writer, packet->Request.display_number);
321 write_card8 (&writer, packet->Request.n_connections);
322 for (int i = 0; i < packet->Request.n_connections; i++)
323 write_card16 (&writer, packet->Request.connections[i].type);
324 write_card8 (&writer, packet->Request.n_connections);
325 for (int i = 0; i < packet->Request.n_connections; i++)
326 write_data (&writer, &packet->Request.connections[i].address);
327 write_string (&writer, packet->Request.authentication_name);
328 write_data (&writer, &packet->Request.authentication_data);
329 write_string_array (&writer, packet->Request.authorization_names);
330 write_string (&writer, packet->Request.manufacturer_display_id);
331 break;
332 case XDMCP_Accept:
333 write_card32 (&writer, packet->Accept.session_id);
334 write_string (&writer, packet->Accept.authentication_name);
335 write_data (&writer, &packet->Accept.authentication_data);
336 write_string (&writer, packet->Accept.authorization_name);
337 write_data (&writer, &packet->Accept.authorization_data);
338 break;
339 case XDMCP_Decline:
340 write_string (&writer, packet->Decline.status);
341 write_string (&writer, packet->Decline.authentication_name);
342 write_data (&writer, &packet->Decline.authentication_data);
343 break;
344 case XDMCP_Manage:
345 write_card32 (&writer, packet->Manage.session_id);
346 write_card16 (&writer, packet->Manage.display_number);
347 write_string (&writer, packet->Manage.display_class);
348 break;
349 case XDMCP_Refuse:
350 write_card32 (&writer, packet->Refuse.session_id);
351 break;
352 case XDMCP_Failed:
353 write_card32 (&writer, packet->Failed.session_id);
354 write_string (&writer, packet->Failed.status);
355 break;
356 case XDMCP_KeepAlive:
357 write_card16 (&writer, packet->KeepAlive.display_number);
358 write_card32 (&writer, packet->KeepAlive.session_id);
359 break;
360 case XDMCP_Alive:
361 write_card8 (&writer, packet->Alive.session_running ? 1 : 0);
362 write_card32 (&writer, packet->Alive.session_id);
363 break;
364 }
365
366 guint16 length = max_length - 6 - writer.remaining;
367
368 /* Write header */
369 writer.data = data;
370 writer.remaining = 6;
371 writer.overflow = FALSE;
372 write_card16(&writer, XDMCP_VERSION);
373 write_card16(&writer, packet->opcode);
374 write_card16(&writer, length);
375
376 if (writer.overflow)
377 {
378 g_warning ("Overflow writing response");
379 return -1;
380 }
381
382 return length + 6;
383 }
384
385 static gchar *
data_tostring(XDMCPData * data)386 data_tostring (XDMCPData *data)
387 {
388 g_autoptr(GString) s = g_string_new ("");
389 for (guint16 i = 0; i < data->length; i++)
390 g_string_append_printf (s, "%02X", data->data[i]);
391
392 return g_steal_pointer (&s->str);
393 }
394
395 static gchar *
string_list_tostring(gchar ** strings)396 string_list_tostring (gchar **strings)
397 {
398 g_autoptr(GString) s = g_string_new ("");
399 for (gchar **i = strings; *i; i++)
400 {
401 if (i != strings)
402 g_string_append (s, " ");
403 g_string_append_printf (s, "'%s'", *i);
404 }
405
406 return g_steal_pointer (&s->str);
407 }
408
409 gchar *
xdmcp_packet_tostring(XDMCPPacket * packet)410 xdmcp_packet_tostring (XDMCPPacket *packet)
411 {
412 switch (packet->opcode)
413 {
414 case XDMCP_BroadcastQuery:
415 {
416 g_autofree gchar *names = string_list_tostring (packet->Query.authentication_names);
417 return g_strdup_printf ("BroadcastQuery(authentication_names=[%s])", names);
418 }
419 case XDMCP_Query:
420 {
421 g_autofree gchar *names = string_list_tostring (packet->Query.authentication_names);
422 return g_strdup_printf ("Query(authentication_names=[%s])", names);
423 }
424 case XDMCP_IndirectQuery:
425 {
426 g_autofree gchar *names = string_list_tostring (packet->Query.authentication_names);
427 return g_strdup_printf ("IndirectQuery(authentication_names=[%s])", names);
428 }
429 case XDMCP_ForwardQuery:
430 {
431 g_autofree gchar *address_text = data_tostring (&packet->ForwardQuery.client_address);
432 g_autofree gchar *port_text = data_tostring (&packet->ForwardQuery.client_port);
433 g_autofree gchar *names_text = string_list_tostring (packet->ForwardQuery.authentication_names);
434 return g_strdup_printf ("ForwardQuery(client_address=%s client_port=%s authentication_names=[%s])",
435 address_text, port_text, names_text);
436 }
437 case XDMCP_Willing:
438 return g_strdup_printf ("Willing(authentication_name='%s' hostname='%s' status='%s')",
439 packet->Willing.authentication_name, packet->Willing.hostname, packet->Willing.status);
440 case XDMCP_Unwilling:
441 return g_strdup_printf ("Unwilling(hostname='%s' status='%s')",
442 packet->Unwilling.hostname, packet->Unwilling.status);
443 case XDMCP_Request:
444 {
445 g_autofree gchar *names_text = string_list_tostring (packet->Request.authorization_names);
446 g_autofree gchar *data_text = data_tostring (&packet->Request.authentication_data);
447 g_autoptr(GString) connections_text = g_string_new ("");
448 for (gint i = 0; i < packet->Request.n_connections; i++)
449 {
450 XDMCPConnection *connection = &packet->Request.connections[i];
451
452 if (i != 0)
453 g_string_append (connections_text, " ");
454
455 GSocketFamily family = G_SOCKET_FAMILY_INVALID;
456 if (connection->type == XAUTH_FAMILY_INTERNET && connection->address.length == 4)
457 family = G_SOCKET_FAMILY_IPV4;
458 else if (connection->type == XAUTH_FAMILY_INTERNET6 && connection->address.length == 16)
459 family = G_SOCKET_FAMILY_IPV6;
460
461 if (family != G_SOCKET_FAMILY_INVALID)
462 {
463 g_autoptr(GInetAddress) address = g_inet_address_new_from_bytes (connection->address.data, family);
464 g_autofree gchar *text = g_inet_address_to_string (address);
465 g_string_append (connections_text, text);
466 }
467 else
468 {
469 g_autofree gchar *text = data_tostring (&connection->address);
470 g_string_append_printf (connections_text, "(%d, %s)", connection->type, text);
471 }
472 }
473 return g_strdup_printf ("Request(display_number=%d connections=[%s] authentication_name='%s' authentication_data=%s authorization_names=[%s] manufacturer_display_id='%s')",
474 packet->Request.display_number, connections_text->str, packet->Request.authentication_name, data_text,
475 names_text, packet->Request.manufacturer_display_id);
476 }
477 case XDMCP_Accept:
478 {
479 g_autofree gchar *authentication_text = data_tostring (&packet->Accept.authentication_data);
480 g_autofree gchar *authorization_text = data_tostring (&packet->Accept.authorization_data);
481 return g_strdup_printf ("Accept(session_id=%d authentication_name='%s' authentication_data=%s authorization_name='%s' authorization_data=%s)",
482 packet->Accept.session_id, packet->Accept.authentication_name, authentication_text,
483 packet->Accept.authorization_name, authorization_text);
484 }
485 case XDMCP_Decline:
486 {
487 g_autofree gchar *t = data_tostring (&packet->Decline.authentication_data);
488 return g_strdup_printf ("Decline(status='%s' authentication_name='%s' authentication_data=%s)",
489 packet->Decline.status, packet->Decline.authentication_name, t);
490 }
491 case XDMCP_Manage:
492 return g_strdup_printf ("Manage(session_id=%d display_number=%d display_class='%s')",
493 packet->Manage.session_id, packet->Manage.display_number, packet->Manage.display_class);
494 case XDMCP_Refuse:
495 return g_strdup_printf ("Refuse(session_id=%d)", packet->Refuse.session_id);
496 case XDMCP_Failed:
497 return g_strdup_printf ("Failed(session_id=%d status='%s')", packet->Failed.session_id, packet->Failed.status);
498 case XDMCP_KeepAlive:
499 return g_strdup_printf ("KeepAlive(display_number=%d session_id=%d)",
500 packet->KeepAlive.display_number, packet->KeepAlive.session_id);
501 case XDMCP_Alive:
502 return g_strdup_printf ("Alive(session_running=%s session_id=%d)",
503 packet->Alive.session_running ? "true" : "false", packet->Alive.session_id);
504 default:
505 return g_strdup_printf ("XDMCPPacket(opcode=%d)", packet->opcode);
506 }
507 }
508
509 void
xdmcp_packet_free(XDMCPPacket * packet)510 xdmcp_packet_free (XDMCPPacket *packet)
511 {
512 if (packet == NULL)
513 return;
514
515 switch (packet->opcode)
516 {
517 case XDMCP_BroadcastQuery:
518 case XDMCP_Query:
519 case XDMCP_IndirectQuery:
520 g_strfreev (packet->Query.authentication_names);
521 break;
522 case XDMCP_ForwardQuery:
523 g_free (packet->ForwardQuery.client_address.data);
524 g_free (packet->ForwardQuery.client_port.data);
525 g_strfreev (packet->ForwardQuery.authentication_names);
526 break;
527 case XDMCP_Willing:
528 g_free (packet->Willing.authentication_name);
529 g_free (packet->Willing.hostname);
530 g_free (packet->Willing.status);
531 break;
532 case XDMCP_Unwilling:
533 g_free (packet->Unwilling.hostname);
534 g_free (packet->Unwilling.status);
535 break;
536 case XDMCP_Request:
537 for (gint i = 0; i < packet->Request.n_connections; i++)
538 g_free (packet->Request.connections[i].address.data);
539 g_free (packet->Request.connections);
540 g_free (packet->Request.authentication_name);
541 g_free (packet->Request.authentication_data.data);
542 g_strfreev (packet->Request.authorization_names);
543 g_free (packet->Request.manufacturer_display_id);
544 break;
545 case XDMCP_Accept:
546 g_free (packet->Accept.authentication_name);
547 g_free (packet->Accept.authentication_data.data);
548 g_free (packet->Accept.authorization_name);
549 g_free (packet->Accept.authorization_data.data);
550 break;
551 case XDMCP_Decline:
552 g_free (packet->Decline.status);
553 g_free (packet->Decline.authentication_name);
554 g_free (packet->Decline.authentication_data.data);
555 break;
556 case XDMCP_Manage:
557 g_free (packet->Manage.display_class);
558 break;
559 case XDMCP_Refuse:
560 break;
561 case XDMCP_Failed:
562 g_free (packet->Failed.status);
563 break;
564 case XDMCP_KeepAlive:
565 break;
566 case XDMCP_Alive:
567 break;
568 }
569 g_free (packet);
570 }
571