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