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