]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - src/xdmcp-protocol.c
698edba95a4f57bbafd2b6f22f3abc7e4a559844
[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
14 #include "xdmcp-protocol.h"
15
16 typedef struct
17 {
18     const guint8 *data;
19     guint16 remaining;
20     gboolean overflow;
21 } PacketReader;
22
23 static guint8
24 read_card8 (PacketReader *reader)
25 {
26     guint8 value;
27
28     if (reader->remaining < 1)
29     {
30         reader->overflow = TRUE;
31         return 0;
32     }
33
34     value = reader->data[0];
35     reader->data++;
36     reader->remaining--;
37
38     return value;
39 }
40
41 static guint16
42 read_card16 (PacketReader *reader)
43 {
44     return read_card8 (reader) << 8 | read_card8 (reader);
45 }
46
47 static guint32
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
54 read_data (PacketReader *reader, XDMCPData *data)
55 {
56     guint16 i;
57
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);
62 }
63
64 static gchar *
65 read_string (PacketReader *reader)
66 {
67     guint16 length, i;
68     gchar *string;
69
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);
74     string[i] = '\0';
75
76     return string;
77 }
78
79 static gchar **
80 read_string_array (PacketReader *reader)
81 {
82     guint8 n_strings, i;
83     gchar **strings;
84
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);
89     strings[i] = NULL;
90
91     return strings;
92 }
93
94 typedef struct
95 {
96     guint8 *data;
97     guint16 remaining;
98     gboolean overflow;
99 } PacketWriter;
100
101 static void
102 write_card8 (PacketWriter *writer, guint8 value)
103 {
104     if (writer->remaining < 1)
105     {
106         writer->overflow = TRUE;
107         return;
108     }
109
110     writer->data[0] = value;
111     writer->data++;
112     writer->remaining--;
113 }
114
115 static void
116 write_card16 (PacketWriter *writer, guint16 value)
117 {
118     write_card8 (writer, value >> 8);
119     write_card8 (writer, value & 0xFF);
120 }
121
122 static void
123 write_card32 (PacketWriter *writer, guint32 value)
124 {
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);
129 }
130
131 static void
132 write_data (PacketWriter *writer, const XDMCPData *value)
133 {
134     guint16 i;
135
136     write_card16 (writer, value->length);
137     for (i = 0; i < value->length; i++)
138         write_card8 (writer, value->data[i]);
139 }
140
141 static void
142 write_string (PacketWriter *writer, const gchar *value)
143 {
144     const gchar *c;
145
146     write_card16 (writer, strlen (value));
147     for (c = value; *c; c++)
148         write_card8 (writer, *c);
149 }
150
151 static void
152 write_string_array (PacketWriter *writer, gchar **values)
153 {
154     gchar **value;
155
156     write_card8 (writer, g_strv_length (values));
157     for (value = values; *value; value++)
158         write_string (writer, *value);
159 }
160
161 XDMCPPacket *
162 xdmcp_packet_alloc (XDMCPOpcode opcode)
163 {
164     XDMCPPacket *packet;
165
166     packet = g_malloc0 (sizeof (XDMCPPacket));
167     packet->opcode = opcode;
168
169     return packet;
170 }
171
172 XDMCPPacket *
173 xdmcp_packet_decode (const guint8 *data, gsize data_length)
174 {
175     XDMCPPacket *packet;
176     guint16 version, opcode, length;
177     PacketReader reader;
178     int i;
179     gboolean failed = FALSE;
180
181     reader.data = data;
182     reader.remaining = data_length;
183     reader.overflow = FALSE;
184
185     version = read_card16 (&reader);
186     opcode = read_card16 (&reader);
187     length = read_card16 (&reader);
188
189     if (reader.overflow)
190     {      
191         g_warning ("Ignoring short packet"); // FIXME: Use GError
192         return NULL;
193     }
194     if (version != XDMCP_VERSION)
195     {
196         g_warning ("Ignoring packet from unknown version %d", version);
197         return NULL;
198     }
199     if (length != reader.remaining)
200     {
201         g_warning ("Ignoring packet of wrong length. Opcode %d expected %d octets, got %d", opcode, length, reader.remaining);
202         return NULL;
203     }
204
205     packet = xdmcp_packet_alloc (opcode);
206     switch (packet->opcode)
207     {
208     case XDMCP_BroadcastQuery:
209     case XDMCP_Query:
210     case XDMCP_IndirectQuery:
211         packet->Query.authentication_names = read_string_array (&reader);
212         break;
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);
217         break;
218     case XDMCP_Willing:
219         packet->Willing.authentication_name = read_string (&reader);
220         packet->Willing.hostname = read_string (&reader);
221         packet->Willing.status = read_string (&reader);
222         break;
223     case XDMCP_Unwilling:
224         packet->Unwilling.hostname = read_string (&reader);
225         packet->Unwilling.status = read_string (&reader);
226         break;
227     case XDMCP_Request:
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)
234         {
235             g_warning ("Number of connection types does not match number of connection addresses");
236             failed = TRUE;
237         }
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);
244         break;
245     case XDMCP_Accept:
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);
251         break;
252     case XDMCP_Decline:
253         packet->Decline.status = read_string (&reader);
254         packet->Decline.authentication_name = read_string (&reader);
255         read_data (&reader, &packet->Decline.authentication_data);
256         break;
257     case XDMCP_Manage:
258         packet->Manage.session_id = read_card32 (&reader);
259         packet->Manage.display_number = read_card16 (&reader);
260         packet->Manage.display_class = read_string (&reader);
261         break;
262     case XDMCP_Refuse:
263         packet->Refuse.session_id = read_card32 (&reader);
264         break;
265     case XDMCP_Failed:
266         packet->Failed.session_id = read_card32 (&reader);
267         packet->Failed.status = read_string (&reader);
268         break;
269     case XDMCP_KeepAlive:
270         packet->KeepAlive.display_number = read_card16 (&reader);
271         packet->KeepAlive.session_id = read_card32 (&reader);
272         break;
273     case XDMCP_Alive:
274         packet->Alive.session_running = read_card8 (&reader) == 0 ? FALSE : TRUE;
275         packet->Alive.session_id = read_card32 (&reader);
276         break;
277     default:
278         g_warning ("Unable to encode unknown opcode %d", packet->opcode);
279         failed = TRUE;
280         break;
281     }
282
283     if (!failed)
284     {
285         if (reader.overflow)
286         {
287             g_warning ("Short packet received");
288             failed = TRUE;
289         }
290         else if (reader.remaining != 0)
291         {
292             g_warning ("Extra data on end of message");
293             failed = TRUE;
294         }
295     }
296     if (failed)
297     {
298         xdmcp_packet_free (packet);
299         return NULL;
300     }
301
302     return packet;
303 }
304
305 gssize
306 xdmcp_packet_encode (XDMCPPacket *packet, guint8 *data, gsize max_length)
307 {
308     guint16 length;
309     PacketWriter writer;
310     int i;
311
312     if (max_length < 6)
313         return -1;
314
315     writer.data = data + 6;
316     writer.remaining = max_length - 6;
317     writer.overflow = FALSE;
318
319     switch (packet->opcode)
320     {
321     case XDMCP_BroadcastQuery:
322     case XDMCP_Query:
323     case XDMCP_IndirectQuery:
324         write_string_array (&writer, packet->Query.authentication_names);
325         break;
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);
330         break;
331     case XDMCP_Willing:
332         write_string (&writer, packet->Willing.authentication_name);
333         write_string (&writer, packet->Willing.hostname);
334         write_string (&writer, packet->Willing.status);
335         break;
336     case XDMCP_Unwilling:
337         write_string (&writer, packet->Unwilling.hostname);
338         write_string (&writer, packet->Unwilling.status);
339         break;
340     case XDMCP_Request:
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);
352         break;
353     case XDMCP_Accept:
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);
359         break;
360     case XDMCP_Decline:
361         write_string (&writer, packet->Decline.status);
362         write_string (&writer, packet->Decline.authentication_name);
363         write_data (&writer, &packet->Decline.authentication_data);
364         break;
365     case XDMCP_Manage:
366         write_card32 (&writer, packet->Manage.session_id);
367         write_card16 (&writer, packet->Manage.display_number);
368         write_string (&writer, packet->Manage.display_class);
369         break;
370     case XDMCP_Refuse:
371         write_card32 (&writer, packet->Refuse.session_id);
372         break;
373     case XDMCP_Failed:
374         write_card32 (&writer, packet->Failed.session_id);
375         write_string (&writer, packet->Failed.status);
376         break;
377     case XDMCP_KeepAlive:
378         write_card16 (&writer, packet->KeepAlive.display_number);
379         write_card32 (&writer, packet->KeepAlive.session_id);
380         break;
381     case XDMCP_Alive:
382         write_card8 (&writer, packet->Alive.session_running ? 1 : 0);
383         write_card32 (&writer, packet->Alive.session_id);
384         break;
385     }
386
387     length = max_length - 6 - writer.remaining;
388
389     /* Write header */
390     writer.data = data;
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);
396
397     if (writer.overflow)
398     {
399         g_warning ("Overflow writing response");
400         return -1;
401     }
402   
403     return length + 6;
404 }
405
406 static gchar *
407 data_tostring (XDMCPData *data)
408 {
409     GString *s;
410     guint16 i;
411     gchar *string;
412
413     s = g_string_new ("");
414     for (i = 0; i < data->length; i++)
415         g_string_append_printf (s, "%02X", data->data[i]);
416     string = s->str;
417     g_string_free (s, FALSE);
418
419     return string;
420 }
421
422 static gchar *
423 string_list_tostring (gchar **strings)
424 {
425     GString *s;
426     gchar *string;
427     gchar **i;
428   
429     s = g_string_new ("");  
430     for (i = strings; *i; i++)
431     {
432         if (i != strings)
433            g_string_append (s, " ");
434         g_string_append_printf (s, "'%s'", *i);
435     }
436     string = s->str;
437     g_string_free (s, FALSE);
438
439     return string;
440 }
441
442 gchar *
443 xdmcp_packet_tostring (XDMCPPacket *packet)
444 {
445     gchar *string, *t, *t2;
446     gint i;
447     GString *t3;
448
449     switch (packet->opcode)
450     {
451     case XDMCP_BroadcastQuery:
452         t = string_list_tostring (packet->Query.authentication_names);
453         string = g_strdup_printf ("BroadcastQuery(authentication_names=[%s])", t);
454         g_free (t);
455         return string;
456     case XDMCP_Query:
457         t = string_list_tostring (packet->Query.authentication_names);
458         string = g_strdup_printf ("Query(authentication_names=[%s])", t);
459         g_free (t);
460         return string;
461     case XDMCP_IndirectQuery:
462         t = string_list_tostring (packet->Query.authentication_names);
463         string = g_strdup_printf ("IndirectQuery(authentication_names=[%s])", t);
464         g_free (t);
465         return string;
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);
470         g_free (t);
471         return string;
472     case XDMCP_Willing:
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);      
478     case XDMCP_Request:
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++)
483         {
484             gchar *t4;
485
486             if (i != 0)
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);
490             g_free (t4);
491         }
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);
495         g_free (t);
496         g_free (t2);
497         g_string_free (t3, TRUE);
498         return string;
499     case XDMCP_Accept:
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);
505         g_free (t);
506         g_free (t2);
507         return string;
508     case XDMCP_Decline:
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);
512         g_free (t);
513         return string;
514     case XDMCP_Manage:
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);
517     case XDMCP_Refuse:
518         return g_strdup_printf ("Refuse(session_id=%d)", packet->Refuse.session_id);
519     case XDMCP_Failed:
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);
524     case XDMCP_Alive:
525         return g_strdup_printf ("Alive(session_running=%s session_id=%d)",
526                                 packet->Alive.session_running ? "true" : "false", packet->Alive.session_id);
527     default:
528         return g_strdup_printf ("XDMCPPacket(opcode=%d)", packet->opcode);
529     }
530 }
531
532 void
533 xdmcp_packet_free (XDMCPPacket *packet)
534 {
535     gint i;
536
537     if (packet == NULL)
538         return;
539
540     switch (packet->opcode)
541     {
542     case XDMCP_BroadcastQuery:
543     case XDMCP_Query:
544     case XDMCP_IndirectQuery:
545         g_strfreev (packet->Query.authentication_names);
546         break;
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);
551         break;
552     case XDMCP_Willing:
553         g_free (packet->Willing.authentication_name);
554         g_free (packet->Willing.hostname);
555         g_free (packet->Willing.status);
556         break;
557     case XDMCP_Unwilling:
558         g_free (packet->Unwilling.hostname);
559         g_free (packet->Unwilling.status);
560         break;
561     case XDMCP_Request:
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);
569         break;
570     case XDMCP_Accept:
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);
575         break;
576     case XDMCP_Decline:
577         g_free (packet->Decline.status);
578         g_free (packet->Decline.authentication_name);
579         g_free (packet->Decline.authentication_data.data);
580         break;
581     case XDMCP_Manage:
582         g_free (packet->Manage.display_class);
583         break;
584     case XDMCP_Refuse:
585         break;
586     case XDMCP_Failed:
587         g_free (packet->Failed.status);
588         break;
589     case XDMCP_KeepAlive:
590         break;
591     case XDMCP_Alive:
592         break;
593     }
594     g_free (packet);
595 }