Back to index

lightdm  1.3.2
xdmcp-protocol.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2010-2011 Robert Ancell.
00003  * Author: Robert Ancell <robert.ancell@canonical.com>
00004  * 
00005  * This program is free software: you can redistribute it and/or modify it under
00006  * the terms of the GNU General Public License as published by the Free Software
00007  * Foundation, either version 3 of the License, or (at your option) any later
00008  * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
00009  * license.
00010  */
00011 
00012 #include <string.h>
00013 
00014 #include "xdmcp-protocol.h"
00015 
00016 typedef struct
00017 {
00018     const guint8 *data;
00019     guint16 remaining;
00020     gboolean overflow;
00021 } PacketReader;
00022 
00023 static guint8
00024 read_card8 (PacketReader *reader)
00025 {
00026     guint8 value;
00027 
00028     if (reader->remaining < 1)
00029     {
00030         reader->overflow = TRUE;
00031         return 0;
00032     }
00033 
00034     value = reader->data[0];
00035     reader->data++;
00036     reader->remaining--;
00037 
00038     return value;
00039 }
00040 
00041 static guint16
00042 read_card16 (PacketReader *reader)
00043 {
00044     return read_card8 (reader) << 8 | read_card8 (reader);
00045 }
00046 
00047 static guint32
00048 read_card32 (PacketReader *reader)
00049 {
00050     return read_card8 (reader) << 24 | read_card8 (reader) << 16 | read_card8 (reader) << 8 | read_card8 (reader);
00051 }
00052 
00053 static void
00054 read_data (PacketReader *reader, XDMCPData *data)
00055 {
00056     guint16 i;
00057 
00058     data->length = read_card16 (reader);
00059     data->data = g_malloc (sizeof (guint8) * data->length);
00060     for (i = 0; i < data->length; i++)
00061         data->data[i] = read_card8 (reader);
00062 }
00063 
00064 static gchar *
00065 read_string (PacketReader *reader)
00066 {
00067     guint16 length, i;
00068     gchar *string;
00069 
00070     length = read_card16 (reader);
00071     string = g_malloc (sizeof (gchar) * (length + 1));
00072     for (i = 0; i < length; i++)
00073         string[i] = (gchar) read_card8 (reader);
00074     string[i] = '\0';
00075 
00076     return string;
00077 }
00078 
00079 static gchar **
00080 read_string_array (PacketReader *reader)
00081 {
00082     guint8 n_strings, i;
00083     gchar **strings;
00084 
00085     n_strings = read_card8 (reader);
00086     strings = g_malloc (sizeof (gchar *) * (n_strings + 1));
00087     for (i = 0; i < n_strings; i++)
00088         strings[i] = read_string (reader);
00089     strings[i] = NULL;
00090 
00091     return strings;
00092 }
00093 
00094 typedef struct
00095 {
00096     guint8 *data;
00097     guint16 remaining;
00098     gboolean overflow;
00099 } PacketWriter;
00100 
00101 static void
00102 write_card8 (PacketWriter *writer, guint8 value)
00103 {
00104     if (writer->remaining < 1)
00105     {
00106         writer->overflow = TRUE;
00107         return;
00108     }
00109 
00110     writer->data[0] = value;
00111     writer->data++;
00112     writer->remaining--;
00113 }
00114 
00115 static void
00116 write_card16 (PacketWriter *writer, guint16 value)
00117 {
00118     write_card8 (writer, value >> 8);
00119     write_card8 (writer, value & 0xFF);
00120 }
00121 
00122 static void
00123 write_card32 (PacketWriter *writer, guint16 value)
00124 {
00125     write_card8 (writer, (value >> 24) & 0xFF);
00126     write_card8 (writer, (value >> 16) & 0xFF);
00127     write_card8 (writer, (value >> 8) & 0xFF);
00128     write_card8 (writer, value & 0xFF);
00129 }
00130 
00131 static void
00132 write_data (PacketWriter *writer, const XDMCPData *value)
00133 {
00134     guint16 i;
00135 
00136     write_card16 (writer, value->length);
00137     for (i = 0; i < value->length; i++)
00138         write_card8 (writer, value->data[i]);
00139 }
00140 
00141 static void
00142 write_string (PacketWriter *writer, const gchar *value)
00143 {
00144     const gchar *c;
00145 
00146     write_card16 (writer, strlen (value));
00147     for (c = value; *c; c++)
00148         write_card8 (writer, *c);
00149 }
00150 
00151 static void
00152 write_string_array (PacketWriter *writer, gchar **values)
00153 {
00154     gchar **value;
00155 
00156     write_card8 (writer, g_strv_length (values));
00157     for (value = values; *value; value++)
00158         write_string (writer, *value);
00159 }
00160 
00161 XDMCPPacket *
00162 xdmcp_packet_alloc (XDMCPOpcode opcode)
00163 {
00164     XDMCPPacket *packet;
00165 
00166     packet = g_malloc0 (sizeof (XDMCPPacket));
00167     packet->opcode = opcode;
00168 
00169     return packet;
00170 }
00171 
00172 XDMCPPacket *
00173 xdmcp_packet_decode (const guint8 *data, gsize data_length)
00174 {
00175     XDMCPPacket *packet;
00176     guint16 version, opcode, length;
00177     PacketReader reader;
00178     int i;
00179     gboolean failed = FALSE;
00180 
00181     reader.data = data;
00182     reader.remaining = data_length;
00183     reader.overflow = FALSE;
00184 
00185     version = read_card16 (&reader);
00186     opcode = read_card16 (&reader);
00187     length = read_card16 (&reader);
00188 
00189     if (reader.overflow)
00190     {      
00191         g_warning ("Ignoring short packet"); // FIXME: Use GError
00192         return NULL;
00193     }
00194     if (version != XDMCP_VERSION)
00195     {
00196         g_warning ("Ignoring packet from unknown version %d", version);
00197         return NULL;
00198     }
00199     if (length != reader.remaining)
00200     {
00201         g_warning ("Ignoring packet of wrong length");
00202         return NULL;
00203     }
00204 
00205     packet = xdmcp_packet_alloc (opcode);
00206     switch (packet->opcode)
00207     {
00208     case XDMCP_BroadcastQuery:
00209     case XDMCP_Query:
00210     case XDMCP_IndirectQuery:
00211         packet->Query.authentication_names = read_string_array (&reader);
00212         break;
00213     case XDMCP_ForwardQuery:
00214         packet->ForwardQuery.client_address = read_string (&reader);
00215         packet->ForwardQuery.client_port = read_string (&reader);
00216         packet->ForwardQuery.authentication_names = read_string_array (&reader);
00217         break;
00218     case XDMCP_Willing:
00219         packet->Willing.authentication_name = read_string (&reader);
00220         packet->Willing.hostname = read_string (&reader);
00221         packet->Willing.status = read_string (&reader);
00222         break;
00223     case XDMCP_Unwilling:
00224         packet->Unwilling.hostname = read_string (&reader);
00225         packet->Unwilling.status = read_string (&reader);
00226         break;
00227     case XDMCP_Request:
00228         packet->Request.display_number = read_card16 (&reader);
00229         packet->Request.n_connections = read_card8 (&reader);
00230         packet->Request.connections = g_malloc (sizeof (XDMCPConnection) * packet->Request.n_connections);
00231         for (i = 0; i < packet->Request.n_connections; i++)
00232             packet->Request.connections[i].type = read_card16 (&reader);
00233         if (read_card8 (&reader) != packet->Request.n_connections)
00234         {
00235             g_warning ("Number of connection types does not match number of connection addresses");
00236             failed = TRUE;
00237         }
00238         for (i = 0; i < packet->Request.n_connections; i++)
00239             read_data (&reader, &packet->Request.connections[i].address);
00240         packet->Request.authentication_name = read_string (&reader);
00241         read_data (&reader, &packet->Request.authentication_data);
00242         packet->Request.authorization_names = read_string_array (&reader);
00243         packet->Request.manufacturer_display_id = read_string (&reader);
00244         break;
00245     case XDMCP_Accept:
00246         packet->Accept.session_id = read_card32 (&reader);
00247         packet->Accept.authentication_name = read_string (&reader);
00248         read_data (&reader, &packet->Accept.authentication_data);
00249         packet->Accept.authorization_name = read_string (&reader);
00250         read_data (&reader, &packet->Accept.authorization_data);
00251         break;
00252     case XDMCP_Decline:
00253         packet->Decline.status = read_string (&reader);
00254         packet->Decline.authentication_name = read_string (&reader);
00255         read_data (&reader, &packet->Decline.authentication_data);
00256         break;
00257     case XDMCP_Manage:
00258         packet->Manage.session_id = read_card32 (&reader);
00259         packet->Manage.display_number = read_card16 (&reader);
00260         packet->Manage.display_class = read_string (&reader);
00261         break;
00262     case XDMCP_Refuse:
00263         packet->Refuse.session_id = read_card32 (&reader);
00264         break;
00265     case XDMCP_Failed:
00266         packet->Failed.session_id = read_card32 (&reader);
00267         packet->Failed.status = read_string (&reader);
00268         break;
00269     case XDMCP_KeepAlive:
00270         packet->KeepAlive.display_number = read_card16 (&reader);
00271         packet->KeepAlive.session_id = read_card32 (&reader);
00272         break;
00273     case XDMCP_Alive:
00274         packet->Alive.session_running = read_card8 (&reader) == 0 ? FALSE : TRUE;
00275         packet->Alive.session_id = read_card32 (&reader);
00276         break;
00277     default:
00278         g_warning ("Unable to encode unknown opcode %d", packet->opcode);
00279         failed = TRUE;
00280         break;
00281     }
00282 
00283     if (!failed)
00284     {
00285         if (reader.overflow)
00286         {
00287             g_warning ("Short packet received");
00288             failed = TRUE;
00289         }
00290         else if (reader.remaining != 0)
00291         {
00292             g_warning ("Extra data on end of message");
00293             failed = TRUE;
00294         }
00295     }
00296     if (failed)
00297     {
00298         xdmcp_packet_free (packet);
00299         return NULL;
00300     }
00301 
00302     return packet;
00303 }
00304 
00305 gssize
00306 xdmcp_packet_encode (XDMCPPacket *packet, guint8 *data, gsize max_length)
00307 {
00308     guint16 length;
00309     PacketWriter writer;
00310     int i;
00311 
00312     if (max_length < 6)
00313         return -1;
00314 
00315     writer.data = data + 6;
00316     writer.remaining = max_length - 6;
00317     writer.overflow = FALSE;
00318 
00319     switch (packet->opcode)
00320     {
00321     case XDMCP_BroadcastQuery:
00322     case XDMCP_Query:
00323     case XDMCP_IndirectQuery:
00324         write_string_array (&writer, packet->Query.authentication_names);
00325         break;
00326     case XDMCP_ForwardQuery:
00327         write_string (&writer, packet->ForwardQuery.client_address);
00328         write_string (&writer, packet->ForwardQuery.client_port);
00329         write_string_array (&writer, packet->ForwardQuery.authentication_names);
00330         break;
00331     case XDMCP_Willing:
00332         write_string (&writer, packet->Willing.authentication_name);
00333         write_string (&writer, packet->Willing.hostname);
00334         write_string (&writer, packet->Willing.status);
00335         break;
00336     case XDMCP_Unwilling:
00337         write_string (&writer, packet->Unwilling.hostname);
00338         write_string (&writer, packet->Unwilling.status);
00339         break;
00340     case XDMCP_Request:
00341         write_card16 (&writer, packet->Request.display_number);
00342         write_card8 (&writer, packet->Request.n_connections);
00343         for (i = 0; i < packet->Request.n_connections; i++)
00344             write_card16 (&writer, packet->Request.connections[i].type);
00345         write_card8 (&writer, packet->Request.n_connections);
00346         for (i = 0; i < packet->Request.n_connections; i++)
00347             write_data (&writer, &packet->Request.connections[i].address);
00348         write_string (&writer, packet->Request.authentication_name);
00349         write_data (&writer, &packet->Request.authentication_data);
00350         write_string_array (&writer, packet->Request.authorization_names);
00351         write_string (&writer, packet->Request.manufacturer_display_id);
00352         break;
00353     case XDMCP_Accept:
00354         write_card32 (&writer, packet->Accept.session_id);      
00355         write_string (&writer, packet->Accept.authentication_name);
00356         write_data (&writer, &packet->Accept.authentication_data);
00357         write_string (&writer, packet->Accept.authorization_name);
00358         write_data (&writer, &packet->Accept.authorization_data);
00359         break;
00360     case XDMCP_Decline:
00361         write_string (&writer, packet->Decline.status);
00362         write_string (&writer, packet->Decline.authentication_name);
00363         write_data (&writer, &packet->Decline.authentication_data);
00364         break;
00365     case XDMCP_Manage:
00366         write_card32 (&writer, packet->Manage.session_id);
00367         write_card16 (&writer, packet->Manage.display_number);
00368         write_string (&writer, packet->Manage.display_class);
00369         break;
00370     case XDMCP_Refuse:
00371         write_card32 (&writer, packet->Refuse.session_id);
00372         break;
00373     case XDMCP_Failed:
00374         write_card32 (&writer, packet->Failed.session_id);
00375         write_string (&writer, packet->Failed.status);
00376         break;
00377     case XDMCP_KeepAlive:
00378         write_card16 (&writer, packet->KeepAlive.display_number);
00379         write_card32 (&writer, packet->KeepAlive.session_id);
00380         break;
00381     case XDMCP_Alive:
00382         write_card8 (&writer, packet->Alive.session_running ? 1 : 0);
00383         write_card32 (&writer, packet->Alive.session_id);
00384         break;
00385     }
00386 
00387     length = max_length - 6 - writer.remaining;
00388 
00389     /* Write header */
00390     writer.data = data;
00391     writer.remaining = 6;
00392     writer.overflow = FALSE;
00393     write_card16(&writer, XDMCP_VERSION);
00394     write_card16(&writer, packet->opcode);
00395     write_card16(&writer, length);
00396 
00397     if (writer.overflow)
00398     {
00399         g_warning ("Overflow writing response");
00400         return -1;
00401     }
00402   
00403     return length + 6;
00404 }
00405 
00406 static gchar *
00407 data_tostring (XDMCPData *data)
00408 {
00409     GString *s;
00410     guint16 i;
00411     gchar *string;
00412 
00413     s = g_string_new ("");
00414     for (i = 0; i < data->length; i++)
00415         g_string_append_printf (s, "%02X", data->data[i]);
00416     string = s->str;
00417     g_string_free (s, FALSE);
00418 
00419     return string;
00420 }
00421 
00422 static gchar *
00423 string_list_tostring (gchar **strings)
00424 {
00425     GString *s;
00426     gchar *string;
00427     gchar **i;
00428   
00429     s = g_string_new ("");  
00430     for (i = strings; *i; i++)
00431     {
00432         if (i != strings)
00433            g_string_append (s, " ");
00434         g_string_append_printf (s, "'%s'", *i);
00435     }
00436     string = s->str;
00437     g_string_free (s, FALSE);
00438 
00439     return string;
00440 }
00441 
00442 gchar *
00443 xdmcp_packet_tostring (XDMCPPacket *packet)
00444 {
00445     gchar *string, *t, *t2;
00446     gint i;
00447     GString *t3;
00448 
00449     switch (packet->opcode)
00450     {
00451     case XDMCP_BroadcastQuery:
00452         t = string_list_tostring (packet->Query.authentication_names);
00453         string = g_strdup_printf ("BroadcastQuery(authentication_names=[%s])", t);
00454         g_free (t);
00455         return string;
00456     case XDMCP_Query:
00457         t = string_list_tostring (packet->Query.authentication_names);
00458         string = g_strdup_printf ("Query(authentication_names=[%s])", t);
00459         g_free (t);
00460         return string;
00461     case XDMCP_IndirectQuery:
00462         t = string_list_tostring (packet->Query.authentication_names);
00463         string = g_strdup_printf ("IndirectQuery(authentication_names=[%s])", t);
00464         g_free (t);
00465         return string;
00466     case XDMCP_ForwardQuery:
00467         t = string_list_tostring (packet->ForwardQuery.authentication_names);
00468         string = g_strdup_printf ("ForwardQuery(client_address='%s' client_port='%s' authentication_names=[%s])",
00469                                   packet->ForwardQuery.client_address, packet->ForwardQuery.client_port, t);
00470         g_free (t);
00471         return string;
00472     case XDMCP_Willing:
00473         return g_strdup_printf ("Willing(authentication_name='%s' hostname='%s' status='%s')",
00474                                 packet->Willing.authentication_name, packet->Willing.hostname, packet->Willing.status);
00475     case XDMCP_Unwilling:
00476         return g_strdup_printf ("Unwilling(hostname='%s' status='%s')",
00477                                 packet->Unwilling.hostname, packet->Unwilling.status);      
00478     case XDMCP_Request:
00479         t = string_list_tostring (packet->Request.authorization_names);
00480         t2 = data_tostring (&packet->Request.authentication_data);
00481         t3 = g_string_new ("");
00482         for (i = 0; i < packet->Request.n_connections; i++)
00483         {
00484             gchar *t4;
00485 
00486             if (i != 0)
00487                g_string_append (t3, " ");
00488             t4 = data_tostring (&packet->Request.connections[i].address);
00489             g_string_append_printf (t3, "(%d, %s)", packet->Request.connections[i].type, t4);
00490             g_free (t4);
00491         }
00492         string = g_strdup_printf ("Request(display_number=%d connections=[%s] authentication_name='%s' authentication_data=%s authorization_names=[%s] manufacturer_display_id='%s')",
00493                                   packet->Request.display_number, t3->str, packet->Request.authentication_name, t2,
00494                                   t, packet->Request.manufacturer_display_id);
00495         g_free (t);
00496         g_free (t2);
00497         g_string_free (t3, TRUE);
00498         return string;
00499     case XDMCP_Accept:
00500         t = data_tostring (&packet->Accept.authentication_data);
00501         t2 = data_tostring (&packet->Accept.authorization_data);
00502         string =  g_strdup_printf ("Accept(session_id=%d authentication_name='%s' authentication_data=%s authorization_name='%s' authorization_data=%s)",
00503                                    packet->Accept.session_id, packet->Accept.authentication_name, t,
00504                                    packet->Accept.authorization_name, t2);
00505         g_free (t);
00506         g_free (t2);
00507         return string;
00508     case XDMCP_Decline:
00509         t = data_tostring (&packet->Decline.authentication_data);
00510         string = g_strdup_printf ("Decline(status='%s' authentication_name='%s' authentication_data=%s)",
00511                                   packet->Decline.status, packet->Decline.authentication_name, t);
00512         g_free (t);
00513         return string;
00514     case XDMCP_Manage:
00515         return g_strdup_printf ("Manage(session_id=%d display_number=%d display_class='%s')",
00516                                 packet->Manage.session_id, packet->Manage.display_number, packet->Manage.display_class);
00517     case XDMCP_Refuse:
00518         return g_strdup_printf ("Refuse(session_id=%d)", packet->Refuse.session_id);
00519     case XDMCP_Failed:
00520         return g_strdup_printf ("Failed(session_id=%d status='%s')", packet->Failed.session_id, packet->Failed.status);
00521     case XDMCP_KeepAlive:
00522         return g_strdup_printf ("KeepAlive(display_number=%d session_id=%d)",
00523                                 packet->KeepAlive.display_number, packet->KeepAlive.session_id);
00524     case XDMCP_Alive:
00525         return g_strdup_printf ("Alive(session_running=%s session_id=%d)",
00526                                 packet->Alive.session_running ? "true" : "false", packet->Alive.session_id);
00527     default:
00528         return g_strdup_printf ("XDMCPPacket(opcode=%d)", packet->opcode);
00529     }
00530 }
00531 
00532 void
00533 xdmcp_packet_free (XDMCPPacket *packet)
00534 {
00535     gint i;
00536 
00537     if (packet == NULL)
00538         return;
00539 
00540     switch (packet->opcode)
00541     {
00542     case XDMCP_BroadcastQuery:
00543     case XDMCP_Query:
00544     case XDMCP_IndirectQuery:
00545         g_strfreev (packet->Query.authentication_names);
00546         break;
00547     case XDMCP_ForwardQuery:
00548         g_free (packet->ForwardQuery.client_address);
00549         g_free (packet->ForwardQuery.client_port);
00550         g_strfreev (packet->ForwardQuery.authentication_names);
00551         break;
00552     case XDMCP_Willing:
00553         g_free (packet->Willing.authentication_name);
00554         g_free (packet->Willing.hostname);
00555         g_free (packet->Willing.status);
00556         break;
00557     case XDMCP_Unwilling:
00558         g_free (packet->Unwilling.hostname);
00559         g_free (packet->Unwilling.status);
00560         break;
00561     case XDMCP_Request:
00562         for (i = 0; i < packet->Request.n_connections; i++)
00563             g_free (packet->Request.connections[i].address.data);
00564         g_free (packet->Request.connections);
00565         g_free (packet->Request.authentication_name);
00566         g_free (packet->Request.authentication_data.data);
00567         g_strfreev (packet->Request.authorization_names);
00568         g_free (packet->Request.manufacturer_display_id);
00569         break;
00570     case XDMCP_Accept:
00571         g_free (packet->Accept.authentication_name);
00572         g_free (packet->Accept.authentication_data.data);
00573         g_free (packet->Accept.authorization_name);
00574         g_free (packet->Accept.authorization_data.data);
00575         break;
00576     case XDMCP_Decline:
00577         g_free (packet->Decline.status);
00578         g_free (packet->Decline.authentication_name);
00579         g_free (packet->Decline.authentication_data.data);
00580         break;
00581     case XDMCP_Manage:
00582         g_free (packet->Manage.display_class);
00583         break;
00584     case XDMCP_Refuse:
00585         break;
00586     case XDMCP_Failed:
00587         g_free (packet->Failed.status);
00588         break;
00589     case XDMCP_KeepAlive:
00590         break;
00591     case XDMCP_Alive:
00592         break;
00593     }
00594     g_free (packet);
00595 }