Improvde #include order consistency
[glib.git] / gio / gdbusauthmechanismsha1.c
blob4729208e0cce427f35d855ac2f4a941504ab0560
1 /* GDBus - GLib D-Bus Library
3 * Copyright (C) 2008-2010 Red Hat, Inc.
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.
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.
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.
20 * Author: David Zeuthen <davidz@redhat.com>
23 #include "config.h"
25 #include <string.h>
26 #include <fcntl.h>
27 #include <errno.h>
28 #include <sys/types.h>
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32 #ifdef _WIN32
33 #include <io.h>
34 #endif
36 #include <glib/gstdio.h>
38 #include "gdbusauthmechanismsha1.h"
39 #include "gcredentials.h"
40 #include "gdbuserror.h"
41 #include "gioenumtypes.h"
42 #include "gioerror.h"
43 #include "gdbusprivate.h"
45 #include "glibintl.h"
47 struct _GDBusAuthMechanismSha1Private
49 gboolean is_client;
50 gboolean is_server;
51 GDBusAuthMechanismState state;
53 /* used on the client side */
54 gchar *to_send;
56 /* used on the server side */
57 gchar *cookie;
58 gchar *server_challenge;
61 static gint mechanism_get_priority (void);
62 static const gchar *mechanism_get_name (void);
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);
94 /* ---------------------------------------------------------------------------------------------------- */
96 G_DEFINE_TYPE (GDBusAuthMechanismSha1, _g_dbus_auth_mechanism_sha1, G_TYPE_DBUS_AUTH_MECHANISM);
98 /* ---------------------------------------------------------------------------------------------------- */
100 static void
101 _g_dbus_auth_mechanism_sha1_finalize (GObject *object)
103 GDBusAuthMechanismSha1 *mechanism = G_DBUS_AUTH_MECHANISM_SHA1 (object);
105 g_free (mechanism->priv->to_send);
107 g_free (mechanism->priv->cookie);
108 g_free (mechanism->priv->server_challenge);
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);
114 static void
115 _g_dbus_auth_mechanism_sha1_class_init (GDBusAuthMechanismSha1Class *klass)
117 GObjectClass *gobject_class;
118 GDBusAuthMechanismClass *mechanism_class;
120 g_type_class_add_private (klass, sizeof (GDBusAuthMechanismSha1Private));
122 gobject_class = G_OBJECT_CLASS (klass);
123 gobject_class->finalize = _g_dbus_auth_mechanism_sha1_finalize;
125 mechanism_class = G_DBUS_AUTH_MECHANISM_CLASS (klass);
126 mechanism_class->get_priority = mechanism_get_priority;
127 mechanism_class->get_name = mechanism_get_name;
128 mechanism_class->is_supported = mechanism_is_supported;
129 mechanism_class->encode_data = mechanism_encode_data;
130 mechanism_class->decode_data = mechanism_decode_data;
131 mechanism_class->server_get_state = mechanism_server_get_state;
132 mechanism_class->server_initiate = mechanism_server_initiate;
133 mechanism_class->server_data_receive = mechanism_server_data_receive;
134 mechanism_class->server_data_send = mechanism_server_data_send;
135 mechanism_class->server_get_reject_reason = mechanism_server_get_reject_reason;
136 mechanism_class->server_shutdown = mechanism_server_shutdown;
137 mechanism_class->client_get_state = mechanism_client_get_state;
138 mechanism_class->client_initiate = mechanism_client_initiate;
139 mechanism_class->client_data_receive = mechanism_client_data_receive;
140 mechanism_class->client_data_send = mechanism_client_data_send;
141 mechanism_class->client_shutdown = mechanism_client_shutdown;
144 static void
145 _g_dbus_auth_mechanism_sha1_init (GDBusAuthMechanismSha1 *mechanism)
147 mechanism->priv = G_TYPE_INSTANCE_GET_PRIVATE (mechanism,
148 G_TYPE_DBUS_AUTH_MECHANISM_SHA1,
149 GDBusAuthMechanismSha1Private);
152 /* ---------------------------------------------------------------------------------------------------- */
154 static gint
155 mechanism_get_priority (void)
157 return 0;
160 static const gchar *
161 mechanism_get_name (void)
163 return "DBUS_COOKIE_SHA1";
166 static gboolean
167 mechanism_is_supported (GDBusAuthMechanism *mechanism)
169 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), FALSE);
170 return TRUE;
173 static gchar *
174 mechanism_encode_data (GDBusAuthMechanism *mechanism,
175 const gchar *data,
176 gsize data_len,
177 gsize *out_data_len)
179 return NULL;
183 static gchar *
184 mechanism_decode_data (GDBusAuthMechanism *mechanism,
185 const gchar *data,
186 gsize data_len,
187 gsize *out_data_len)
189 return NULL;
192 /* ---------------------------------------------------------------------------------------------------- */
194 static gint
195 random_ascii (void)
197 gint ret;
198 ret = g_random_int_range (0, 60);
199 if (ret < 25)
200 ret += 'A';
201 else if (ret < 50)
202 ret += 'a' - 25;
203 else
204 ret += '0' - 50;
205 return ret;
208 static gchar *
209 random_ascii_string (guint len)
211 GString *challenge;
212 guint n;
214 challenge = g_string_new (NULL);
215 for (n = 0; n < len; n++)
216 g_string_append_c (challenge, random_ascii ());
217 return g_string_free (challenge, FALSE);
220 static gchar *
221 random_blob (guint len)
223 GString *challenge;
224 guint n;
226 challenge = g_string_new (NULL);
227 for (n = 0; n < len; n++)
228 g_string_append_c (challenge, g_random_int_range (0, 256));
229 return g_string_free (challenge, FALSE);
232 /* ---------------------------------------------------------------------------------------------------- */
234 /* ensure keyring dir exists and permissions are correct */
235 static gchar *
236 ensure_keyring_directory (GError **error)
238 gchar *path;
239 const gchar *e;
241 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
243 e = g_getenv ("G_DBUS_COOKIE_SHA1_KEYRING_DIR");
244 if (e != NULL)
246 path = g_strdup (e);
248 else
250 path = g_build_filename (g_get_home_dir (),
251 ".dbus-keyrings",
252 NULL);
255 if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
257 if (g_getenv ("G_DBUS_COOKIE_SHA1_KEYRING_DIR_IGNORE_PERMISSION") == NULL)
259 #ifdef G_OS_UNIX
260 struct stat statbuf;
261 if (stat (path, &statbuf) != 0)
263 g_set_error (error,
264 G_IO_ERROR,
265 g_io_error_from_errno (errno),
266 _("Error when getting information for directory `%s': %s"),
267 path,
268 strerror (errno));
269 g_free (path);
270 path = NULL;
271 goto out;
273 if ((statbuf.st_mode & 0777) != 0700)
275 g_set_error (error,
276 G_IO_ERROR,
277 G_IO_ERROR_FAILED,
278 _("Permissions on directory `%s' are malformed. Expected mode 0700, got 0%o"),
279 path,
280 statbuf.st_mode & 0777);
281 g_free (path);
282 path = NULL;
283 goto out;
285 #else
286 #ifdef __GNUC__
287 #warning Please implement permission checking on this non-UNIX platform
288 #endif
289 #endif
291 goto out;
294 if (g_mkdir (path, 0700) != 0)
296 g_set_error (error,
297 G_IO_ERROR,
298 g_io_error_from_errno (errno),
299 _("Error creating directory `%s': %s"),
300 path,
301 strerror (errno));
302 g_free (path);
303 path = NULL;
304 goto out;
307 out:
308 return path;
311 /* ---------------------------------------------------------------------------------------------------- */
313 static void
314 append_nibble (GString *s, gint val)
316 g_string_append_c (s, val >= 10 ? ('a' + val - 10) : ('0' + val));
319 static gchar *
320 hexencode (const gchar *str,
321 gssize len)
323 guint n;
324 GString *s;
326 if (len == -1)
327 len = strlen (str);
329 s = g_string_new (NULL);
330 for (n = 0; n < len; n++)
332 gint val;
333 gint upper_nibble;
334 gint lower_nibble;
336 val = ((const guchar *) str)[n];
337 upper_nibble = val >> 4;
338 lower_nibble = val & 0x0f;
340 append_nibble (s, upper_nibble);
341 append_nibble (s, lower_nibble);
344 return g_string_free (s, FALSE);
347 /* ---------------------------------------------------------------------------------------------------- */
349 /* looks up an entry in the keyring */
350 static gchar *
351 keyring_lookup_entry (const gchar *cookie_context,
352 gint cookie_id,
353 GError **error)
355 gchar *ret;
356 gchar *keyring_dir;
357 gchar *contents;
358 gchar *path;
359 guint n;
360 gchar **lines;
362 g_return_val_if_fail (cookie_context != NULL, NULL);
363 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
365 ret = NULL;
366 path = NULL;
367 contents = NULL;
368 lines = NULL;
370 keyring_dir = ensure_keyring_directory (error);
371 if (keyring_dir == NULL)
372 goto out;
374 path = g_build_filename (keyring_dir, cookie_context, NULL);
376 if (!g_file_get_contents (path,
377 &contents,
378 NULL,
379 error))
381 g_prefix_error (error,
382 _("Error opening keyring `%s' for reading: "),
383 path);
384 goto out;
386 g_assert (contents != NULL);
388 lines = g_strsplit (contents, "\n", 0);
389 for (n = 0; lines[n] != NULL; n++)
391 const gchar *line = lines[n];
392 gchar **tokens;
393 gchar *endp;
394 gint line_id;
395 guint64 line_when;
397 if (line[0] == '\0')
398 continue;
400 tokens = g_strsplit (line, " ", 0);
401 if (g_strv_length (tokens) != 3)
403 g_set_error (error,
404 G_IO_ERROR,
405 G_IO_ERROR_FAILED,
406 _("Line %d of the keyring at `%s' with content `%s' is malformed"),
407 n + 1,
408 path,
409 line);
410 g_strfreev (tokens);
411 goto out;
414 line_id = g_ascii_strtoll (tokens[0], &endp, 10);
415 if (*endp != '\0')
417 g_set_error (error,
418 G_IO_ERROR,
419 G_IO_ERROR_FAILED,
420 _("First token of line %d of the keyring at `%s' with content `%s' is malformed"),
421 n + 1,
422 path,
423 line);
424 g_strfreev (tokens);
425 goto out;
428 line_when = g_ascii_strtoll (tokens[1], &endp, 10);
429 line_when = line_when; /* To avoid -Wunused-but-set-variable */
430 if (*endp != '\0')
432 g_set_error (error,
433 G_IO_ERROR,
434 G_IO_ERROR_FAILED,
435 _("Second token of line %d of the keyring at `%s' with content `%s' is malformed"),
436 n + 1,
437 path,
438 line);
439 g_strfreev (tokens);
440 goto out;
443 if (line_id == cookie_id)
445 /* YAY, success */
446 ret = tokens[2]; /* steal pointer */
447 tokens[2] = NULL;
448 g_strfreev (tokens);
449 goto out;
452 g_strfreev (tokens);
455 /* BOOH, didn't find the cookie */
456 g_set_error (error,
457 G_IO_ERROR,
458 G_IO_ERROR_FAILED,
459 _("Didn't find cookie with id %d in the keyring at `%s'"),
460 cookie_id,
461 path);
463 out:
464 g_free (keyring_dir);
465 g_free (path);
466 g_free (contents);
467 g_strfreev (lines);
468 return ret;
471 /* function for logging important events that the system administrator should take notice of */
472 static void
473 _log (const gchar *message,
474 ...)
476 gchar *s;
477 va_list var_args;
479 va_start (var_args, message);
480 s = g_strdup_vprintf (message, var_args);
481 va_end (var_args);
483 /* TODO: might want to send this to syslog instead */
484 g_printerr ("GDBus-DBUS_COOKIE_SHA1: %s\n", s);
485 g_free (s);
488 static gint
489 keyring_acquire_lock (const gchar *path,
490 GError **error)
492 gchar *lock;
493 gint ret;
494 guint num_tries;
495 guint num_create_tries;
497 g_return_val_if_fail (path != NULL, FALSE);
498 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
500 ret = -1;
501 lock = g_strdup_printf ("%s.lock", path);
503 /* This is what the D-Bus spec says
505 * Create a lockfile name by appending ".lock" to the name of the
506 * cookie file. The server should attempt to create this file using
507 * O_CREAT | O_EXCL. If file creation fails, the lock
508 * fails. Servers should retry for a reasonable period of time,
509 * then they may choose to delete an existing lock to keep users
510 * from having to manually delete a stale lock. [1]
512 * [1] : Lockfiles are used instead of real file locking fcntl() because
513 * real locking implementations are still flaky on network filesystems
516 num_create_tries = 0;
517 #ifdef EEXISTS
518 again:
519 #endif
520 num_tries = 0;
521 while (g_file_test (lock, G_FILE_TEST_EXISTS))
523 /* sleep 10ms, then try again */
524 g_usleep (1000*10);
525 num_tries++;
526 if (num_tries == 50)
528 /* ok, we slept 50*10ms = 0.5 seconds. Conclude that the lock file must be
529 * stale (nuke the it from orbit)
531 if (g_unlink (lock) != 0)
533 g_set_error (error,
534 G_IO_ERROR,
535 g_io_error_from_errno (errno),
536 _("Error deleting stale lock file `%s': %s"),
537 lock,
538 strerror (errno));
539 goto out;
541 _log ("Deleted stale lock file `%s'", lock);
542 break;
546 ret = g_open (lock, O_CREAT |
547 #ifdef O_EXCL
548 O_EXCL,
549 #else
551 #endif
552 0700);
553 if (ret == -1)
555 #ifdef EEXISTS
556 /* EEXIST: pathname already exists and O_CREAT and O_EXCL were used. */
557 if (errno == EEXISTS)
559 num_create_tries++;
560 if (num_create_tries < 5)
561 goto again;
563 #endif
564 num_create_tries = num_create_tries; /* To avoid -Wunused-but-set-variable */
565 g_set_error (error,
566 G_IO_ERROR,
567 g_io_error_from_errno (errno),
568 _("Error creating lock file `%s': %s"),
569 lock,
570 strerror (errno));
571 goto out;
574 out:
575 g_free (lock);
576 return ret;
579 static gboolean
580 keyring_release_lock (const gchar *path,
581 gint lock_fd,
582 GError **error)
584 gchar *lock;
585 gboolean ret;
587 g_return_val_if_fail (path != NULL, FALSE);
588 g_return_val_if_fail (lock_fd != -1, FALSE);
589 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
591 ret = FALSE;
592 lock = g_strdup_printf ("%s.lock", path);
593 if (close (lock_fd) != 0)
595 g_set_error (error,
596 G_IO_ERROR,
597 g_io_error_from_errno (errno),
598 _("Error closing (unlinked) lock file `%s': %s"),
599 lock,
600 strerror (errno));
601 goto out;
603 if (g_unlink (lock) != 0)
605 g_set_error (error,
606 G_IO_ERROR,
607 g_io_error_from_errno (errno),
608 _("Error unlinking lock file `%s': %s"),
609 lock,
610 strerror (errno));
611 goto out;
614 ret = TRUE;
616 out:
617 g_free (lock);
618 return ret;
622 /* adds an entry to the keyring, taking care of locking and deleting stale/future entries */
623 static gboolean
624 keyring_generate_entry (const gchar *cookie_context,
625 gint *out_id,
626 gchar **out_cookie,
627 GError **error)
629 gboolean ret;
630 gchar *keyring_dir;
631 gchar *path;
632 gchar *contents;
633 GError *local_error;
634 gchar **lines;
635 gint max_line_id;
636 GString *new_contents;
637 guint64 now;
638 gboolean have_id;
639 gint use_id;
640 gchar *use_cookie;
641 gboolean changed_file;
642 gint lock_fd;
644 g_return_val_if_fail (cookie_context != NULL, FALSE);
645 g_return_val_if_fail (out_id != NULL, FALSE);
646 g_return_val_if_fail (out_cookie != NULL, FALSE);
647 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
649 ret = FALSE;
650 path = NULL;
651 contents = NULL;
652 lines = NULL;
653 new_contents = NULL;
654 have_id = FALSE;
655 use_id = 0;
656 use_cookie = NULL;
657 lock_fd = -1;
659 keyring_dir = ensure_keyring_directory (error);
660 if (keyring_dir == NULL)
661 goto out;
663 path = g_build_filename (keyring_dir, cookie_context, NULL);
665 lock_fd = keyring_acquire_lock (path, error);
666 if (lock_fd == -1)
667 goto out;
669 local_error = NULL;
670 contents = NULL;
671 if (!g_file_get_contents (path,
672 &contents,
673 NULL,
674 &local_error))
676 if (local_error->domain == G_FILE_ERROR && local_error->code == G_FILE_ERROR_NOENT)
678 /* file doesn't have to exist */
679 g_error_free (local_error);
681 else
683 g_propagate_prefixed_error (error,
684 local_error,
685 _("Error opening keyring `%s' for writing: "),
686 path);
687 goto out;
691 new_contents = g_string_new (NULL);
692 now = time (NULL);
693 changed_file = FALSE;
695 max_line_id = 0;
696 if (contents != NULL)
698 guint n;
699 lines = g_strsplit (contents, "\n", 0);
700 for (n = 0; lines[n] != NULL; n++)
702 const gchar *line = lines[n];
703 gchar **tokens;
704 gchar *endp;
705 gint line_id;
706 guint64 line_when;
707 gboolean keep_entry;
709 if (line[0] == '\0')
710 continue;
712 tokens = g_strsplit (line, " ", 0);
713 if (g_strv_length (tokens) != 3)
715 g_set_error (error,
716 G_IO_ERROR,
717 G_IO_ERROR_FAILED,
718 _("Line %d of the keyring at `%s' with content `%s' is malformed"),
719 n + 1,
720 path,
721 line);
722 g_strfreev (tokens);
723 goto out;
726 line_id = g_ascii_strtoll (tokens[0], &endp, 10);
727 if (*endp != '\0')
729 g_set_error (error,
730 G_IO_ERROR,
731 G_IO_ERROR_FAILED,
732 _("First token of line %d of the keyring at `%s' with content `%s' is malformed"),
733 n + 1,
734 path,
735 line);
736 g_strfreev (tokens);
737 goto out;
740 line_when = g_ascii_strtoll (tokens[1], &endp, 10);
741 if (*endp != '\0')
743 g_set_error (error,
744 G_IO_ERROR,
745 G_IO_ERROR_FAILED,
746 _("Second token of line %d of the keyring at `%s' with content `%s' is malformed"),
747 n + 1,
748 path,
749 line);
750 g_strfreev (tokens);
751 goto out;
753 line_when = line_when; /* To avoid -Wunused-but-set-variable */
756 /* D-Bus spec says:
758 * Once the lockfile has been created, the server loads the
759 * cookie file. It should then delete any cookies that are
760 * old (the timeout can be fairly short), or more than a
761 * reasonable time in the future (so that cookies never
762 * accidentally become permanent, if the clock was set far
763 * into the future at some point). If no recent keys remain,
764 * the server may generate a new key.
767 keep_entry = TRUE;
768 if (line_when > now)
770 /* Oddball case: entry is more recent than our current wall-clock time..
771 * This is OK, it means that another server on another machine but with
772 * same $HOME wrote the entry.
774 * So discard the entry if it's more than 1 day in the future ("reasonable
775 * time in the future").
777 if (line_when - now > 24*60*60)
779 keep_entry = FALSE;
780 _log ("Deleted SHA1 cookie from %" G_GUINT64_FORMAT " seconds in the future", line_when - now);
783 else
785 /* Discard entry if it's older than 15 minutes ("can be fairly short") */
786 if (now - line_when > 15*60)
788 keep_entry = FALSE;
792 if (!keep_entry)
794 changed_file = FALSE;
796 else
798 g_string_append_printf (new_contents,
799 "%d %" G_GUINT64_FORMAT " %s\n",
800 line_id,
801 line_when,
802 tokens[2]);
803 max_line_id = MAX (line_id, max_line_id);
804 /* Only reuse entry if not older than 10 minutes.
806 * (We need a bit of grace time compared to 15 minutes above.. otherwise
807 * there's a race where we reuse the 14min59.9 secs old entry and a
808 * split-second later another server purges the now 15 minute old entry.)
810 if (now - line_when < 10 * 60)
812 if (!have_id)
814 use_id = line_id;
815 use_cookie = tokens[2]; /* steal memory */
816 tokens[2] = NULL;
817 have_id = TRUE;
821 g_strfreev (tokens);
823 } /* for each line */
825 ret = TRUE;
827 if (have_id)
829 *out_id = use_id;
830 *out_cookie = use_cookie;
831 use_cookie = NULL;
833 else
835 gchar *raw_cookie;
836 *out_id = max_line_id + 1;
837 raw_cookie = random_blob (32);
838 *out_cookie = hexencode (raw_cookie, 32);
839 g_free (raw_cookie);
841 g_string_append_printf (new_contents,
842 "%d %" G_GUINT64_FORMAT " %s\n",
843 *out_id,
844 (guint64) time (NULL),
845 *out_cookie);
846 changed_file = TRUE;
849 /* and now actually write the cookie file if there are changes (this is atomic) */
850 if (changed_file)
852 if (!g_file_set_contents (path,
853 new_contents->str,
855 error))
857 *out_id = 0;
858 *out_cookie = 0;
859 g_free (*out_cookie);
860 ret = FALSE;
861 goto out;
865 out:
867 if (lock_fd != -1)
869 GError *local_error;
870 local_error = NULL;
871 if (!keyring_release_lock (path, lock_fd, &local_error))
873 if (error != NULL)
875 if (*error == NULL)
877 *error = local_error;
879 else
881 g_prefix_error (error,
882 _("(Additionally, releasing the lock for `%s' also failed: %s) "),
883 path,
884 local_error->message);
887 else
889 g_error_free (local_error);
894 g_free (keyring_dir);
895 g_free (path);
896 g_strfreev (lines);
897 g_free (contents);
898 if (new_contents != NULL)
899 g_string_free (new_contents, TRUE);
900 g_free (use_cookie);
901 return ret;
904 /* ---------------------------------------------------------------------------------------------------- */
906 static gchar *
907 generate_sha1 (const gchar *server_challenge,
908 const gchar *client_challenge,
909 const gchar *cookie)
911 GString *str;
912 gchar *sha1;
914 str = g_string_new (server_challenge);
915 g_string_append_c (str, ':');
916 g_string_append (str, client_challenge);
917 g_string_append_c (str, ':');
918 g_string_append (str, cookie);
919 sha1 = g_compute_checksum_for_string (G_CHECKSUM_SHA1, str->str, -1);
920 g_string_free (str, TRUE);
922 return sha1;
925 /* ---------------------------------------------------------------------------------------------------- */
927 static GDBusAuthMechanismState
928 mechanism_server_get_state (GDBusAuthMechanism *mechanism)
930 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
932 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID);
933 g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, G_DBUS_AUTH_MECHANISM_STATE_INVALID);
935 return m->priv->state;
938 static void
939 mechanism_server_initiate (GDBusAuthMechanism *mechanism,
940 const gchar *initial_response,
941 gsize initial_response_len)
943 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
945 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
946 g_return_if_fail (!m->priv->is_server && !m->priv->is_client);
948 m->priv->is_server = TRUE;
949 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
951 if (initial_response != NULL && strlen (initial_response) > 0)
953 #ifdef G_OS_UNIX
954 gint64 uid;
955 gchar *endp;
957 uid = g_ascii_strtoll (initial_response, &endp, 10);
958 if (*endp == '\0')
960 if (uid == getuid ())
962 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND;
965 #elif defined(G_OS_WIN32)
966 gchar *sid;
967 sid = _g_dbus_win32_get_user_sid ();
968 if (g_strcmp0 (initial_response, sid) == 0)
969 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND;
970 g_free (sid);
971 #else
972 #error Please implement for your OS
973 #endif
977 static void
978 mechanism_server_data_receive (GDBusAuthMechanism *mechanism,
979 const gchar *data,
980 gsize data_len)
982 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
983 gchar **tokens;
984 const gchar *client_challenge;
985 const gchar *alleged_sha1;
986 gchar *sha1;
988 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
989 g_return_if_fail (m->priv->is_server && !m->priv->is_client);
990 g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA);
992 tokens = NULL;
993 sha1 = NULL;
995 tokens = g_strsplit (data, " ", 0);
996 if (g_strv_length (tokens) != 2)
998 g_warning ("Malformed data `%s'", data);
999 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1000 goto out;
1003 client_challenge = tokens[0];
1004 alleged_sha1 = tokens[1];
1006 sha1 = generate_sha1 (m->priv->server_challenge, client_challenge, m->priv->cookie);
1008 if (g_strcmp0 (sha1, alleged_sha1) == 0)
1010 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
1012 else
1014 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1017 out:
1018 g_strfreev (tokens);
1019 g_free (sha1);
1022 static gchar *
1023 mechanism_server_data_send (GDBusAuthMechanism *mechanism,
1024 gsize *out_data_len)
1026 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1027 gchar *s;
1028 gint cookie_id;
1029 const gchar *cookie_context;
1030 GError *error;
1032 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL);
1033 g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL);
1034 g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL);
1036 s = NULL;
1038 /* TODO: use GDBusAuthObserver here to get the cookie context to use? */
1039 cookie_context = "org_gtk_gdbus_general";
1041 cookie_id = -1;
1042 error = NULL;
1043 if (!keyring_generate_entry (cookie_context,
1044 &cookie_id,
1045 &m->priv->cookie,
1046 &error))
1048 g_warning ("Error adding entry to keyring: %s", error->message);
1049 g_error_free (error);
1050 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1051 goto out;
1054 m->priv->server_challenge = random_ascii_string (16);
1055 s = g_strdup_printf ("%s %d %s",
1056 cookie_context,
1057 cookie_id,
1058 m->priv->server_challenge);
1060 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA;
1062 out:
1063 return s;
1066 static gchar *
1067 mechanism_server_get_reject_reason (GDBusAuthMechanism *mechanism)
1069 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1071 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL);
1072 g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL);
1073 g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_REJECTED, NULL);
1075 /* can never end up here because we are never in the REJECTED state */
1076 g_assert_not_reached ();
1078 return NULL;
1081 static void
1082 mechanism_server_shutdown (GDBusAuthMechanism *mechanism)
1084 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1086 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
1087 g_return_if_fail (m->priv->is_server && !m->priv->is_client);
1089 m->priv->is_server = FALSE;
1092 /* ---------------------------------------------------------------------------------------------------- */
1094 static GDBusAuthMechanismState
1095 mechanism_client_get_state (GDBusAuthMechanism *mechanism)
1097 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1099 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID);
1100 g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, G_DBUS_AUTH_MECHANISM_STATE_INVALID);
1102 return m->priv->state;
1105 static gchar *
1106 mechanism_client_initiate (GDBusAuthMechanism *mechanism,
1107 gsize *out_initial_response_len)
1109 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1110 gchar *initial_response;
1112 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL);
1113 g_return_val_if_fail (!m->priv->is_server && !m->priv->is_client, NULL);
1115 m->priv->is_client = TRUE;
1116 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA;
1118 *out_initial_response_len = -1;
1120 #ifdef G_OS_UNIX
1121 initial_response = g_strdup_printf ("%" G_GINT64_FORMAT, (gint64) getuid ());
1122 #elif defined (G_OS_WIN32)
1123 initial_response = _g_dbus_win32_get_user_sid ();
1124 #else
1125 #error Please implement for your OS
1126 #endif
1127 g_assert (initial_response != NULL);
1129 return initial_response;
1132 static void
1133 mechanism_client_data_receive (GDBusAuthMechanism *mechanism,
1134 const gchar *data,
1135 gsize data_len)
1137 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1138 gchar **tokens;
1139 const gchar *cookie_context;
1140 guint cookie_id;
1141 const gchar *server_challenge;
1142 gchar *client_challenge;
1143 gchar *endp;
1144 gchar *cookie;
1145 GError *error;
1146 gchar *sha1;
1148 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
1149 g_return_if_fail (m->priv->is_client && !m->priv->is_server);
1150 g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA);
1152 tokens = NULL;
1153 cookie = NULL;
1154 client_challenge = NULL;
1156 tokens = g_strsplit (data, " ", 0);
1157 if (g_strv_length (tokens) != 3)
1159 g_warning ("Malformed data `%s'", data);
1160 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1161 goto out;
1164 cookie_context = tokens[0];
1165 cookie_id = g_ascii_strtoll (tokens[1], &endp, 10);
1166 if (*endp != '\0')
1168 g_warning ("Malformed cookie_id `%s'", tokens[1]);
1169 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1170 goto out;
1172 server_challenge = tokens[2];
1174 error = NULL;
1175 cookie = keyring_lookup_entry (cookie_context, cookie_id, &error);
1176 if (cookie == NULL)
1178 g_warning ("Problems looking up entry in keyring: %s", error->message);
1179 g_error_free (error);
1180 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1181 goto out;
1184 client_challenge = random_ascii_string (16);
1185 sha1 = generate_sha1 (server_challenge, client_challenge, cookie);
1186 m->priv->to_send = g_strdup_printf ("%s %s", client_challenge, sha1);
1187 g_free (sha1);
1188 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND;
1190 out:
1191 g_strfreev (tokens);
1192 g_free (cookie);
1193 g_free (client_challenge);
1196 static gchar *
1197 mechanism_client_data_send (GDBusAuthMechanism *mechanism,
1198 gsize *out_data_len)
1200 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1202 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL);
1203 g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, NULL);
1204 g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL);
1206 g_assert (m->priv->to_send != NULL);
1208 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
1210 return g_strdup (m->priv->to_send);
1213 static void
1214 mechanism_client_shutdown (GDBusAuthMechanism *mechanism)
1216 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1218 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
1219 g_return_if_fail (m->priv->is_client && !m->priv->is_server);
1221 m->priv->is_client = FALSE;
1224 /* ---------------------------------------------------------------------------------------------------- */