2 * Copyright (C) 2010-2011 Robert Ancell.
3 * Author: Robert Ancell <robert.ancell@canonical.com>
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
18 #include <glib/gstdio.h>
20 #include "x-authority.h"
22 struct XAuthorityPrivate
27 /* Address of the X server (format dependent on family) */
31 /* Display number of X server */
34 /* Authorization scheme */
35 gchar *authorization_name;
37 /* Authorization data */
38 guint8 *authorization_data;
39 gsize authorization_data_length;
42 G_DEFINE_TYPE (XAuthority, x_authority, G_TYPE_OBJECT);
45 x_authority_new (guint16 family, const guint8 *address, gsize address_length, const gchar *number, const gchar *name, const guint8 *data, gsize data_length)
47 XAuthority *auth = g_object_new (X_AUTHORITY_TYPE, NULL);
49 x_authority_set_family (auth, family);
50 x_authority_set_address (auth, address, address_length);
51 x_authority_set_number (auth, number);
52 x_authority_set_authorization_name (auth, name);
53 x_authority_set_authorization_data (auth, data, data_length);
59 x_authority_new_cookie (guint16 family, const guint8 *address, gsize address_length, const gchar *number)
64 for (i = 0; i < 16; i++)
65 cookie[i] = g_random_int () & 0xFF;
67 return x_authority_new (family, address, address_length, number, "MIT-MAGIC-COOKIE-1", cookie, 16);
71 x_authority_set_family (XAuthority *auth, guint16 family)
73 g_return_if_fail (auth != NULL);
74 auth->priv->family = family;
78 x_authority_get_family (XAuthority *auth)
80 g_return_val_if_fail (auth != NULL, 0);
81 return auth->priv->family;
85 x_authority_set_address (XAuthority *auth, const guint8 *address, gsize address_length)
87 g_return_if_fail (auth != NULL);
88 g_free (auth->priv->address);
89 auth->priv->address = g_malloc (address_length);
90 memcpy (auth->priv->address, address, address_length);
91 auth->priv->address_length = address_length;
95 x_authority_get_address (XAuthority *auth)
97 g_return_val_if_fail (auth != NULL, NULL);
98 return auth->priv->address;
102 x_authority_get_address_length (XAuthority *auth)
104 g_return_val_if_fail (auth != NULL, 0);
105 return auth->priv->address_length;
109 x_authority_set_number (XAuthority *auth, const gchar *number)
111 g_return_if_fail (auth != NULL);
112 g_free (auth->priv->number);
113 auth->priv->number = g_strdup (number);
117 x_authority_get_number (XAuthority *auth)
119 g_return_val_if_fail (auth != NULL, NULL);
120 return auth->priv->number;
124 x_authority_set_authorization_name (XAuthority *auth, const gchar *name)
126 g_return_if_fail (auth != NULL);
127 g_free (auth->priv->authorization_name);
128 auth->priv->authorization_name = g_strdup (name);
132 x_authority_get_authorization_name (XAuthority *auth)
134 g_return_val_if_fail (auth != NULL, NULL);
135 return auth->priv->authorization_name;
139 x_authority_set_authorization_data (XAuthority *auth, const guint8 *data, gsize data_length)
141 g_return_if_fail (auth != NULL);
142 g_free (auth->priv->authorization_data);
143 auth->priv->authorization_data = g_malloc (data_length);
144 memcpy (auth->priv->authorization_data, data, data_length);
145 auth->priv->authorization_data_length = data_length;
149 x_authority_get_authorization_data (XAuthority *auth)
151 g_return_val_if_fail (auth != NULL, NULL);
152 return auth->priv->authorization_data;
156 x_authority_copy_authorization_data (XAuthority *auth)
160 g_return_val_if_fail (auth != NULL, NULL);
162 data = g_malloc (auth->priv->authorization_data_length);
163 memcpy (data, auth->priv->authorization_data, auth->priv->authorization_data_length);
168 x_authority_get_authorization_data_length (XAuthority *auth)
170 g_return_val_if_fail (auth != NULL, 0);
171 return auth->priv->authorization_data_length;
175 read_uint16 (gchar *data, gsize data_length, gsize *offset, guint16 *value)
177 if (data_length - *offset < 2)
180 *value = data[*offset] << 8 | data[*offset + 1];
187 read_data (gchar *data, gsize data_length, gsize *offset, guint16 length, guint8 **value)
194 if (data_length - *offset < length)
197 *value = g_malloc0 (length + 1);
198 for (i = 0; i < length; i++)
199 (*value)[i] = data[*offset + i];
201 (*value)[length] = 0;
207 read_string (gchar *data, gsize data_length, gsize *offset, gchar **value)
210 if (!read_uint16 (data, data_length, offset, &length))
212 return read_data (data, data_length, offset, length, (guint8 **) value);
216 write_uint16 (int fd, guint16 value)
221 return write (fd, v, 2) == 2;
225 write_data (int fd, const guint8 *value, gsize value_length)
227 return write (fd, value, value_length) == value_length;
231 write_string (int fd, const gchar *value)
233 size_t value_length = strlen (value);
234 return write_uint16 (fd, value_length) && write_data (fd, (guint8 *) value, value_length);
238 x_authority_write (XAuthority *auth, XAuthWriteMode mode, const gchar *filename, GError **error)
241 gsize input_length = 0, input_offset = 0;
242 GList *link, *records = NULL;
244 gboolean result = TRUE;
245 gboolean matched = FALSE;
248 g_return_val_if_fail (auth != NULL, FALSE);
249 g_return_val_if_fail (filename != NULL, FALSE);
251 /* Read out existing records */
252 if (mode != XAUTH_WRITE_MODE_SET)
254 GError *read_error = NULL;
256 g_file_get_contents (filename, &input, &input_length, &read_error);
257 if (read_error && !g_error_matches (read_error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
258 g_warning ("Error reading existing Xauthority: %s", read_error->message);
259 g_clear_error (&read_error);
261 while (input_offset != input_length)
263 gboolean address_matches = FALSE;
264 guint16 address_length = 0;
265 guint16 authorization_data_length = 0;
267 a = g_object_new (X_AUTHORITY_TYPE, NULL);
269 result = read_uint16 (input, input_length, &input_offset, &a->priv->family) &&
270 read_uint16 (input, input_length, &input_offset, &address_length) &&
271 read_data (input, input_length, &input_offset, address_length, &a->priv->address) &&
272 read_string (input, input_length, &input_offset, &a->priv->number) &&
273 read_string (input, input_length, &input_offset, &a->priv->authorization_name) &&
274 read_uint16 (input, input_length, &input_offset, &authorization_data_length) &&
275 read_data (input, input_length, &input_offset, authorization_data_length, &a->priv->authorization_data);
276 a->priv->address_length = address_length;
277 a->priv->authorization_data_length = authorization_data_length;
285 if (auth->priv->address_length == a->priv->address_length)
288 for (i = 0; i < auth->priv->address_length && auth->priv->address[i] == a->priv->address[i]; i++);
289 address_matches = i == auth->priv->address_length;
292 /* If this record matches, then update or delete it */
294 auth->priv->family == a->priv->family &&
296 strcmp (auth->priv->number, a->priv->number) == 0)
299 if (mode == XAUTH_WRITE_MODE_REMOVE)
305 x_authority_set_authorization_data (a, auth->priv->authorization_data, auth->priv->authorization_data_length);
308 records = g_list_append (records, a);
312 /* If didn't exist, then add a new one */
314 records = g_list_append (records, g_object_ref (auth));
316 /* Write records back */
318 output_fd = g_open (filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
323 g_file_error_from_errno (errno),
324 "Failed to open X authority %s: %s",
332 for (link = records; link && result; link = link->next)
334 XAuthority *a = link->data;
336 result = write_uint16 (output_fd, a->priv->family) &&
337 write_uint16 (output_fd, a->priv->address_length) &&
338 write_data (output_fd, a->priv->address, a->priv->address_length) &&
339 write_string (output_fd, a->priv->number) &&
340 write_string (output_fd, a->priv->authorization_name) &&
341 write_uint16 (output_fd, a->priv->authorization_data_length) &&
342 write_data (output_fd, a->priv->authorization_data, a->priv->authorization_data_length);
346 g_list_free (records);
355 g_file_error_from_errno (errno),
356 "Failed to write X authority %s: %s",
366 x_authority_init (XAuthority *auth)
368 auth->priv = G_TYPE_INSTANCE_GET_PRIVATE (auth, X_AUTHORITY_TYPE, XAuthorityPrivate);
369 auth->priv->number = g_strdup ("");
373 x_authority_finalize (GObject *object)
377 self = X_AUTHORITY (object);
379 g_free (self->priv->address);
380 g_free (self->priv->number);
381 g_free (self->priv->authorization_name);
382 g_free (self->priv->authorization_data);
384 G_OBJECT_CLASS (x_authority_parent_class)->finalize (object);
388 x_authority_class_init (XAuthorityClass *klass)
390 GObjectClass *object_class = G_OBJECT_CLASS (klass);
392 object_class->finalize = x_authority_finalize;
394 g_type_class_add_private (klass, sizeof (XAuthorityPrivate));