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_new_local_cookie (const gchar *number)
75 gethostname (hostname, 1024);
76 return x_authority_new_cookie (XAUTH_FAMILY_LOCAL, (guint8 *) hostname, strlen (hostname), number);
80 x_authority_set_family (XAuthority *auth, guint16 family)
82 g_return_if_fail (auth != NULL);
83 auth->priv->family = family;
87 x_authority_get_family (XAuthority *auth)
89 g_return_val_if_fail (auth != NULL, 0);
90 return auth->priv->family;
94 x_authority_set_address (XAuthority *auth, const guint8 *address, gsize address_length)
96 g_return_if_fail (auth != NULL);
97 g_free (auth->priv->address);
98 auth->priv->address = g_malloc (address_length);
99 memcpy (auth->priv->address, address, address_length);
100 auth->priv->address_length = address_length;
104 x_authority_get_address (XAuthority *auth)
106 g_return_val_if_fail (auth != NULL, NULL);
107 return auth->priv->address;
111 x_authority_get_address_length (XAuthority *auth)
113 g_return_val_if_fail (auth != NULL, 0);
114 return auth->priv->address_length;
118 x_authority_set_number (XAuthority *auth, const gchar *number)
120 g_return_if_fail (auth != NULL);
121 g_free (auth->priv->number);
122 auth->priv->number = g_strdup (number);
126 x_authority_get_number (XAuthority *auth)
128 g_return_val_if_fail (auth != NULL, NULL);
129 return auth->priv->number;
133 x_authority_set_authorization_name (XAuthority *auth, const gchar *name)
135 g_return_if_fail (auth != NULL);
136 g_free (auth->priv->authorization_name);
137 auth->priv->authorization_name = g_strdup (name);
141 x_authority_get_authorization_name (XAuthority *auth)
143 g_return_val_if_fail (auth != NULL, NULL);
144 return auth->priv->authorization_name;
148 x_authority_set_authorization_data (XAuthority *auth, const guint8 *data, gsize data_length)
150 g_return_if_fail (auth != NULL);
151 g_free (auth->priv->authorization_data);
152 auth->priv->authorization_data = g_malloc (data_length);
153 memcpy (auth->priv->authorization_data, data, data_length);
154 auth->priv->authorization_data_length = data_length;
158 x_authority_get_authorization_data (XAuthority *auth)
160 g_return_val_if_fail (auth != NULL, NULL);
161 return auth->priv->authorization_data;
165 x_authority_copy_authorization_data (XAuthority *auth)
169 g_return_val_if_fail (auth != NULL, NULL);
171 data = g_malloc (auth->priv->authorization_data_length);
172 memcpy (data, auth->priv->authorization_data, auth->priv->authorization_data_length);
177 x_authority_get_authorization_data_length (XAuthority *auth)
179 g_return_val_if_fail (auth != NULL, 0);
180 return auth->priv->authorization_data_length;
184 read_uint16 (gchar *data, gsize data_length, gsize *offset, guint16 *value)
186 if (data_length - *offset < 2)
189 *value = data[*offset] << 8 | data[*offset + 1];
196 read_data (gchar *data, gsize data_length, gsize *offset, guint16 length, guint8 **value)
203 if (data_length - *offset < length)
206 *value = g_malloc0 (length + 1);
207 for (i = 0; i < length; i++)
208 (*value)[i] = data[*offset + i];
210 (*value)[length] = 0;
216 read_string (gchar *data, gsize data_length, gsize *offset, gchar **value)
219 if (!read_uint16 (data, data_length, offset, &length))
221 return read_data (data, data_length, offset, length, (guint8 **) value);
225 write_uint16 (int fd, guint16 value)
230 return write (fd, v, 2) == 2;
234 write_data (int fd, const guint8 *value, gsize value_length)
236 return write (fd, value, value_length) == value_length;
240 write_string (int fd, const gchar *value)
242 size_t value_length = strlen (value);
243 return write_uint16 (fd, value_length) && write_data (fd, (guint8 *) value, value_length);
247 x_authority_write (XAuthority *auth, XAuthWriteMode mode, const gchar *filename, GError **error)
250 gsize input_length = 0, input_offset = 0;
251 GList *link, *records = NULL;
253 gboolean result = TRUE;
254 gboolean matched = FALSE;
257 g_return_val_if_fail (auth != NULL, FALSE);
258 g_return_val_if_fail (filename != NULL, FALSE);
260 /* Read out existing records */
261 if (mode != XAUTH_WRITE_MODE_SET)
263 GError *read_error = NULL;
265 g_file_get_contents (filename, &input, &input_length, &read_error);
266 if (read_error && !g_error_matches (read_error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
267 g_warning ("Error reading existing Xauthority: %s", read_error->message);
268 g_clear_error (&read_error);
270 while (input_offset != input_length)
272 gboolean address_matches = FALSE;
273 guint16 address_length = 0;
274 guint16 authorization_data_length = 0;
276 a = g_object_new (X_AUTHORITY_TYPE, NULL);
278 result = read_uint16 (input, input_length, &input_offset, &a->priv->family) &&
279 read_uint16 (input, input_length, &input_offset, &address_length) &&
280 read_data (input, input_length, &input_offset, address_length, &a->priv->address) &&
281 read_string (input, input_length, &input_offset, &a->priv->number) &&
282 read_string (input, input_length, &input_offset, &a->priv->authorization_name) &&
283 read_uint16 (input, input_length, &input_offset, &authorization_data_length) &&
284 read_data (input, input_length, &input_offset, authorization_data_length, &a->priv->authorization_data);
285 a->priv->address_length = address_length;
286 a->priv->authorization_data_length = authorization_data_length;
294 if (auth->priv->address_length == a->priv->address_length)
297 for (i = 0; i < auth->priv->address_length && auth->priv->address[i] == a->priv->address[i]; i++);
298 address_matches = i == auth->priv->address_length;
301 /* If this record matches, then update or delete it */
303 auth->priv->family == a->priv->family &&
305 strcmp (auth->priv->number, a->priv->number) == 0)
308 if (mode == XAUTH_WRITE_MODE_REMOVE)
314 x_authority_set_authorization_data (a, auth->priv->authorization_data, auth->priv->authorization_data_length);
317 records = g_list_append (records, a);
321 /* If didn't exist, then add a new one */
323 records = g_list_append (records, g_object_ref (auth));
325 /* Write records back */
327 output_fd = g_open (filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
332 g_file_error_from_errno (errno),
333 "Failed to open X authority %s: %s",
341 for (link = records; link && result; link = link->next)
343 XAuthority *a = link->data;
345 result = write_uint16 (output_fd, a->priv->family) &&
346 write_uint16 (output_fd, a->priv->address_length) &&
347 write_data (output_fd, a->priv->address, a->priv->address_length) &&
348 write_string (output_fd, a->priv->number) &&
349 write_string (output_fd, a->priv->authorization_name) &&
350 write_uint16 (output_fd, a->priv->authorization_data_length) &&
351 write_data (output_fd, a->priv->authorization_data, a->priv->authorization_data_length);
355 g_list_free (records);
364 g_file_error_from_errno (errno),
365 "Failed to write X authority %s: %s",
375 x_authority_init (XAuthority *auth)
377 auth->priv = G_TYPE_INSTANCE_GET_PRIVATE (auth, X_AUTHORITY_TYPE, XAuthorityPrivate);
378 auth->priv->number = g_strdup ("");
382 x_authority_finalize (GObject *object)
384 XAuthority *self = X_AUTHORITY (object);
386 g_free (self->priv->address);
387 g_free (self->priv->number);
388 g_free (self->priv->authorization_name);
389 g_free (self->priv->authorization_data);
391 G_OBJECT_CLASS (x_authority_parent_class)->finalize (object);
395 x_authority_class_init (XAuthorityClass *klass)
397 GObjectClass *object_class = G_OBJECT_CLASS (klass);
399 object_class->finalize = x_authority_finalize;
401 g_type_class_add_private (klass, sizeof (XAuthorityPrivate));