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