Back to index

lightdm  1.3.2
xdmcp-client.c
Go to the documentation of this file.
00001 #include <stdlib.h>
00002 #include <stdio.h>
00003 #include <string.h>
00004 #include <errno.h>
00005 #include <sys/types.h>
00006 #include <sys/socket.h>
00007 #include <gio/gio.h>
00008 
00009 #include "x-common.h"
00010 #include "xdmcp-client.h"
00011 
00012 G_DEFINE_TYPE (XDMCPClient, xdmcp_client, G_TYPE_OBJECT);
00013 
00014 #define MAXIMUM_REQUEST_LENGTH 65535
00015 
00016 typedef enum
00017 {
00018     XDMCP_BroadcastQuery = 1,
00019     XDMCP_Query          = 2,
00020     XDMCP_IndirectQuery  = 3,
00021     XDMCP_ForwardQuery   = 4,
00022     XDMCP_Willing        = 5,
00023     XDMCP_Unwilling      = 6,
00024     XDMCP_Request        = 7,
00025     XDMCP_Accept         = 8,
00026     XDMCP_Decline        = 9,
00027     XDMCP_Manage         = 10,
00028     XDMCP_Refuse         = 11,
00029     XDMCP_Failed         = 12,
00030     XDMCP_KeepAlive      = 13,
00031     XDMCP_Alive          = 14
00032 } XDMCPOpcode;
00033 
00034 struct XDMCPClientPrivate
00035 {
00036     gchar *host;
00037     gint port;
00038     GSocket *socket;
00039     guint query_timer;
00040     gchar *authorization_name;
00041     gint authorization_data_length;
00042     guint8 *authorization_data;
00043 };
00044 
00045 enum {
00046     XDMCP_CLIENT_QUERY,  
00047     XDMCP_CLIENT_WILLING,
00048     XDMCP_CLIENT_ACCEPT,
00049     XDMCP_CLIENT_DECLINE,
00050     XDMCP_CLIENT_FAILED,
00051     XDMCP_CLIENT_LAST_SIGNAL
00052 };
00053 static guint xdmcp_client_signals[XDMCP_CLIENT_LAST_SIGNAL] = { 0 };
00054 
00055 static void
00056 xdmcp_write (XDMCPClient *client, const guint8 *buffer, gssize buffer_length)
00057 {
00058     gssize n_written;
00059     GError *error = NULL;
00060 
00061     n_written = g_socket_send (client->priv->socket, (const gchar *) buffer, buffer_length, NULL, &error);
00062     if (n_written < 0)
00063         g_warning ("Failed to send XDMCP request: %s", error->message);
00064     else if (n_written != buffer_length)
00065         g_warning ("Partial write for XDMCP request, wrote %zi, expected %zi", n_written, buffer_length);
00066     g_clear_error (&error);
00067 }
00068 
00069 static void
00070 decode_willing (XDMCPClient *client, const guint8 *buffer, gssize buffer_length)
00071 {
00072     XDMCPWilling *message;
00073     gsize offset = 0;
00074     guint16 length;
00075 
00076     if (client->priv->query_timer == 0)
00077     {
00078         g_debug ("Ignoring XDMCP unrequested/duplicate Willing");
00079         return;
00080     }
00081 
00082     /* Stop sending queries */
00083     g_source_remove (client->priv->query_timer);
00084     client->priv->query_timer = 0;
00085   
00086     message = g_malloc0 (sizeof (XDMCPWilling));
00087 
00088     length = read_card16 (buffer, buffer_length, X_BYTE_ORDER_MSB, &offset);
00089     message->authentication_name = read_string (buffer, buffer_length, length, &offset);
00090     length = read_card16 (buffer, buffer_length, X_BYTE_ORDER_MSB, &offset);
00091     message->hostname = read_string (buffer, buffer_length, length, &offset);
00092     length = read_card16 (buffer, buffer_length, X_BYTE_ORDER_MSB, &offset);
00093     message->status = read_string (buffer, buffer_length, length, &offset);
00094 
00095     g_signal_emit (client, xdmcp_client_signals[XDMCP_CLIENT_WILLING], 0, message);
00096   
00097     g_free (message->authentication_name);
00098     g_free (message->hostname);
00099     g_free (message->status);
00100     g_free (message);
00101 }
00102 
00103 static void
00104 decode_accept (XDMCPClient *client, const guint8 *buffer, gssize buffer_length)
00105 {
00106     XDMCPAccept *message;
00107     gsize offset = 0;
00108     guint16 length;
00109 
00110     message = g_malloc (sizeof (XDMCPAccept));
00111 
00112     message->session_id = read_card32 (buffer, buffer_length, X_BYTE_ORDER_MSB, &offset);
00113     length = read_card16 (buffer, buffer_length, X_BYTE_ORDER_MSB, &offset);
00114     message->authentication_name = read_string (buffer, buffer_length, length, &offset);
00115     length = read_card16 (buffer, buffer_length, X_BYTE_ORDER_MSB, &offset);
00116     read_string8 (buffer, buffer_length, length, &offset);
00117     length = read_card16 (buffer, buffer_length, X_BYTE_ORDER_MSB, &offset);
00118     message->authorization_name = read_string (buffer, buffer_length, length, &offset);
00119     message->authorization_data_length = read_card16 (buffer, buffer_length, X_BYTE_ORDER_MSB, &offset);
00120     message->authorization_data = read_string8 (buffer, buffer_length, length, &offset);
00121 
00122     g_signal_emit (client, xdmcp_client_signals[XDMCP_CLIENT_ACCEPT], 0, message);
00123 
00124     g_free (message->authentication_name);
00125     g_free (message->authorization_name);
00126     g_free (message->authorization_data);
00127     g_free (message);
00128 }
00129 
00130 static void
00131 decode_decline (XDMCPClient *client, const guint8 *buffer, gssize buffer_length)
00132 {
00133     XDMCPDecline *message;
00134     gsize offset = 0;
00135     guint16 length;
00136   
00137     message = g_malloc0 (sizeof (XDMCPDecline));
00138 
00139     length = read_card16 (buffer, buffer_length, X_BYTE_ORDER_MSB, &offset);
00140     message->status = read_string (buffer, buffer_length, length, &offset);
00141     length = read_card16 (buffer, buffer_length, X_BYTE_ORDER_MSB, &offset);
00142     message->authentication_name = read_string (buffer, buffer_length, length, &offset);
00143     length = read_card16 (buffer, buffer_length, X_BYTE_ORDER_MSB, &offset);
00144     read_string8 (buffer, buffer_length, length, &offset);
00145   
00146     g_signal_emit (client, xdmcp_client_signals[XDMCP_CLIENT_DECLINE], 0, message);
00147 
00148     g_free (message->status);
00149     g_free (message->authentication_name);
00150     g_free (message);
00151 }
00152 
00153 static void
00154 decode_failed (XDMCPClient *client, const guint8 *buffer, gssize buffer_length)
00155 {
00156     XDMCPFailed *message;
00157     gsize offset = 0;
00158     guint16 length;
00159 
00160     message = g_malloc0 (sizeof (XDMCPFailed));
00161 
00162     message->session_id = read_card32 (buffer, buffer_length, X_BYTE_ORDER_MSB, &offset);
00163     length = read_card16 (buffer, buffer_length, X_BYTE_ORDER_MSB, &offset);
00164     message->status = read_string (buffer, buffer_length, length, &offset);
00165 
00166     g_signal_emit (client, xdmcp_client_signals[XDMCP_CLIENT_FAILED], 0, message);
00167 
00168     g_free (message->status);
00169     g_free (message);
00170 }
00171 
00172 static gboolean
00173 xdmcp_data_cb (GIOChannel *channel, GIOCondition condition, gpointer data)
00174 {
00175     XDMCPClient *client = data;
00176     guint8 buffer[MAXIMUM_REQUEST_LENGTH];
00177     gssize n_read;
00178 
00179     n_read = recv (g_io_channel_unix_get_fd (channel), buffer, MAXIMUM_REQUEST_LENGTH, 0);
00180     if (n_read < 0)
00181         g_warning ("Error reading from XDMCP socket: %s", strerror (errno));
00182     else if (n_read == 0)
00183     {
00184         g_debug ("EOF");
00185         return FALSE;
00186     }
00187     else
00188     {
00189         gsize offset = 0;
00190         guint16 version, opcode, length;
00191 
00192         version = read_card16 (buffer, n_read, X_BYTE_ORDER_MSB, &offset);
00193         opcode = read_card16 (buffer, n_read, X_BYTE_ORDER_MSB, &offset);
00194         length = read_card16 (buffer, n_read, X_BYTE_ORDER_MSB, &offset);
00195 
00196         if (version != 1)
00197         {
00198             g_debug ("Ignoring XDMCP version %d message", version);
00199             return TRUE;
00200         }
00201         if (6 + length > n_read)
00202         {
00203             g_debug ("Ignoring XDMCP message of length %zi with invalid length field %d", n_read, length);
00204             return TRUE;
00205         }
00206         switch (opcode)
00207         {
00208         case XDMCP_Willing:
00209             decode_willing (client, buffer + offset, n_read - offset);
00210             break;
00211 
00212         case XDMCP_Accept:
00213             decode_accept (client, buffer + offset, n_read - offset);
00214             break;
00215 
00216         case XDMCP_Decline:
00217             decode_decline (client, buffer + offset, n_read - offset);
00218             break;
00219 
00220         case XDMCP_Failed:
00221             decode_failed (client, buffer + offset, n_read - offset);
00222             break;
00223 
00224         default:
00225             g_debug ("Ignoring unknown XDMCP opcode %d", opcode);
00226             break;
00227         }
00228     }
00229 
00230     return TRUE;
00231 }
00232 
00233 static gboolean
00234 xdmcp_query_cb (gpointer data)
00235 {
00236     XDMCPClient *client = data;
00237     g_signal_emit (client, xdmcp_client_signals[XDMCP_CLIENT_QUERY], 0);
00238     xdmcp_client_send_query (client);
00239     return TRUE;
00240 }
00241 
00242 XDMCPClient *
00243 xdmcp_client_new (void)
00244 {
00245     return g_object_new (xdmcp_client_get_type (), NULL);
00246 }
00247 
00248 void
00249 xdmcp_client_set_hostname (XDMCPClient *client, const gchar *hostname)
00250 {
00251     g_free (client->priv->host);
00252     client->priv->host = g_strdup (hostname);
00253 }
00254 
00255 void
00256 xdmcp_client_set_port (XDMCPClient *client, guint16 port)
00257 {
00258     client->priv->port = port;
00259 }
00260 
00261 gboolean
00262 xdmcp_client_start (XDMCPClient *client)
00263 {
00264     GSocketConnectable *address;
00265     GSocketAddress *socket_address;
00266     GError *error = NULL;
00267 
00268     client->priv->socket = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &error);
00269 
00270     address = g_network_address_new (client->priv->host, client->priv->port);
00271     socket_address = g_socket_address_enumerator_next (g_socket_connectable_enumerate (address), NULL, NULL);
00272   
00273     if (!client->priv->socket ||
00274         !g_socket_connect (client->priv->socket, socket_address, NULL, &error) ||
00275         !g_io_add_watch (g_io_channel_unix_new (g_socket_get_fd (client->priv->socket)), G_IO_IN, xdmcp_data_cb, client))
00276     {
00277         g_warning ("Error creating XDMCP socket: %s", error->message);
00278         return FALSE;
00279     }
00280 
00281     client->priv->query_timer = g_timeout_add (2000, xdmcp_query_cb, client);
00282     xdmcp_query_cb (client); 
00283 
00284     return TRUE;
00285 }
00286 
00287 GInetAddress *
00288 xdmcp_client_get_local_address (XDMCPClient *client)
00289 {
00290     GSocketAddress *socket_address;
00291   
00292     if (!client->priv->socket)
00293         return NULL;
00294 
00295     socket_address = g_socket_get_local_address (client->priv->socket, NULL);
00296     return g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (socket_address));
00297 }
00298 
00299 static void
00300 xdmcp_client_init (XDMCPClient *client)
00301 {
00302     client->priv = G_TYPE_INSTANCE_GET_PRIVATE (client, xdmcp_client_get_type (), XDMCPClientPrivate);
00303     client->priv->port = XDMCP_PORT;
00304 }
00305 
00306 void
00307 xdmcp_client_send_query (XDMCPClient *client)
00308 {
00309     guint8 buffer[MAXIMUM_REQUEST_LENGTH];
00310     gsize offset = 0;
00311 
00312     write_card16 (buffer, MAXIMUM_REQUEST_LENGTH, X_BYTE_ORDER_MSB, XDMCP_VERSION, &offset);
00313     write_card16 (buffer, MAXIMUM_REQUEST_LENGTH, X_BYTE_ORDER_MSB, XDMCP_Query, &offset);
00314     write_card16 (buffer, MAXIMUM_REQUEST_LENGTH, X_BYTE_ORDER_MSB, 1, &offset);
00315     write_card8 (buffer, MAXIMUM_REQUEST_LENGTH, 0, &offset);
00316 
00317     xdmcp_write (client, buffer, offset);   
00318 }
00319 
00320 void
00321 xdmcp_client_send_request (XDMCPClient *client,
00322                            guint16 display_number,
00323                            GInetAddress **addresses,
00324                            const gchar *authentication_name,
00325                            const guint8 *authentication_data, guint16 authentication_data_length,
00326                            gchar **authorization_names, const gchar *mfid)
00327 {
00328     guint8 buffer[MAXIMUM_REQUEST_LENGTH];
00329     gsize length = 0, offset = 0, n_addresses = 0, n_names = 0;
00330     GInetAddress **address;
00331     gchar **name;
00332 
00333     length = 11 + strlen (authentication_name) + authentication_data_length + strlen (mfid);
00334     for (address = addresses; *address; address++)
00335     {
00336         gssize native_address_length = g_inet_address_get_native_size (*address);
00337         length += 4 + native_address_length;
00338         n_addresses++;
00339     }
00340     for (name = authorization_names; *name; name++)
00341     {
00342         length += 2 + strlen (*name);
00343         n_names++;
00344     }
00345 
00346     write_card16 (buffer, MAXIMUM_REQUEST_LENGTH, X_BYTE_ORDER_MSB, XDMCP_VERSION, &offset);
00347     write_card16 (buffer, MAXIMUM_REQUEST_LENGTH, X_BYTE_ORDER_MSB, XDMCP_Request, &offset);
00348     write_card16 (buffer, MAXIMUM_REQUEST_LENGTH, X_BYTE_ORDER_MSB, length, &offset);
00349 
00350     write_card16 (buffer, MAXIMUM_REQUEST_LENGTH, X_BYTE_ORDER_MSB, display_number, &offset);
00351     write_card8 (buffer, MAXIMUM_REQUEST_LENGTH, n_addresses, &offset);
00352     for (address = addresses; *address; address++)
00353         write_card16 (buffer, MAXIMUM_REQUEST_LENGTH, X_BYTE_ORDER_MSB, 0, &offset); /* FamilyInternet */
00354     write_card8 (buffer, MAXIMUM_REQUEST_LENGTH, n_addresses, &offset);
00355     for (address = addresses; *address; address++)
00356     {
00357         gssize native_address_length;
00358         const guint8 *native_address;
00359 
00360         native_address_length = g_inet_address_get_native_size (*address);
00361         native_address = g_inet_address_to_bytes (*address);
00362         write_card16 (buffer, MAXIMUM_REQUEST_LENGTH, X_BYTE_ORDER_MSB, native_address_length, &offset);
00363         write_string8 (buffer, MAXIMUM_REQUEST_LENGTH, native_address, native_address_length, &offset);
00364     }
00365     write_card16 (buffer, MAXIMUM_REQUEST_LENGTH, X_BYTE_ORDER_MSB, strlen (authentication_name), &offset);
00366     write_string (buffer, MAXIMUM_REQUEST_LENGTH, authentication_name, &offset);
00367     write_card16 (buffer, MAXIMUM_REQUEST_LENGTH, X_BYTE_ORDER_MSB, authentication_data_length, &offset);
00368     write_string8 (buffer, MAXIMUM_REQUEST_LENGTH, authentication_data, authentication_data_length, &offset);
00369     write_card8 (buffer, MAXIMUM_REQUEST_LENGTH, n_names, &offset);
00370     for (name = authorization_names; *name; name++)
00371     {
00372         write_card16 (buffer, MAXIMUM_REQUEST_LENGTH, X_BYTE_ORDER_MSB, strlen (*name), &offset);
00373         write_string (buffer, MAXIMUM_REQUEST_LENGTH, *name, &offset);
00374     }
00375     write_card16 (buffer, MAXIMUM_REQUEST_LENGTH, X_BYTE_ORDER_MSB, strlen (mfid), &offset);
00376     write_string (buffer, MAXIMUM_REQUEST_LENGTH, mfid, &offset);
00377 
00378     xdmcp_write (client, buffer, offset);
00379 }
00380 
00381 void
00382 xdmcp_client_send_manage (XDMCPClient *client, guint32 session_id, guint16 display_number, gchar *display_class)
00383 {
00384     guint8 buffer[MAXIMUM_REQUEST_LENGTH];
00385     gsize offset = 0;
00386 
00387     write_card16 (buffer, MAXIMUM_REQUEST_LENGTH, X_BYTE_ORDER_MSB, XDMCP_VERSION, &offset);
00388     write_card16 (buffer, MAXIMUM_REQUEST_LENGTH, X_BYTE_ORDER_MSB, XDMCP_Manage, &offset);
00389     write_card16 (buffer, MAXIMUM_REQUEST_LENGTH, X_BYTE_ORDER_MSB, 8 + strlen (display_class), &offset);
00390 
00391     write_card32 (buffer, MAXIMUM_REQUEST_LENGTH, X_BYTE_ORDER_MSB, session_id, &offset);
00392     write_card16 (buffer, MAXIMUM_REQUEST_LENGTH, X_BYTE_ORDER_MSB, display_number, &offset);
00393     write_card16 (buffer, MAXIMUM_REQUEST_LENGTH, X_BYTE_ORDER_MSB, strlen (display_class), &offset);
00394     write_string (buffer, MAXIMUM_REQUEST_LENGTH, display_class, &offset);
00395 
00396     xdmcp_write (client, buffer, offset); 
00397 }
00398 
00399 static void
00400 xdmcp_client_finalize (GObject *object)
00401 {
00402     XDMCPClient *client = (XDMCPClient *) object;
00403     g_free (client->priv->host);
00404     if (client->priv->socket)
00405         g_object_unref (client->priv->socket);
00406     g_free (client->priv->authorization_name);
00407     g_free (client->priv->authorization_data);
00408 }
00409 
00410 static void
00411 xdmcp_client_class_init (XDMCPClientClass *klass)
00412 {
00413     GObjectClass *object_class = G_OBJECT_CLASS (klass);
00414     object_class->finalize = xdmcp_client_finalize;
00415     g_type_class_add_private (klass, sizeof (XDMCPClientPrivate));
00416     xdmcp_client_signals[XDMCP_CLIENT_QUERY] =
00417         g_signal_new ("query",
00418                       G_TYPE_FROM_CLASS (klass),
00419                       G_SIGNAL_RUN_LAST,
00420                       G_STRUCT_OFFSET (XDMCPClientClass, query),
00421                       NULL, NULL,
00422                       g_cclosure_marshal_VOID__VOID,
00423                       G_TYPE_NONE, 0);
00424     xdmcp_client_signals[XDMCP_CLIENT_WILLING] =
00425         g_signal_new ("willing",
00426                       G_TYPE_FROM_CLASS (klass),
00427                       G_SIGNAL_RUN_LAST,
00428                       G_STRUCT_OFFSET (XDMCPClientClass, willing),
00429                       NULL, NULL,
00430                       g_cclosure_marshal_VOID__POINTER,
00431                       G_TYPE_NONE, 1, G_TYPE_POINTER);
00432     xdmcp_client_signals[XDMCP_CLIENT_ACCEPT] =
00433         g_signal_new ("accept",
00434                       G_TYPE_FROM_CLASS (klass),
00435                       G_SIGNAL_RUN_LAST,
00436                       G_STRUCT_OFFSET (XDMCPClientClass, accept),
00437                       NULL, NULL,
00438                       g_cclosure_marshal_VOID__POINTER,
00439                       G_TYPE_NONE, 1, G_TYPE_POINTER);
00440     xdmcp_client_signals[XDMCP_CLIENT_DECLINE] =
00441         g_signal_new ("decline",
00442                       G_TYPE_FROM_CLASS (klass),
00443                       G_SIGNAL_RUN_LAST,
00444                       G_STRUCT_OFFSET (XDMCPClientClass, decline),
00445                       NULL, NULL,
00446                       g_cclosure_marshal_VOID__POINTER,
00447                       G_TYPE_NONE, 1, G_TYPE_POINTER);
00448     xdmcp_client_signals[XDMCP_CLIENT_FAILED] =
00449         g_signal_new ("failed",
00450                       G_TYPE_FROM_CLASS (klass),
00451                       G_SIGNAL_RUN_LAST,
00452                       G_STRUCT_OFFSET (XDMCPClientClass, failed),
00453                       NULL, NULL,
00454                       g_cclosure_marshal_VOID__POINTER,
00455                       G_TYPE_NONE, 1, G_TYPE_POINTER);
00456 }