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