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