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