Back to index

lightdm  1.3.2
xauthority.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 #include <errno.h>
00014 #include <unistd.h>
00015 #include <sys/stat.h>
00016 
00017 #include "xauthority.h"
00018 
00019 struct XAuthorityPrivate
00020 {
00021     /* Protocol family */
00022     guint16 family;
00023 
00024     /* Address of the X server (format dependent on family) */
00025     guint8 *address;
00026     gsize address_length;
00027   
00028     /* Display number of X server */
00029     gchar *number;
00030 
00031     /* Authorization scheme */
00032     gchar *authorization_name;
00033 
00034     /* Authorization data */
00035     guint8 *authorization_data;
00036     gsize authorization_data_length;
00037 };
00038 
00039 G_DEFINE_TYPE (XAuthority, xauth, G_TYPE_OBJECT);
00040 
00041 XAuthority *
00042 xauth_new (guint16 family, const guint8 *address, gsize address_length, const gchar *number, const gchar *name, const guint8 *data, gsize data_length)
00043 {
00044     XAuthority *auth = g_object_new (XAUTHORITY_TYPE, NULL);
00045 
00046     xauth_set_family (auth, family);  
00047     xauth_set_address (auth, address, address_length);
00048     xauth_set_number (auth, number);
00049     xauth_set_authorization_name (auth, name);
00050     xauth_set_authorization_data (auth, data, data_length);
00051 
00052     return auth;
00053 }
00054 
00055 XAuthority *
00056 xauth_new_cookie (guint16 family, const guint8 *address, gsize address_length, const gchar *number)
00057 {
00058     guint8 cookie[16];
00059     gint i;
00060   
00061     for (i = 0; i < 16; i++)
00062         cookie[i] = g_random_int () & 0xFF;
00063 
00064     return xauth_new (family, address, address_length, number, "MIT-MAGIC-COOKIE-1", cookie, 16);
00065 }
00066 
00067 void
00068 xauth_set_family (XAuthority *auth, guint16 family)
00069 {
00070     g_return_if_fail (auth != NULL);
00071     auth->priv->family = family;
00072 }
00073 
00074 guint16
00075 xauth_get_family (XAuthority *auth)
00076 {
00077     g_return_val_if_fail (auth != NULL, 0);
00078     return auth->priv->family;
00079 }
00080 
00081 void
00082 xauth_set_address (XAuthority *auth, const guint8 *address, gsize address_length)
00083 {
00084     g_return_if_fail (auth != NULL);
00085     g_free (auth->priv->address);
00086     auth->priv->address = g_malloc (address_length);
00087     memcpy (auth->priv->address, address, address_length);
00088     auth->priv->address_length = address_length;
00089 }
00090 
00091 const guint8 *
00092 xauth_get_address (XAuthority *auth)
00093 {
00094     g_return_val_if_fail (auth != NULL, NULL);
00095     return auth->priv->address;
00096 }
00097 
00098 const gsize
00099 xauth_get_address_length (XAuthority *auth)
00100 {
00101     g_return_val_if_fail (auth != NULL, 0);
00102     return auth->priv->address_length;
00103 }
00104 
00105 void
00106 xauth_set_number (XAuthority *auth, const gchar *number)
00107 {
00108     g_return_if_fail (auth != NULL);
00109     g_free (auth->priv->number);
00110     auth->priv->number = g_strdup (number);
00111 }
00112 
00113 const gchar *
00114 xauth_get_number (XAuthority *auth)
00115 {
00116     g_return_val_if_fail (auth != NULL, NULL);
00117     return auth->priv->number;
00118 }
00119 
00120 void
00121 xauth_set_authorization_name (XAuthority *auth, const gchar *name)
00122 {
00123     g_return_if_fail (auth != NULL);
00124     g_free (auth->priv->authorization_name);
00125     auth->priv->authorization_name = g_strdup (name);
00126 }
00127 
00128 const gchar *
00129 xauth_get_authorization_name (XAuthority *auth)
00130 {
00131     g_return_val_if_fail (auth != NULL, NULL);
00132     return auth->priv->authorization_name;
00133 }
00134 
00135 void
00136 xauth_set_authorization_data (XAuthority *auth, const guint8 *data, gsize data_length)
00137 {
00138     g_return_if_fail (auth != NULL);
00139     g_free (auth->priv->authorization_data);
00140     auth->priv->authorization_data = g_malloc (data_length);
00141     memcpy (auth->priv->authorization_data, data, data_length);
00142     auth->priv->authorization_data_length = data_length;
00143 }
00144 
00145 const guint8 *
00146 xauth_get_authorization_data (XAuthority *auth)
00147 {
00148     g_return_val_if_fail (auth != NULL, NULL);
00149     return auth->priv->authorization_data;
00150 }
00151 
00152 guint8 *
00153 xauth_copy_authorization_data (XAuthority *auth)
00154 {
00155     guint8 *data;
00156 
00157     g_return_val_if_fail (auth != NULL, NULL);
00158 
00159     data = g_malloc (auth->priv->authorization_data_length);
00160     memcpy (data, auth->priv->authorization_data, auth->priv->authorization_data_length);
00161     return data;
00162 }
00163 
00164 gsize
00165 xauth_get_authorization_data_length (XAuthority *auth)
00166 {
00167     g_return_val_if_fail (auth != NULL, 0);
00168     return auth->priv->authorization_data_length;
00169 }
00170 
00171 static gboolean
00172 read_uint16 (GInputStream *stream, guint16 *value, gboolean *eof, GError **error)
00173 {
00174     guint8 data[2] = {0, 0};
00175     gsize n_read;
00176 
00177     if (g_input_stream_read_all (stream, data, 2, &n_read, NULL, error) < 0)
00178         return FALSE;
00179   
00180     if (n_read == 0 && eof)
00181        *eof = TRUE;
00182 
00183     *value = data[0] << 8 | data[1];
00184   
00185     return TRUE;
00186 }
00187 
00188 static gboolean
00189 read_data (GInputStream *stream, guint16 length, guint8 **value, GError **error)
00190 {
00191     g_free (*value);
00192     *value = g_malloc0 (length + 1);
00193     if (g_input_stream_read_all (stream, *value, length, NULL, NULL, error) < 0)
00194     {
00195         g_free (*value);
00196         *value = NULL;
00197         return FALSE;
00198     }
00199     (*value)[length] = 0;
00200 
00201     return TRUE;
00202 }
00203 
00204 static gboolean
00205 read_string (GInputStream *stream, gchar **value, GError **error)
00206 {
00207     guint16 length;
00208     if (!read_uint16 (stream, &length, NULL, error))
00209         return FALSE;
00210     return read_data (stream, length, (guint8 **) value, error);
00211 }
00212 
00213 static gboolean
00214 write_uint16 (GOutputStream *stream, guint16 value, GError **error)
00215 {
00216     guint8 data[2];
00217 
00218     data[0] = value >> 8;
00219     data[1] = value & 0xFF;
00220     return g_output_stream_write (stream, data, 2, NULL, error) >= 0;
00221 }
00222 
00223 static gboolean
00224 write_data (GOutputStream *stream, const guint8 *data, gsize data_length, GError **error)
00225 {
00226     return g_output_stream_write (stream, data, data_length, NULL, error) >= 0;
00227 }
00228 
00229 static gboolean
00230 write_string (GOutputStream *stream, const gchar *value, GError **error)
00231 {
00232     if (!write_uint16 (stream, strlen (value), error) ||
00233         !write_data (stream, (guint8 *) value, strlen (value), error))
00234         return FALSE;
00235   
00236     return TRUE;
00237 }
00238 
00239 gboolean
00240 xauth_write (XAuthority *auth, XAuthWriteMode mode, GFile *file, GError **error)
00241 {
00242     GList *link, *records = NULL;
00243     GFileInputStream *input_stream = NULL;
00244     GFileOutputStream *output_stream;
00245     XAuthority *a;
00246     gboolean result;
00247     gboolean matched = FALSE;
00248 
00249     g_return_val_if_fail (auth != NULL, FALSE);
00250     g_return_val_if_fail (file != NULL, FALSE);
00251 
00252     /* Read out existing records */
00253     if (mode != XAUTH_WRITE_MODE_SET)
00254     {
00255         GError *read_error = NULL;
00256 
00257         input_stream = g_file_read (file, NULL, &read_error);
00258         if (read_error && !g_error_matches (read_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
00259             g_warning ("Error reading existing Xauthority: %s", read_error->message);
00260         g_clear_error (&read_error);
00261     }
00262     while (input_stream)
00263     {
00264         gboolean eof = FALSE, address_matches = FALSE;
00265         guint16 address_length = 0;
00266         guint16 authorization_data_length = 0;
00267         GError *read_error = NULL;
00268 
00269         a = g_object_new (XAUTHORITY_TYPE, NULL);
00270 
00271         result = read_uint16 (G_INPUT_STREAM (input_stream), &a->priv->family, &eof, &read_error) &&
00272                  read_uint16 (G_INPUT_STREAM (input_stream), &address_length, NULL, &read_error) &&
00273                  read_data (G_INPUT_STREAM (input_stream), address_length, &a->priv->address, &read_error) &&
00274                  read_string (G_INPUT_STREAM (input_stream), &a->priv->number, &read_error) &&
00275                  read_string (G_INPUT_STREAM (input_stream), &a->priv->authorization_name, &read_error) &&
00276                  read_uint16 (G_INPUT_STREAM (input_stream), &authorization_data_length, NULL, &read_error) &&
00277                  read_data (G_INPUT_STREAM (input_stream), authorization_data_length, &a->priv->authorization_data, &read_error);
00278         a->priv->address_length = address_length;
00279         a->priv->authorization_data_length = authorization_data_length;
00280         if (read_error)
00281             g_warning ("Error reading X authority %s: %s", g_file_get_path (file), read_error->message);
00282         g_clear_error (&read_error);
00283 
00284         if (eof || !result)
00285         {
00286             g_object_unref (a);
00287             break;
00288         }
00289 
00290         if (auth->priv->address_length == a->priv->address_length)
00291         {
00292             guint16 i;
00293             for (i = 0; i < auth->priv->address_length && auth->priv->address[i] == a->priv->address[i]; i++);
00294             address_matches = i == auth->priv->address_length;
00295         }
00296 
00297         /* If this record matches, then update or delete it */
00298         if (!matched &&
00299             auth->priv->family == a->priv->family &&
00300             address_matches &&
00301             strcmp (auth->priv->number, a->priv->number) == 0)
00302         {
00303             matched = TRUE;
00304             if (mode == XAUTH_WRITE_MODE_REMOVE)
00305             {
00306                 g_object_unref (a);
00307                 continue;
00308             }
00309             else
00310                 xauth_set_authorization_data (a, auth->priv->authorization_data, auth->priv->authorization_data_length);
00311         }
00312 
00313         records = g_list_append (records, a);
00314     }
00315     if (input_stream)
00316     {
00317         GError *close_error = NULL;
00318         g_input_stream_close (G_INPUT_STREAM (input_stream), NULL, &close_error);
00319         if (close_error)
00320             g_warning ("Error closing Xauthority: %s", close_error->message);
00321         g_clear_error (&close_error);
00322         g_object_unref (input_stream);
00323     }
00324 
00325     /* If didn't exist, then add a new one */
00326     if (!matched)
00327         records = g_list_append (records, g_object_ref (auth));
00328 
00329     output_stream = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_PRIVATE, NULL, error);
00330     if (!output_stream)
00331         return FALSE;
00332 
00333     /* Workaround because g_file_replace () generates a file does not exist error even though it can replace it */
00334     g_clear_error (error);
00335 
00336     /* Write records back */
00337     result = TRUE;
00338     for (link = records; link && result; link = link->next)
00339     {
00340         XAuthority *a = link->data;
00341 
00342         result = write_uint16 (G_OUTPUT_STREAM (output_stream), a->priv->family, error) &&
00343                  write_uint16 (G_OUTPUT_STREAM (output_stream), a->priv->address_length, error) &&
00344                  write_data (G_OUTPUT_STREAM (output_stream), a->priv->address, a->priv->address_length, error) &&
00345                  write_string (G_OUTPUT_STREAM (output_stream), a->priv->number, error) &&
00346                  write_string (G_OUTPUT_STREAM (output_stream), a->priv->authorization_name, error) &&
00347                  write_uint16 (G_OUTPUT_STREAM (output_stream), a->priv->authorization_data_length, error) &&
00348                  write_data (G_OUTPUT_STREAM (output_stream), a->priv->authorization_data, a->priv->authorization_data_length, error);
00349 
00350         g_object_unref (a);
00351     }
00352     g_list_free (records);
00353 
00354     if (result)
00355         result = g_output_stream_close (G_OUTPUT_STREAM (output_stream), NULL, error);
00356     g_object_unref (output_stream);
00357 
00358     return result;
00359 }    
00360 
00361 static void
00362 xauth_init (XAuthority *auth)
00363 {
00364     auth->priv = G_TYPE_INSTANCE_GET_PRIVATE (auth, XAUTHORITY_TYPE, XAuthorityPrivate);
00365     auth->priv->number = g_strdup ("");
00366 }
00367 
00368 static void
00369 xauth_finalize (GObject *object)
00370 {
00371     XAuthority *self;
00372 
00373     self = XAUTHORITY (object);
00374 
00375     g_free (self->priv->address);
00376     g_free (self->priv->number);
00377     g_free (self->priv->authorization_name);
00378     g_free (self->priv->authorization_data);
00379 
00380     G_OBJECT_CLASS (xauth_parent_class)->finalize (object);  
00381 }
00382 
00383 static void
00384 xauth_class_init (XAuthorityClass *klass)
00385 {
00386     GObjectClass *object_class = G_OBJECT_CLASS (klass);
00387 
00388     object_class->finalize = xauth_finalize;
00389 
00390     g_type_class_add_private (klass, sizeof (XAuthorityPrivate));
00391 }