GMemoryInputStream: fix skip_async()
[platform/upstream/glib.git] / gio / gdbusauthmechanismsha1.c
1 /* GDBus - GLib D-Bus Library
2  *
3  * Copyright (C) 2008-2010 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: David Zeuthen <davidz@redhat.com>
21  */
22
23 #include "config.h"
24
25 #include <string.h>
26 #include <fcntl.h>
27 #include <errno.h>
28 #include <sys/types.h>
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32 #ifdef _WIN32
33 #include <io.h>
34 #endif
35
36 #include <glib/gstdio.h>
37
38 #include "gdbusauthmechanismsha1.h"
39 #include "gcredentials.h"
40 #include "gdbuserror.h"
41 #include "gioenumtypes.h"
42 #include "gioerror.h"
43 #include "gdbusprivate.h"
44
45 #include "glibintl.h"
46
47 struct _GDBusAuthMechanismSha1Private
48 {
49   gboolean is_client;
50   gboolean is_server;
51   GDBusAuthMechanismState state;
52
53   /* used on the client side */
54   gchar *to_send;
55
56   /* used on the server side */
57   gchar *cookie;
58   gchar *server_challenge;
59 };
60
61 static gint                     mechanism_get_priority              (void);
62 static const gchar             *mechanism_get_name                  (void);
63
64 static gboolean                 mechanism_is_supported              (GDBusAuthMechanism   *mechanism);
65 static gchar                   *mechanism_encode_data               (GDBusAuthMechanism   *mechanism,
66                                                                      const gchar          *data,
67                                                                      gsize                 data_len,
68                                                                      gsize                *out_data_len);
69 static gchar                   *mechanism_decode_data               (GDBusAuthMechanism   *mechanism,
70                                                                      const gchar          *data,
71                                                                      gsize                 data_len,
72                                                                      gsize                *out_data_len);
73 static GDBusAuthMechanismState  mechanism_server_get_state          (GDBusAuthMechanism   *mechanism);
74 static void                     mechanism_server_initiate           (GDBusAuthMechanism   *mechanism,
75                                                                      const gchar          *initial_response,
76                                                                      gsize                 initial_response_len);
77 static void                     mechanism_server_data_receive       (GDBusAuthMechanism   *mechanism,
78                                                                      const gchar          *data,
79                                                                      gsize                 data_len);
80 static gchar                   *mechanism_server_data_send          (GDBusAuthMechanism   *mechanism,
81                                                                      gsize                *out_data_len);
82 static gchar                   *mechanism_server_get_reject_reason  (GDBusAuthMechanism   *mechanism);
83 static void                     mechanism_server_shutdown           (GDBusAuthMechanism   *mechanism);
84 static GDBusAuthMechanismState  mechanism_client_get_state          (GDBusAuthMechanism   *mechanism);
85 static gchar                   *mechanism_client_initiate           (GDBusAuthMechanism   *mechanism,
86                                                                      gsize                *out_initial_response_len);
87 static void                     mechanism_client_data_receive       (GDBusAuthMechanism   *mechanism,
88                                                                      const gchar          *data,
89                                                                      gsize                 data_len);
90 static gchar                   *mechanism_client_data_send          (GDBusAuthMechanism   *mechanism,
91                                                                      gsize                *out_data_len);
92 static void                     mechanism_client_shutdown           (GDBusAuthMechanism   *mechanism);
93
94 /* ---------------------------------------------------------------------------------------------------- */
95
96 G_DEFINE_TYPE (GDBusAuthMechanismSha1, _g_dbus_auth_mechanism_sha1, G_TYPE_DBUS_AUTH_MECHANISM);
97
98 /* ---------------------------------------------------------------------------------------------------- */
99
100 static void
101 _g_dbus_auth_mechanism_sha1_finalize (GObject *object)
102 {
103   GDBusAuthMechanismSha1 *mechanism = G_DBUS_AUTH_MECHANISM_SHA1 (object);
104
105   g_free (mechanism->priv->to_send);
106
107   g_free (mechanism->priv->cookie);
108   g_free (mechanism->priv->server_challenge);
109
110   if (G_OBJECT_CLASS (_g_dbus_auth_mechanism_sha1_parent_class)->finalize != NULL)
111     G_OBJECT_CLASS (_g_dbus_auth_mechanism_sha1_parent_class)->finalize (object);
112 }
113
114 static void
115 _g_dbus_auth_mechanism_sha1_class_init (GDBusAuthMechanismSha1Class *klass)
116 {
117   GObjectClass *gobject_class;
118   GDBusAuthMechanismClass *mechanism_class;
119
120   g_type_class_add_private (klass, sizeof (GDBusAuthMechanismSha1Private));
121
122   gobject_class = G_OBJECT_CLASS (klass);
123   gobject_class->finalize = _g_dbus_auth_mechanism_sha1_finalize;
124
125   mechanism_class = G_DBUS_AUTH_MECHANISM_CLASS (klass);
126   mechanism_class->get_priority              = mechanism_get_priority;
127   mechanism_class->get_name                  = mechanism_get_name;
128   mechanism_class->is_supported              = mechanism_is_supported;
129   mechanism_class->encode_data               = mechanism_encode_data;
130   mechanism_class->decode_data               = mechanism_decode_data;
131   mechanism_class->server_get_state          = mechanism_server_get_state;
132   mechanism_class->server_initiate           = mechanism_server_initiate;
133   mechanism_class->server_data_receive       = mechanism_server_data_receive;
134   mechanism_class->server_data_send          = mechanism_server_data_send;
135   mechanism_class->server_get_reject_reason  = mechanism_server_get_reject_reason;
136   mechanism_class->server_shutdown           = mechanism_server_shutdown;
137   mechanism_class->client_get_state          = mechanism_client_get_state;
138   mechanism_class->client_initiate           = mechanism_client_initiate;
139   mechanism_class->client_data_receive       = mechanism_client_data_receive;
140   mechanism_class->client_data_send          = mechanism_client_data_send;
141   mechanism_class->client_shutdown           = mechanism_client_shutdown;
142 }
143
144 static void
145 _g_dbus_auth_mechanism_sha1_init (GDBusAuthMechanismSha1 *mechanism)
146 {
147   mechanism->priv = G_TYPE_INSTANCE_GET_PRIVATE (mechanism,
148                                                  G_TYPE_DBUS_AUTH_MECHANISM_SHA1,
149                                                  GDBusAuthMechanismSha1Private);
150 }
151
152 /* ---------------------------------------------------------------------------------------------------- */
153
154 static gint
155 mechanism_get_priority (void)
156 {
157   return 0;
158 }
159
160 static const gchar *
161 mechanism_get_name (void)
162 {
163   return "DBUS_COOKIE_SHA1";
164 }
165
166 static gboolean
167 mechanism_is_supported (GDBusAuthMechanism *mechanism)
168 {
169   g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), FALSE);
170   return TRUE;
171 }
172
173 static gchar *
174 mechanism_encode_data (GDBusAuthMechanism   *mechanism,
175                        const gchar          *data,
176                        gsize                 data_len,
177                        gsize                *out_data_len)
178 {
179   return NULL;
180 }
181
182
183 static gchar *
184 mechanism_decode_data (GDBusAuthMechanism   *mechanism,
185                        const gchar          *data,
186                        gsize                 data_len,
187                        gsize                *out_data_len)
188 {
189   return NULL;
190 }
191
192 /* ---------------------------------------------------------------------------------------------------- */
193
194 static gint
195 random_ascii (void)
196 {
197   gint ret;
198   ret = g_random_int_range (0, 60);
199   if (ret < 25)
200     ret += 'A';
201   else if (ret < 50)
202     ret += 'a' - 25;
203   else
204     ret += '0' - 50;
205   return ret;
206 }
207
208 static gchar *
209 random_ascii_string (guint len)
210 {
211   GString *challenge;
212   guint n;
213
214   challenge = g_string_new (NULL);
215   for (n = 0; n < len; n++)
216     g_string_append_c (challenge, random_ascii ());
217   return g_string_free (challenge, FALSE);
218 }
219
220 static gchar *
221 random_blob (guint len)
222 {
223   GString *challenge;
224   guint n;
225
226   challenge = g_string_new (NULL);
227   for (n = 0; n < len; n++)
228     g_string_append_c (challenge, g_random_int_range (0, 256));
229   return g_string_free (challenge, FALSE);
230 }
231
232 /* ---------------------------------------------------------------------------------------------------- */
233
234 /* ensure keyring dir exists and permissions are correct */
235 static gchar *
236 ensure_keyring_directory (GError **error)
237 {
238   gchar *path;
239   const gchar *e;
240
241   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
242
243   e = g_getenv ("G_DBUS_COOKIE_SHA1_KEYRING_DIR");
244   if (e != NULL)
245     {
246       path = g_strdup (e);
247     }
248   else
249     {
250       path = g_build_filename (g_get_home_dir (),
251                                ".dbus-keyrings",
252                                NULL);
253     }
254
255   if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
256     {
257       if (g_getenv ("G_DBUS_COOKIE_SHA1_KEYRING_DIR_IGNORE_PERMISSION") == NULL)
258         {
259 #ifdef G_OS_UNIX
260           struct stat statbuf;
261           if (stat (path, &statbuf) != 0)
262             {
263               g_set_error (error,
264                            G_IO_ERROR,
265                            g_io_error_from_errno (errno),
266                            _("Error when getting information for directory `%s': %s"),
267                            path,
268                            strerror (errno));
269               g_free (path);
270               path = NULL;
271               goto out;
272             }
273           if ((statbuf.st_mode  & 0777) != 0700)
274             {
275               g_set_error (error,
276                            G_IO_ERROR,
277                            G_IO_ERROR_FAILED,
278                            _("Permissions on directory `%s' are malformed. Expected mode 0700, got 0%o"),
279                            path,
280                            statbuf.st_mode & 0777);
281               g_free (path);
282               path = NULL;
283               goto out;
284             }
285 #else
286 #ifdef __GNUC__
287 #warning Please implement permission checking on this non-UNIX platform
288 #endif
289 #endif
290         }
291         goto out;
292     }
293
294   if (g_mkdir (path, 0700) != 0)
295     {
296       g_set_error (error,
297                    G_IO_ERROR,
298                    g_io_error_from_errno (errno),
299                    _("Error creating directory `%s': %s"),
300                    path,
301                    strerror (errno));
302       g_free (path);
303       path = NULL;
304       goto out;
305     }
306
307 out:
308   return path;
309 }
310
311 /* ---------------------------------------------------------------------------------------------------- */
312
313 static void
314 append_nibble (GString *s, gint val)
315 {
316   g_string_append_c (s, val >= 10 ? ('a' + val - 10) : ('0' + val));
317 }
318
319 static gchar *
320 hexencode (const gchar *str,
321            gssize       len)
322 {
323   guint n;
324   GString *s;
325
326   if (len == -1)
327     len = strlen (str);
328
329   s = g_string_new (NULL);
330   for (n = 0; n < len; n++)
331     {
332       gint val;
333       gint upper_nibble;
334       gint lower_nibble;
335
336       val = ((const guchar *) str)[n];
337       upper_nibble = val >> 4;
338       lower_nibble = val & 0x0f;
339
340       append_nibble (s, upper_nibble);
341       append_nibble (s, lower_nibble);
342     }
343
344   return g_string_free (s, FALSE);
345 }
346
347 /* ---------------------------------------------------------------------------------------------------- */
348
349 /* looks up an entry in the keyring */
350 static gchar *
351 keyring_lookup_entry (const gchar  *cookie_context,
352                       gint          cookie_id,
353                       GError      **error)
354 {
355   gchar *ret;
356   gchar *keyring_dir;
357   gchar *contents;
358   gchar *path;
359   guint n;
360   gchar **lines;
361
362   g_return_val_if_fail (cookie_context != NULL, NULL);
363   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
364
365   ret = NULL;
366   path = NULL;
367   contents = NULL;
368   lines = NULL;
369
370   keyring_dir = ensure_keyring_directory (error);
371   if (keyring_dir == NULL)
372     goto out;
373
374   path = g_build_filename (keyring_dir, cookie_context, NULL);
375
376   if (!g_file_get_contents (path,
377                             &contents,
378                             NULL,
379                             error))
380     {
381       g_prefix_error (error,
382                       _("Error opening keyring `%s' for reading: "),
383                       path);
384       goto out;
385     }
386   g_assert (contents != NULL);
387
388   lines = g_strsplit (contents, "\n", 0);
389   for (n = 0; lines[n] != NULL; n++)
390     {
391       const gchar *line = lines[n];
392       gchar **tokens;
393       gchar *endp;
394       gint line_id;
395       guint64 line_when;
396
397       if (line[0] == '\0')
398         continue;
399
400       tokens = g_strsplit (line, " ", 0);
401       if (g_strv_length (tokens) != 3)
402         {
403           g_set_error (error,
404                        G_IO_ERROR,
405                        G_IO_ERROR_FAILED,
406                        _("Line %d of the keyring at `%s' with content `%s' is malformed"),
407                        n + 1,
408                        path,
409                        line);
410           g_strfreev (tokens);
411           goto out;
412         }
413
414       line_id = g_ascii_strtoll (tokens[0], &endp, 10);
415       if (*endp != '\0')
416         {
417           g_set_error (error,
418                        G_IO_ERROR,
419                        G_IO_ERROR_FAILED,
420                        _("First token of line %d of the keyring at `%s' with content `%s' is malformed"),
421                        n + 1,
422                        path,
423                        line);
424           g_strfreev (tokens);
425           goto out;
426         }
427
428       line_when = g_ascii_strtoll (tokens[1], &endp, 10);
429       line_when = line_when; /* To avoid -Wunused-but-set-variable */
430       if (*endp != '\0')
431         {
432           g_set_error (error,
433                        G_IO_ERROR,
434                        G_IO_ERROR_FAILED,
435                        _("Second token of line %d of the keyring at `%s' with content `%s' is malformed"),
436                        n + 1,
437                        path,
438                        line);
439           g_strfreev (tokens);
440           goto out;
441         }
442
443       if (line_id == cookie_id)
444         {
445           /* YAY, success */
446           ret = tokens[2]; /* steal pointer */
447           tokens[2] = NULL;
448           g_strfreev (tokens);
449           goto out;
450         }
451
452       g_strfreev (tokens);
453     }
454
455   /* BOOH, didn't find the cookie */
456   g_set_error (error,
457                G_IO_ERROR,
458                G_IO_ERROR_FAILED,
459                _("Didn't find cookie with id %d in the keyring at `%s'"),
460                cookie_id,
461                path);
462
463  out:
464   g_free (keyring_dir);
465   g_free (path);
466   g_free (contents);
467   g_strfreev (lines);
468   return ret;
469 }
470
471 /* function for logging important events that the system administrator should take notice of */
472 static void
473 _log (const gchar *message,
474       ...)
475 {
476   gchar *s;
477   va_list var_args;
478
479   va_start (var_args, message);
480   s = g_strdup_vprintf (message, var_args);
481   va_end (var_args);
482
483   /* TODO: might want to send this to syslog instead */
484   g_printerr ("GDBus-DBUS_COOKIE_SHA1: %s\n", s);
485   g_free (s);
486 }
487
488 static gint
489 keyring_acquire_lock (const gchar  *path,
490                       GError      **error)
491 {
492   gchar *lock;
493   gint ret;
494   guint num_tries;
495   guint num_create_tries;
496
497   g_return_val_if_fail (path != NULL, FALSE);
498   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
499
500   ret = -1;
501   lock = g_strdup_printf ("%s.lock", path);
502
503   /* This is what the D-Bus spec says
504    *
505    *  Create a lockfile name by appending ".lock" to the name of the
506    *  cookie file. The server should attempt to create this file using
507    *  O_CREAT | O_EXCL. If file creation fails, the lock
508    *  fails. Servers should retry for a reasonable period of time,
509    *  then they may choose to delete an existing lock to keep users
510    *  from having to manually delete a stale lock. [1]
511    *
512    *  [1] : Lockfiles are used instead of real file locking fcntl() because
513    *         real locking implementations are still flaky on network filesystems
514    */
515
516   num_create_tries = 0;
517 #ifdef EEXISTS
518  again:
519 #endif
520   num_tries = 0;
521   while (g_file_test (lock, G_FILE_TEST_EXISTS))
522     {
523       /* sleep 10ms, then try again */
524       g_usleep (1000*10);
525       num_tries++;
526       if (num_tries == 50)
527         {
528           /* ok, we slept 50*10ms = 0.5 seconds. Conclude that the lock file must be
529            * stale (nuke the it from orbit)
530            */
531           if (g_unlink (lock) != 0)
532             {
533               g_set_error (error,
534                            G_IO_ERROR,
535                            g_io_error_from_errno (errno),
536                            _("Error deleting stale lock file `%s': %s"),
537                            lock,
538                            strerror (errno));
539               goto out;
540             }
541           _log ("Deleted stale lock file `%s'", lock);
542           break;
543         }
544     }
545
546   ret = g_open (lock, O_CREAT |
547 #ifdef O_EXCL
548                 O_EXCL,
549 #else
550                 0,
551 #endif
552                 0700);
553   if (ret == -1)
554     {
555 #ifdef EEXISTS
556       /* EEXIST: pathname already exists and O_CREAT and O_EXCL were used. */
557       if (errno == EEXISTS)
558         {
559           num_create_tries++;
560           if (num_create_tries < 5)
561             goto again;
562         }
563 #endif
564       num_create_tries = num_create_tries; /* To avoid -Wunused-but-set-variable */
565       g_set_error (error,
566                    G_IO_ERROR,
567                    g_io_error_from_errno (errno),
568                    _("Error creating lock file `%s': %s"),
569                    lock,
570                    strerror (errno));
571       goto out;
572     }
573
574  out:
575   g_free (lock);
576   return ret;
577 }
578
579 static gboolean
580 keyring_release_lock (const gchar  *path,
581                       gint          lock_fd,
582                       GError      **error)
583 {
584   gchar *lock;
585   gboolean ret;
586
587   g_return_val_if_fail (path != NULL, FALSE);
588   g_return_val_if_fail (lock_fd != -1, FALSE);
589   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
590
591   ret = FALSE;
592   lock = g_strdup_printf ("%s.lock", path);
593   if (close (lock_fd) != 0)
594     {
595       g_set_error (error,
596                    G_IO_ERROR,
597                    g_io_error_from_errno (errno),
598                    _("Error closing (unlinked) lock file `%s': %s"),
599                    lock,
600                    strerror (errno));
601       goto out;
602     }
603   if (g_unlink (lock) != 0)
604     {
605       g_set_error (error,
606                    G_IO_ERROR,
607                    g_io_error_from_errno (errno),
608                    _("Error unlinking lock file `%s': %s"),
609                    lock,
610                    strerror (errno));
611       goto out;
612     }
613
614   ret = TRUE;
615
616  out:
617   g_free (lock);
618   return ret;
619 }
620
621
622 /* adds an entry to the keyring, taking care of locking and deleting stale/future entries */
623 static gboolean
624 keyring_generate_entry (const gchar  *cookie_context,
625                         gint         *out_id,
626                         gchar       **out_cookie,
627                         GError      **error)
628 {
629   gboolean ret;
630   gchar *keyring_dir;
631   gchar *path;
632   gchar *contents;
633   GError *local_error;
634   gchar **lines;
635   gint max_line_id;
636   GString *new_contents;
637   guint64 now;
638   gboolean have_id;
639   gint use_id;
640   gchar *use_cookie;
641   gboolean changed_file;
642   gint lock_fd;
643
644   g_return_val_if_fail (cookie_context != NULL, FALSE);
645   g_return_val_if_fail (out_id != NULL, FALSE);
646   g_return_val_if_fail (out_cookie != NULL, FALSE);
647   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
648
649   ret = FALSE;
650   path = NULL;
651   contents = NULL;
652   lines = NULL;
653   new_contents = NULL;
654   have_id = FALSE;
655   use_id = 0;
656   use_cookie = NULL;
657   lock_fd = -1;
658
659   keyring_dir = ensure_keyring_directory (error);
660   if (keyring_dir == NULL)
661     goto out;
662
663   path = g_build_filename (keyring_dir, cookie_context, NULL);
664
665   lock_fd = keyring_acquire_lock (path, error);
666   if (lock_fd == -1)
667     goto out;
668
669   local_error = NULL;
670   contents = NULL;
671   if (!g_file_get_contents (path,
672                             &contents,
673                             NULL,
674                             &local_error))
675     {
676       if (local_error->domain == G_FILE_ERROR && local_error->code == G_FILE_ERROR_NOENT)
677         {
678           /* file doesn't have to exist */
679           g_error_free (local_error);
680         }
681       else
682         {
683           g_propagate_prefixed_error (error,
684                                       local_error,
685                                       _("Error opening keyring `%s' for writing: "),
686                                       path);
687           goto out;
688         }
689     }
690
691   new_contents = g_string_new (NULL);
692   now = time (NULL);
693   changed_file = FALSE;
694
695   max_line_id = 0;
696   if (contents != NULL)
697     {
698       guint n;
699       lines = g_strsplit (contents, "\n", 0);
700       for (n = 0; lines[n] != NULL; n++)
701         {
702           const gchar *line = lines[n];
703           gchar **tokens;
704           gchar *endp;
705           gint line_id;
706           guint64 line_when;
707           gboolean keep_entry;
708
709           if (line[0] == '\0')
710             continue;
711
712           tokens = g_strsplit (line, " ", 0);
713           if (g_strv_length (tokens) != 3)
714             {
715               g_set_error (error,
716                            G_IO_ERROR,
717                            G_IO_ERROR_FAILED,
718                            _("Line %d of the keyring at `%s' with content `%s' is malformed"),
719                            n + 1,
720                            path,
721                            line);
722               g_strfreev (tokens);
723               goto out;
724             }
725
726           line_id = g_ascii_strtoll (tokens[0], &endp, 10);
727           if (*endp != '\0')
728             {
729               g_set_error (error,
730                            G_IO_ERROR,
731                            G_IO_ERROR_FAILED,
732                            _("First token of line %d of the keyring at `%s' with content `%s' is malformed"),
733                            n + 1,
734                            path,
735                            line);
736               g_strfreev (tokens);
737               goto out;
738             }
739
740           line_when = g_ascii_strtoll (tokens[1], &endp, 10);
741           if (*endp != '\0')
742             {
743               g_set_error (error,
744                            G_IO_ERROR,
745                            G_IO_ERROR_FAILED,
746                            _("Second token of line %d of the keyring at `%s' with content `%s' is malformed"),
747                            n + 1,
748                            path,
749                            line);
750               g_strfreev (tokens);
751               goto out;
752             }
753           line_when = line_when; /* To avoid -Wunused-but-set-variable */
754
755
756           /* D-Bus spec says:
757            *
758            *  Once the lockfile has been created, the server loads the
759            *  cookie file. It should then delete any cookies that are
760            *  old (the timeout can be fairly short), or more than a
761            *  reasonable time in the future (so that cookies never
762            *  accidentally become permanent, if the clock was set far
763            *  into the future at some point). If no recent keys remain,
764            *  the server may generate a new key.
765            *
766            */
767           keep_entry = TRUE;
768           if (line_when > now)
769             {
770               /* Oddball case: entry is more recent than our current wall-clock time..
771                * This is OK, it means that another server on another machine but with
772                * same $HOME wrote the entry.
773                *
774                * So discard the entry if it's more than 1 day in the future ("reasonable
775                * time in the future").
776                */
777               if (line_when - now > 24*60*60)
778                 {
779                   keep_entry = FALSE;
780                   _log ("Deleted SHA1 cookie from %" G_GUINT64_FORMAT " seconds in the future", line_when - now);
781                 }
782             }
783           else
784             {
785               /* Discard entry if it's older than 15 minutes ("can be fairly short") */
786               if (now - line_when > 15*60)
787                 {
788                   keep_entry = FALSE;
789                 }
790             }
791
792           if (!keep_entry)
793             {
794               changed_file = FALSE;
795             }
796           else
797             {
798               g_string_append_printf (new_contents,
799                                       "%d %" G_GUINT64_FORMAT " %s\n",
800                                       line_id,
801                                       line_when,
802                                       tokens[2]);
803               max_line_id = MAX (line_id, max_line_id);
804               /* Only reuse entry if not older than 10 minutes.
805                *
806                * (We need a bit of grace time compared to 15 minutes above.. otherwise
807                * there's a race where we reuse the 14min59.9 secs old entry and a
808                * split-second later another server purges the now 15 minute old entry.)
809                */
810               if (now - line_when < 10 * 60)
811                 {
812                   if (!have_id)
813                     {
814                       use_id = line_id;
815                       use_cookie = tokens[2]; /* steal memory */
816                       tokens[2] = NULL;
817                       have_id = TRUE;
818                     }
819                 }
820             }
821           g_strfreev (tokens);
822         }
823     } /* for each line */
824
825   ret = TRUE;
826
827   if (have_id)
828     {
829       *out_id = use_id;
830       *out_cookie = use_cookie;
831       use_cookie = NULL;
832     }
833   else
834     {
835       gchar *raw_cookie;
836       *out_id = max_line_id + 1;
837       raw_cookie = random_blob (32);
838       *out_cookie = hexencode (raw_cookie, 32);
839       g_free (raw_cookie);
840
841       g_string_append_printf (new_contents,
842                               "%d %" G_GUINT64_FORMAT " %s\n",
843                               *out_id,
844                               (guint64) time (NULL),
845                               *out_cookie);
846       changed_file = TRUE;
847     }
848
849   /* and now actually write the cookie file if there are changes (this is atomic) */
850   if (changed_file)
851     {
852       if (!g_file_set_contents (path,
853                                 new_contents->str,
854                                 -1,
855                                 error))
856         {
857           *out_id = 0;
858           *out_cookie = 0;
859           g_free (*out_cookie);
860           ret = FALSE;
861           goto out;
862         }
863     }
864
865  out:
866
867   if (lock_fd != -1)
868     {
869       GError *local_error;
870       local_error = NULL;
871       if (!keyring_release_lock (path, lock_fd, &local_error))
872         {
873           if (error != NULL)
874             {
875               if (*error == NULL)
876                 {
877                   *error = local_error;
878                 }
879               else
880                 {
881                   g_prefix_error (error,
882                                   _("(Additionally, releasing the lock for `%s' also failed: %s) "),
883                                   path,
884                                   local_error->message);
885                 }
886             }
887           else
888             {
889               g_error_free (local_error);
890             }
891         }
892     }
893
894   g_free (keyring_dir);
895   g_free (path);
896   g_strfreev (lines);
897   g_free (contents);
898   if (new_contents != NULL)
899     g_string_free (new_contents, TRUE);
900   g_free (use_cookie);
901   return ret;
902 }
903
904 /* ---------------------------------------------------------------------------------------------------- */
905
906 static gchar *
907 generate_sha1 (const gchar *server_challenge,
908                const gchar *client_challenge,
909                const gchar *cookie)
910 {
911   GString *str;
912   gchar *sha1;
913
914   str = g_string_new (server_challenge);
915   g_string_append_c (str, ':');
916   g_string_append (str, client_challenge);
917   g_string_append_c (str, ':');
918   g_string_append (str, cookie);
919   sha1 = g_compute_checksum_for_string (G_CHECKSUM_SHA1, str->str, -1);
920   g_string_free (str, TRUE);
921
922   return sha1;
923 }
924
925 /* ---------------------------------------------------------------------------------------------------- */
926
927 static GDBusAuthMechanismState
928 mechanism_server_get_state (GDBusAuthMechanism   *mechanism)
929 {
930   GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
931
932   g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID);
933   g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, G_DBUS_AUTH_MECHANISM_STATE_INVALID);
934
935   return m->priv->state;
936 }
937
938 static void
939 mechanism_server_initiate (GDBusAuthMechanism   *mechanism,
940                            const gchar          *initial_response,
941                            gsize                 initial_response_len)
942 {
943   GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
944
945   g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
946   g_return_if_fail (!m->priv->is_server && !m->priv->is_client);
947
948   m->priv->is_server = TRUE;
949   m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
950
951   if (initial_response != NULL && strlen (initial_response) > 0)
952     {
953 #ifdef G_OS_UNIX
954       gint64 uid;
955       gchar *endp;
956
957       uid = g_ascii_strtoll (initial_response, &endp, 10);
958       if (*endp == '\0')
959         {
960           if (uid == getuid ())
961             {
962               m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND;
963             }
964         }
965 #elif defined(G_OS_WIN32)
966       gchar *sid;
967       sid = _g_dbus_win32_get_user_sid ();
968       if (g_strcmp0 (initial_response, sid) == 0)
969         m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND;
970       g_free (sid);
971 #else
972 #error Please implement for your OS
973 #endif
974     }
975 }
976
977 static void
978 mechanism_server_data_receive (GDBusAuthMechanism   *mechanism,
979                                const gchar          *data,
980                                gsize                 data_len)
981 {
982   GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
983   gchar **tokens;
984   const gchar *client_challenge;
985   const gchar *alleged_sha1;
986   gchar *sha1;
987
988   g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
989   g_return_if_fail (m->priv->is_server && !m->priv->is_client);
990   g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA);
991
992   tokens = NULL;
993   sha1 = NULL;
994
995   tokens = g_strsplit (data, " ", 0);
996   if (g_strv_length (tokens) != 2)
997     {
998       g_warning ("Malformed data `%s'", data);
999       m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1000       goto out;
1001     }
1002
1003   client_challenge = tokens[0];
1004   alleged_sha1 = tokens[1];
1005
1006   sha1 = generate_sha1 (m->priv->server_challenge, client_challenge, m->priv->cookie);
1007
1008   if (g_strcmp0 (sha1, alleged_sha1) == 0)
1009     {
1010       m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
1011     }
1012   else
1013     {
1014       m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1015     }
1016
1017  out:
1018   g_strfreev (tokens);
1019   g_free (sha1);
1020 }
1021
1022 static gchar *
1023 mechanism_server_data_send (GDBusAuthMechanism   *mechanism,
1024                             gsize                *out_data_len)
1025 {
1026   GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1027   gchar *s;
1028   gint cookie_id;
1029   const gchar *cookie_context;
1030   GError *error;
1031
1032   g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL);
1033   g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL);
1034   g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL);
1035
1036   s = NULL;
1037
1038   /* TODO: use GDBusAuthObserver here to get the cookie context to use? */
1039   cookie_context = "org_gtk_gdbus_general";
1040
1041   cookie_id = -1;
1042   error = NULL;
1043   if (!keyring_generate_entry (cookie_context,
1044                                &cookie_id,
1045                                &m->priv->cookie,
1046                                &error))
1047     {
1048       g_warning ("Error adding entry to keyring: %s", error->message);
1049       g_error_free (error);
1050       m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1051       goto out;
1052     }
1053
1054   m->priv->server_challenge = random_ascii_string (16);
1055   s = g_strdup_printf ("%s %d %s",
1056                        cookie_context,
1057                        cookie_id,
1058                        m->priv->server_challenge);
1059
1060   m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA;
1061
1062  out:
1063   return s;
1064 }
1065
1066 static gchar *
1067 mechanism_server_get_reject_reason (GDBusAuthMechanism   *mechanism)
1068 {
1069   GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1070
1071   g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL);
1072   g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL);
1073   g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_REJECTED, NULL);
1074
1075   /* can never end up here because we are never in the REJECTED state */
1076   g_assert_not_reached ();
1077
1078   return NULL;
1079 }
1080
1081 static void
1082 mechanism_server_shutdown (GDBusAuthMechanism   *mechanism)
1083 {
1084   GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1085
1086   g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
1087   g_return_if_fail (m->priv->is_server && !m->priv->is_client);
1088
1089   m->priv->is_server = FALSE;
1090 }
1091
1092 /* ---------------------------------------------------------------------------------------------------- */
1093
1094 static GDBusAuthMechanismState
1095 mechanism_client_get_state (GDBusAuthMechanism   *mechanism)
1096 {
1097   GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1098
1099   g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID);
1100   g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, G_DBUS_AUTH_MECHANISM_STATE_INVALID);
1101
1102   return m->priv->state;
1103 }
1104
1105 static gchar *
1106 mechanism_client_initiate (GDBusAuthMechanism   *mechanism,
1107                            gsize                *out_initial_response_len)
1108 {
1109   GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1110   gchar *initial_response;
1111
1112   g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL);
1113   g_return_val_if_fail (!m->priv->is_server && !m->priv->is_client, NULL);
1114
1115   m->priv->is_client = TRUE;
1116   m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA;
1117
1118   *out_initial_response_len = -1;
1119
1120 #ifdef G_OS_UNIX
1121   initial_response = g_strdup_printf ("%" G_GINT64_FORMAT, (gint64) getuid ());
1122 #elif defined (G_OS_WIN32)
1123 initial_response = _g_dbus_win32_get_user_sid ();
1124 #else
1125 #error Please implement for your OS
1126 #endif
1127   g_assert (initial_response != NULL);
1128
1129   return initial_response;
1130 }
1131
1132 static void
1133 mechanism_client_data_receive (GDBusAuthMechanism   *mechanism,
1134                                const gchar          *data,
1135                                gsize                 data_len)
1136 {
1137   GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1138   gchar **tokens;
1139   const gchar *cookie_context;
1140   guint cookie_id;
1141   const gchar *server_challenge;
1142   gchar *client_challenge;
1143   gchar *endp;
1144   gchar *cookie;
1145   GError *error;
1146   gchar *sha1;
1147
1148   g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
1149   g_return_if_fail (m->priv->is_client && !m->priv->is_server);
1150   g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA);
1151
1152   tokens = NULL;
1153   cookie = NULL;
1154   client_challenge = NULL;
1155
1156   tokens = g_strsplit (data, " ", 0);
1157   if (g_strv_length (tokens) != 3)
1158     {
1159       g_warning ("Malformed data `%s'", data);
1160       m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1161       goto out;
1162     }
1163
1164   cookie_context = tokens[0];
1165   cookie_id = g_ascii_strtoll (tokens[1], &endp, 10);
1166   if (*endp != '\0')
1167     {
1168       g_warning ("Malformed cookie_id `%s'", tokens[1]);
1169       m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1170       goto out;
1171     }
1172   server_challenge = tokens[2];
1173
1174   error = NULL;
1175   cookie = keyring_lookup_entry (cookie_context, cookie_id, &error);
1176   if (cookie == NULL)
1177     {
1178       g_warning ("Problems looking up entry in keyring: %s", error->message);
1179       g_error_free (error);
1180       m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1181       goto out;
1182     }
1183
1184   client_challenge = random_ascii_string (16);
1185   sha1 = generate_sha1 (server_challenge, client_challenge, cookie);
1186   m->priv->to_send = g_strdup_printf ("%s %s", client_challenge, sha1);
1187   g_free (sha1);
1188   m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND;
1189
1190  out:
1191   g_strfreev (tokens);
1192   g_free (cookie);
1193   g_free (client_challenge);
1194 }
1195
1196 static gchar *
1197 mechanism_client_data_send (GDBusAuthMechanism   *mechanism,
1198                             gsize                *out_data_len)
1199 {
1200   GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1201
1202   g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL);
1203   g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, NULL);
1204   g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL);
1205
1206   g_assert (m->priv->to_send != NULL);
1207
1208   m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
1209
1210   return g_strdup (m->priv->to_send);
1211 }
1212
1213 static void
1214 mechanism_client_shutdown (GDBusAuthMechanism   *mechanism)
1215 {
1216   GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1217
1218   g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
1219   g_return_if_fail (m->priv->is_client && !m->priv->is_server);
1220
1221   m->priv->is_client = FALSE;
1222 }
1223
1224 /* ---------------------------------------------------------------------------------------------------- */