]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - src/x-authority.c
Implement XDMCP ForwardQuery
[sojka/lightdm.git] / src / x-authority.c
1 /*
2  * Copyright (C) 2010-2011 Robert Ancell.
3  * Author: Robert Ancell <robert.ancell@canonical.com>
4  *
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
9  * license.
10  */
11
12 #include <string.h>
13 #include <stdio.h>
14 #include <errno.h>
15 #include <unistd.h>
16 #include <sys/stat.h>
17 #include <fcntl.h>
18 #include <glib/gstdio.h>
19
20 #include "x-authority.h"
21
22 struct XAuthorityPrivate
23 {
24     /* Protocol family */
25     guint16 family;
26
27     /* Address of the X server (format dependent on family) */
28     guint8 *address;
29     gsize address_length;
30
31     /* Display number of X server */
32     gchar *number;
33
34     /* Authorization scheme */
35     gchar *authorization_name;
36
37     /* Authorization data */
38     guint8 *authorization_data;
39     gsize authorization_data_length;
40 };
41
42 G_DEFINE_TYPE (XAuthority, x_authority, G_TYPE_OBJECT);
43
44 XAuthority *
45 x_authority_new (guint16 family, const guint8 *address, gsize address_length, const gchar *number, const gchar *name, const guint8 *data, gsize data_length)
46 {
47     XAuthority *auth = g_object_new (X_AUTHORITY_TYPE, NULL);
48
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);
54
55     return auth;
56 }
57
58 XAuthority *
59 x_authority_new_cookie (guint16 family, const guint8 *address, gsize address_length, const gchar *number)
60 {
61     guint8 cookie[16];
62     gint i;
63
64     for (i = 0; i < 16; i++)
65         cookie[i] = g_random_int () & 0xFF;
66
67     return x_authority_new (family, address, address_length, number, "MIT-MAGIC-COOKIE-1", cookie, 16);
68 }
69
70 void
71 x_authority_set_family (XAuthority *auth, guint16 family)
72 {
73     g_return_if_fail (auth != NULL);
74     auth->priv->family = family;
75 }
76
77 guint16
78 x_authority_get_family (XAuthority *auth)
79 {
80     g_return_val_if_fail (auth != NULL, 0);
81     return auth->priv->family;
82 }
83
84 void
85 x_authority_set_address (XAuthority *auth, const guint8 *address, gsize address_length)
86 {
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;
92 }
93
94 const guint8 *
95 x_authority_get_address (XAuthority *auth)
96 {
97     g_return_val_if_fail (auth != NULL, NULL);
98     return auth->priv->address;
99 }
100
101 const gsize
102 x_authority_get_address_length (XAuthority *auth)
103 {
104     g_return_val_if_fail (auth != NULL, 0);
105     return auth->priv->address_length;
106 }
107
108 void
109 x_authority_set_number (XAuthority *auth, const gchar *number)
110 {
111     g_return_if_fail (auth != NULL);
112     g_free (auth->priv->number);
113     auth->priv->number = g_strdup (number);
114 }
115
116 const gchar *
117 x_authority_get_number (XAuthority *auth)
118 {
119     g_return_val_if_fail (auth != NULL, NULL);
120     return auth->priv->number;
121 }
122
123 void
124 x_authority_set_authorization_name (XAuthority *auth, const gchar *name)
125 {
126     g_return_if_fail (auth != NULL);
127     g_free (auth->priv->authorization_name);
128     auth->priv->authorization_name = g_strdup (name);
129 }
130
131 const gchar *
132 x_authority_get_authorization_name (XAuthority *auth)
133 {
134     g_return_val_if_fail (auth != NULL, NULL);
135     return auth->priv->authorization_name;
136 }
137
138 void
139 x_authority_set_authorization_data (XAuthority *auth, const guint8 *data, gsize data_length)
140 {
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;
146 }
147
148 const guint8 *
149 x_authority_get_authorization_data (XAuthority *auth)
150 {
151     g_return_val_if_fail (auth != NULL, NULL);
152     return auth->priv->authorization_data;
153 }
154
155 guint8 *
156 x_authority_copy_authorization_data (XAuthority *auth)
157 {
158     guint8 *data;
159
160     g_return_val_if_fail (auth != NULL, NULL);
161
162     data = g_malloc (auth->priv->authorization_data_length);
163     memcpy (data, auth->priv->authorization_data, auth->priv->authorization_data_length);
164     return data;
165 }
166
167 gsize
168 x_authority_get_authorization_data_length (XAuthority *auth)
169 {
170     g_return_val_if_fail (auth != NULL, 0);
171     return auth->priv->authorization_data_length;
172 }
173
174 static gboolean
175 read_uint16 (gchar *data, gsize data_length, gsize *offset, guint16 *value)
176 {
177     if (data_length - *offset < 2)
178         return FALSE;
179
180     *value = data[*offset] << 8 | data[*offset + 1];
181     *offset += 2;
182
183     return TRUE;
184 }
185
186 static gboolean
187 read_data (gchar *data, gsize data_length, gsize *offset, guint16 length, guint8 **value)
188 {
189     int i;
190
191     g_free (*value);
192     *value = NULL;
193
194     if (data_length - *offset < length)
195         return FALSE;
196
197     *value = g_malloc0 (length + 1);
198     for (i = 0; i < length; i++)
199         (*value)[i] = data[*offset + i];
200     *offset += length;
201     (*value)[length] = 0;
202
203     return TRUE;
204 }
205
206 static gboolean
207 read_string (gchar *data, gsize data_length, gsize *offset, gchar **value)
208 {
209     guint16 length;
210     if (!read_uint16 (data, data_length, offset, &length))
211         return FALSE;
212     return read_data (data, data_length, offset, length, (guint8 **) value);
213 }
214
215 static gboolean
216 write_uint16 (int fd, guint16 value)
217 {
218     guint8 v[2];
219     v[0] = value >> 8;
220     v[1] = value & 0xFF;
221     return write (fd, v, 2) == 2;
222 }
223
224 static gboolean
225 write_data (int fd, const guint8 *value, gsize value_length)
226 {
227     return write (fd, value, value_length) == value_length;
228 }
229
230 static gboolean
231 write_string (int fd, const gchar *value)
232 {
233     size_t value_length = strlen (value);
234     return write_uint16 (fd, value_length) && write_data (fd, (guint8 *) value, value_length);
235 }
236
237 gboolean
238 x_authority_write (XAuthority *auth, XAuthWriteMode mode, const gchar *filename, GError **error)
239 {
240     gchar *input = NULL;
241     gsize input_length = 0, input_offset = 0;
242     GList *link, *records = NULL;
243     XAuthority *a;
244     gboolean result = TRUE;
245     gboolean matched = FALSE;
246     int output_fd;
247
248     g_return_val_if_fail (auth != NULL, FALSE);
249     g_return_val_if_fail (filename != NULL, FALSE);
250
251     /* Read out existing records */
252     if (mode != XAUTH_WRITE_MODE_SET)
253     {
254         GError *read_error = NULL;
255
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);
260     }
261     while (input_offset != input_length)
262     {
263         gboolean address_matches = FALSE;
264         guint16 address_length = 0;
265         guint16 authorization_data_length = 0;
266
267         a = g_object_new (X_AUTHORITY_TYPE, NULL);
268
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;
278
279         if (!result)
280         {
281             g_object_unref (a);
282             break;
283         }
284
285         if (auth->priv->address_length == a->priv->address_length)
286         {
287             guint16 i;
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;
290         }
291
292         /* If this record matches, then update or delete it */
293         if (!matched &&
294             auth->priv->family == a->priv->family &&
295             address_matches &&
296             strcmp (auth->priv->number, a->priv->number) == 0)
297         {
298             matched = TRUE;
299             if (mode == XAUTH_WRITE_MODE_REMOVE)
300             {
301                 g_object_unref (a);
302                 continue;
303             }
304             else
305                 x_authority_set_authorization_data (a, auth->priv->authorization_data, auth->priv->authorization_data_length);
306         }
307
308         records = g_list_append (records, a);
309     }
310     g_free (input);
311
312     /* If didn't exist, then add a new one */
313     if (!matched)
314         records = g_list_append (records, g_object_ref (auth));
315
316     /* Write records back */
317     errno = 0;
318     output_fd = g_open (filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
319     if (output_fd < 0)
320     {
321         g_set_error (error,
322                      G_FILE_ERROR,
323                      g_file_error_from_errno (errno),
324                      "Failed to open X authority %s: %s",
325                      filename,
326                      g_strerror (errno));
327         return FALSE;
328     }
329
330     errno = 0;
331     result = TRUE;
332     for (link = records; link && result; link = link->next)
333     {
334         XAuthority *a = link->data;
335
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);
343
344         g_object_unref (a);
345     }
346     g_list_free (records);
347
348     fsync (output_fd);
349     close (output_fd);
350
351     if (!result)
352     {
353         g_set_error (error,
354                      G_FILE_ERROR,
355                      g_file_error_from_errno (errno),
356                      "Failed to write X authority %s: %s",
357                      filename,
358                      g_strerror (errno));
359         return FALSE;
360     }
361
362     return TRUE;
363 }
364
365 static void
366 x_authority_init (XAuthority *auth)
367 {
368     auth->priv = G_TYPE_INSTANCE_GET_PRIVATE (auth, X_AUTHORITY_TYPE, XAuthorityPrivate);
369     auth->priv->number = g_strdup ("");
370 }
371
372 static void
373 x_authority_finalize (GObject *object)
374 {
375     XAuthority *self = X_AUTHORITY (object);
376
377     g_free (self->priv->address);
378     g_free (self->priv->number);
379     g_free (self->priv->authorization_name);
380     g_free (self->priv->authorization_data);
381
382     G_OBJECT_CLASS (x_authority_parent_class)->finalize (object);
383 }
384
385 static void
386 x_authority_class_init (XAuthorityClass *klass)
387 {
388     GObjectClass *object_class = G_OBJECT_CLASS (klass);
389
390     object_class->finalize = x_authority_finalize;
391
392     g_type_class_add_private (klass, sizeof (XAuthorityPrivate));
393 }