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.1 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, see <http://www.gnu.org/licenses/>.
18 * Author: David Zeuthen <davidz@redhat.com>
26 #include <sys/types.h>
28 #include <glib/gstdio.h>
37 #include "gdbusauthmechanismsha1.h"
38 #include "gcredentials.h"
39 #include "gdbuserror.h"
40 #include "gioenumtypes.h"
42 #include "gdbusprivate.h"
43 #include "glib-private.h"
48 * Arbitrary timeouts for keys in the keyring.
49 * For interoperability, these match the reference implementation, libdbus.
50 * To make them easier to compare, their names also match libdbus
51 * (see dbus/dbus-keyring.c).
55 * Maximum age of a key before we create a new key to use in challenges:
58 #define NEW_KEY_TIMEOUT_SECONDS (60*5)
61 * Time before we drop a key from the keyring: 7 minutes.
62 * Authentication will succeed if it takes less than
63 * EXPIRE_KEYS_TIMEOUT_SECONDS - NEW_KEY_TIMEOUT_SECONDS (2 minutes)
65 * The spec says "delete any cookies that are old (the timeout can be
68 #define EXPIRE_KEYS_TIMEOUT_SECONDS (NEW_KEY_TIMEOUT_SECONDS + (60*2))
71 * Maximum amount of time a key can be in the future due to clock skew
72 * with a shared home directory: 5 minutes.
73 * The spec says "a reasonable time in the future".
75 #define MAX_TIME_TRAVEL_SECONDS (60*5)
78 struct _GDBusAuthMechanismSha1Private
82 GDBusAuthMechanismState state;
83 gchar *reject_reason; /* non-NULL iff (state == G_DBUS_AUTH_MECHANISM_STATE_REJECTED) */
85 /* used on the client side */
88 /* used on the server side */
90 gchar *server_challenge;
93 static gint mechanism_get_priority (void);
94 static const gchar *mechanism_get_name (void);
96 static gboolean mechanism_is_supported (GDBusAuthMechanism *mechanism);
97 static gchar *mechanism_encode_data (GDBusAuthMechanism *mechanism,
100 gsize *out_data_len);
101 static gchar *mechanism_decode_data (GDBusAuthMechanism *mechanism,
104 gsize *out_data_len);
105 static GDBusAuthMechanismState mechanism_server_get_state (GDBusAuthMechanism *mechanism);
106 static void mechanism_server_initiate (GDBusAuthMechanism *mechanism,
107 const gchar *initial_response,
108 gsize initial_response_len);
109 static void mechanism_server_data_receive (GDBusAuthMechanism *mechanism,
112 static gchar *mechanism_server_data_send (GDBusAuthMechanism *mechanism,
113 gsize *out_data_len);
114 static gchar *mechanism_server_get_reject_reason (GDBusAuthMechanism *mechanism);
115 static void mechanism_server_shutdown (GDBusAuthMechanism *mechanism);
116 static GDBusAuthMechanismState mechanism_client_get_state (GDBusAuthMechanism *mechanism);
117 static gchar *mechanism_client_initiate (GDBusAuthMechanism *mechanism,
118 gsize *out_initial_response_len);
119 static void mechanism_client_data_receive (GDBusAuthMechanism *mechanism,
122 static gchar *mechanism_client_data_send (GDBusAuthMechanism *mechanism,
123 gsize *out_data_len);
124 static void mechanism_client_shutdown (GDBusAuthMechanism *mechanism);
126 /* ---------------------------------------------------------------------------------------------------- */
128 G_DEFINE_TYPE_WITH_PRIVATE (GDBusAuthMechanismSha1, _g_dbus_auth_mechanism_sha1, G_TYPE_DBUS_AUTH_MECHANISM)
130 /* ---------------------------------------------------------------------------------------------------- */
133 _g_dbus_auth_mechanism_sha1_finalize (GObject *object)
135 GDBusAuthMechanismSha1 *mechanism = G_DBUS_AUTH_MECHANISM_SHA1 (object);
137 g_free (mechanism->priv->reject_reason);
138 g_free (mechanism->priv->to_send);
140 g_free (mechanism->priv->cookie);
141 g_free (mechanism->priv->server_challenge);
143 if (G_OBJECT_CLASS (_g_dbus_auth_mechanism_sha1_parent_class)->finalize != NULL)
144 G_OBJECT_CLASS (_g_dbus_auth_mechanism_sha1_parent_class)->finalize (object);
148 _g_dbus_auth_mechanism_sha1_class_init (GDBusAuthMechanismSha1Class *klass)
150 GObjectClass *gobject_class;
151 GDBusAuthMechanismClass *mechanism_class;
153 gobject_class = G_OBJECT_CLASS (klass);
154 gobject_class->finalize = _g_dbus_auth_mechanism_sha1_finalize;
156 mechanism_class = G_DBUS_AUTH_MECHANISM_CLASS (klass);
157 mechanism_class->get_priority = mechanism_get_priority;
158 mechanism_class->get_name = mechanism_get_name;
159 mechanism_class->is_supported = mechanism_is_supported;
160 mechanism_class->encode_data = mechanism_encode_data;
161 mechanism_class->decode_data = mechanism_decode_data;
162 mechanism_class->server_get_state = mechanism_server_get_state;
163 mechanism_class->server_initiate = mechanism_server_initiate;
164 mechanism_class->server_data_receive = mechanism_server_data_receive;
165 mechanism_class->server_data_send = mechanism_server_data_send;
166 mechanism_class->server_get_reject_reason = mechanism_server_get_reject_reason;
167 mechanism_class->server_shutdown = mechanism_server_shutdown;
168 mechanism_class->client_get_state = mechanism_client_get_state;
169 mechanism_class->client_initiate = mechanism_client_initiate;
170 mechanism_class->client_data_receive = mechanism_client_data_receive;
171 mechanism_class->client_data_send = mechanism_client_data_send;
172 mechanism_class->client_shutdown = mechanism_client_shutdown;
176 _g_dbus_auth_mechanism_sha1_init (GDBusAuthMechanismSha1 *mechanism)
178 mechanism->priv = _g_dbus_auth_mechanism_sha1_get_instance_private (mechanism);
181 /* ---------------------------------------------------------------------------------------------------- */
184 mechanism_get_priority (void)
190 mechanism_get_name (void)
192 return "DBUS_COOKIE_SHA1";
196 mechanism_is_supported (GDBusAuthMechanism *mechanism)
198 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), FALSE);
203 mechanism_encode_data (GDBusAuthMechanism *mechanism,
213 mechanism_decode_data (GDBusAuthMechanism *mechanism,
221 /* ---------------------------------------------------------------------------------------------------- */
227 ret = g_random_int_range (0, 60);
238 random_ascii_string (guint len)
243 challenge = g_string_new (NULL);
244 for (n = 0; n < len; n++)
245 g_string_append_c (challenge, random_ascii ());
246 return g_string_free (challenge, FALSE);
250 random_blob (guint len)
255 challenge = g_string_new (NULL);
256 for (n = 0; n < len; n++)
257 g_string_append_c (challenge, g_random_int_range (0, 256));
258 return g_string_free (challenge, FALSE);
261 /* ---------------------------------------------------------------------------------------------------- */
263 /* ensure keyring dir exists and permissions are correct */
265 ensure_keyring_directory (GError **error)
274 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
276 e = g_getenv ("G_DBUS_COOKIE_SHA1_KEYRING_DIR");
283 path = g_build_filename (g_get_home_dir (),
289 if (stat (path, &statbuf) != 0)
297 g_io_error_from_errno (errsv),
298 _("Error when getting information for directory “%s”: %s"),
301 g_clear_pointer (&path, g_free);
305 else if (S_ISDIR (statbuf.st_mode))
307 if (g_getenv ("G_DBUS_COOKIE_SHA1_KEYRING_DIR_IGNORE_PERMISSION") == NULL &&
308 (statbuf.st_mode & 0777) != 0700)
313 _("Permissions on directory “%s” are malformed. Expected mode 0700, got 0%o"),
315 (guint) (statbuf.st_mode & 0777));
316 g_clear_pointer (&path, g_free);
320 return g_steal_pointer (&path);
322 #else /* if !G_OS_UNIX */
323 /* On non-Unix platforms, check that it exists as a directory, but don’t do
324 * permissions checks at the moment. */
325 if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
328 #pragma GCC diagnostic push
329 #pragma GCC diagnostic warning "-Wcpp"
330 #warning Please implement permission checking on this non-UNIX platform
331 #pragma GCC diagnostic pop
332 #endif /* __GNUC__ */
333 return g_steal_pointer (&path);
335 #endif /* if !G_OS_UNIX */
337 /* Only create the directory if not running as setuid */
338 is_setuid = GLIB_PRIVATE_CALL (g_check_setuid) ();
340 g_mkdir_with_parents (path, 0700) != 0)
345 g_io_error_from_errno (errsv),
346 _("Error creating directory “%s”: %s"),
349 g_clear_pointer (&path, g_free);
356 G_IO_ERROR_PERMISSION_DENIED,
357 _("Error creating directory “%s”: %s"),
359 _("Operation not supported"));
360 g_clear_pointer (&path, g_free);
364 return g_steal_pointer (&path);
367 /* ---------------------------------------------------------------------------------------------------- */
369 /* looks up an entry in the keyring */
371 keyring_lookup_entry (const gchar *cookie_context,
382 g_return_val_if_fail (cookie_context != NULL, NULL);
383 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
390 keyring_dir = ensure_keyring_directory (error);
391 if (keyring_dir == NULL)
394 path = g_build_filename (keyring_dir, cookie_context, NULL);
396 if (!g_file_get_contents (path,
401 g_prefix_error (error,
402 _("Error opening keyring “%s” for reading: "),
406 g_assert (contents != NULL);
408 lines = g_strsplit (contents, "\n", 0);
409 for (n = 0; lines[n] != NULL; n++)
411 const gchar *line = lines[n];
419 tokens = g_strsplit (line, " ", 0);
420 if (g_strv_length (tokens) != 3)
425 _("Line %d of the keyring at “%s” with content “%s” is malformed"),
433 line_id = g_ascii_strtoll (tokens[0], &endp, 10);
439 _("First token of line %d of the keyring at “%s” with content “%s” is malformed"),
447 (void)g_ascii_strtoll (tokens[1], &endp, 10); /* do not care what the timestamp is */
453 _("Second token of line %d of the keyring at “%s” with content “%s” is malformed"),
461 if (line_id == cookie_id)
464 ret = tokens[2]; /* steal pointer */
473 /* BOOH, didn't find the cookie */
477 _("Didn’t find cookie with id %d in the keyring at “%s”"),
482 g_free (keyring_dir);
489 /* function for logging important events that the system administrator should take notice of */
492 _log (const gchar *message,
498 va_start (var_args, message);
499 s = g_strdup_vprintf (message, var_args);
502 /* TODO: might want to send this to syslog instead */
503 g_printerr ("GDBus-DBUS_COOKIE_SHA1: %s\n", s);
507 /* Returns FD for lock file, if it was created exclusively (didn't exist already,
508 * and was created successfully) */
510 create_lock_exclusive (const gchar *lock_path,
516 ret = g_open (lock_path, O_CREAT | O_EXCL, 0600);
522 g_io_error_from_errno (errsv),
523 _("Error creating lock file “%s”: %s"),
533 keyring_acquire_lock (const gchar *path,
541 /* Total possible sleep period = max_tries * timeout_usec = 0.5s */
542 const guint max_tries = 50;
543 const guint timeout_usec = 1000 * 10;
545 g_return_val_if_fail (path != NULL, -1);
546 g_return_val_if_fail (error == NULL || *error == NULL, -1);
549 lock = g_strconcat (path, ".lock", NULL);
551 /* This is what the D-Bus spec says
552 * (https://dbus.freedesktop.org/doc/dbus-specification.html#auth-mechanisms-sha)
554 * Create a lockfile name by appending ".lock" to the name of the
555 * cookie file. The server should attempt to create this file using
556 * O_CREAT | O_EXCL. If file creation fails, the lock
557 * fails. Servers should retry for a reasonable period of time,
558 * then they may choose to delete an existing lock to keep users
559 * from having to manually delete a stale lock. [1]
561 * [1] : Lockfiles are used instead of real file locking fcntl() because
562 * real locking implementations are still flaky on network filesystems
565 for (num_tries = 0; num_tries < max_tries; num_tries++)
567 /* Ignore the error until the final call. */
568 ret = create_lock_exclusive (lock, NULL);
572 /* sleep 10ms, then try again */
573 g_usleep (timeout_usec);
576 if (num_tries == max_tries)
578 /* ok, we slept 50*10ms = 0.5 seconds. Conclude that the lock file must be
579 * stale (nuke it from orbit)
581 if (g_unlink (lock) != 0)
586 g_io_error_from_errno (errsv),
587 _("Error deleting stale lock file “%s”: %s"),
593 _log ("Deleted stale lock file '%s'", lock);
595 /* Try one last time to create it, now that we've deleted the stale one */
596 ret = create_lock_exclusive (lock, error);
607 keyring_release_lock (const gchar *path,
614 g_return_val_if_fail (path != NULL, FALSE);
615 g_return_val_if_fail (lock_fd != -1, FALSE);
616 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
619 lock = g_strdup_printf ("%s.lock", path);
620 if (close (lock_fd) != 0)
625 g_io_error_from_errno (errsv),
626 _("Error closing (unlinked) lock file “%s”: %s"),
631 if (g_unlink (lock) != 0)
636 g_io_error_from_errno (errsv),
637 _("Error unlinking lock file “%s”: %s"),
651 /* adds an entry to the keyring, taking care of locking and deleting stale/future entries */
653 keyring_generate_entry (const gchar *cookie_context,
665 GString *new_contents;
670 gboolean changed_file;
673 g_return_val_if_fail (cookie_context != NULL, FALSE);
674 g_return_val_if_fail (out_id != NULL, FALSE);
675 g_return_val_if_fail (out_cookie != NULL, FALSE);
676 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
688 keyring_dir = ensure_keyring_directory (error);
689 if (keyring_dir == NULL)
692 path = g_build_filename (keyring_dir, cookie_context, NULL);
694 lock_fd = keyring_acquire_lock (path, error);
700 if (!g_file_get_contents (path,
705 if (local_error->domain == G_FILE_ERROR && local_error->code == G_FILE_ERROR_NOENT)
707 /* file doesn't have to exist */
708 g_error_free (local_error);
712 g_propagate_prefixed_error (error,
714 _("Error opening keyring “%s” for writing: "),
720 new_contents = g_string_new (NULL);
721 now = g_get_real_time () / G_USEC_PER_SEC;
722 changed_file = FALSE;
725 if (contents != NULL)
728 lines = g_strsplit (contents, "\n", 0);
729 for (n = 0; lines[n] != NULL; n++)
731 const gchar *line = lines[n];
741 tokens = g_strsplit (line, " ", 0);
742 if (g_strv_length (tokens) != 3)
747 _("Line %d of the keyring at “%s” with content “%s” is malformed"),
755 line_id = g_ascii_strtoll (tokens[0], &endp, 10);
761 _("First token of line %d of the keyring at “%s” with content “%s” is malformed"),
769 line_when = g_ascii_strtoll (tokens[1], &endp, 10);
775 _("Second token of line %d of the keyring at “%s” with content “%s” is malformed"),
786 * Once the lockfile has been created, the server loads the
787 * cookie file. It should then delete any cookies that are
788 * old (the timeout can be fairly short), or more than a
789 * reasonable time in the future (so that cookies never
790 * accidentally become permanent, if the clock was set far
791 * into the future at some point). If no recent keys remain,
792 * the server may generate a new key.
798 /* Oddball case: entry is more recent than our current wall-clock time..
799 * This is OK, it means that another server on another machine but with
800 * same $HOME wrote the entry. */
801 if (line_when - now > MAX_TIME_TRAVEL_SECONDS)
804 _log ("Deleted SHA1 cookie from %" G_GUINT64_FORMAT " seconds in the future", line_when - now);
809 /* Discard entry if it's too old. */
810 if (now - line_when > EXPIRE_KEYS_TIMEOUT_SECONDS)
818 changed_file = FALSE;
822 g_string_append_printf (new_contents,
823 "%d %" G_GUINT64_FORMAT " %s\n",
827 max_line_id = MAX (line_id, max_line_id);
828 /* Only reuse entry if not older than 5 minutes.
830 * (We need a bit of grace time compared to 7 minutes above.. otherwise
831 * there's a race where we reuse the 6min59.9 secs old entry and a
832 * split-second later another server purges the now 7 minute old entry.)
834 if (now - line_when < NEW_KEY_TIMEOUT_SECONDS)
839 use_cookie = tokens[2]; /* steal memory */
847 } /* for each line */
854 *out_cookie = use_cookie;
860 *out_id = max_line_id + 1;
861 raw_cookie = random_blob (32);
862 *out_cookie = _g_dbus_hexencode (raw_cookie, 32);
865 g_string_append_printf (new_contents,
866 "%d %" G_GINT64_FORMAT " %s\n",
868 g_get_real_time () / G_USEC_PER_SEC,
873 /* and now actually write the cookie file if there are changes (this is atomic) */
876 if (!g_file_set_contents_full (path,
879 G_FILE_SET_CONTENTS_CONSISTENT,
884 g_free (*out_cookie);
897 if (!keyring_release_lock (path, lock_fd, &local_error))
903 *error = local_error;
907 g_prefix_error (error,
908 _("(Additionally, releasing the lock for “%s” also failed: %s) "),
910 local_error->message);
911 g_error_free (local_error);
916 g_error_free (local_error);
921 g_free (keyring_dir);
925 if (new_contents != NULL)
926 g_string_free (new_contents, TRUE);
931 /* ---------------------------------------------------------------------------------------------------- */
934 generate_sha1 (const gchar *server_challenge,
935 const gchar *client_challenge,
941 str = g_string_new (server_challenge);
942 g_string_append_c (str, ':');
943 g_string_append (str, client_challenge);
944 g_string_append_c (str, ':');
945 g_string_append (str, cookie);
946 sha1 = g_compute_checksum_for_string (G_CHECKSUM_SHA1, str->str, -1);
947 g_string_free (str, TRUE);
952 /* ---------------------------------------------------------------------------------------------------- */
954 static GDBusAuthMechanismState
955 mechanism_server_get_state (GDBusAuthMechanism *mechanism)
957 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
959 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID);
960 g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, G_DBUS_AUTH_MECHANISM_STATE_INVALID);
962 return m->priv->state;
966 mechanism_server_initiate (GDBusAuthMechanism *mechanism,
967 const gchar *initial_response,
968 gsize initial_response_len)
970 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
972 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
973 g_return_if_fail (!m->priv->is_server && !m->priv->is_client);
975 m->priv->is_server = TRUE;
976 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
978 if (initial_response != NULL && initial_response_len > 0)
984 uid = g_ascii_strtoll (initial_response, &endp, 10);
987 if (uid == getuid ())
989 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND;
992 #elif defined(G_OS_WIN32)
994 sid = _g_dbus_win32_get_user_sid ();
995 if (g_strcmp0 (initial_response, sid) == 0)
996 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND;
999 #error Please implement for your OS
1005 mechanism_server_data_receive (GDBusAuthMechanism *mechanism,
1009 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1011 const gchar *client_challenge;
1012 const gchar *alleged_sha1;
1015 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
1016 g_return_if_fail (m->priv->is_server && !m->priv->is_client);
1017 g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA);
1022 tokens = g_strsplit (data, " ", 0);
1023 if (g_strv_length (tokens) != 2)
1025 g_free (m->priv->reject_reason);
1026 m->priv->reject_reason = g_strdup_printf ("Malformed data '%s'", data);
1027 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1031 client_challenge = tokens[0];
1032 alleged_sha1 = tokens[1];
1034 sha1 = generate_sha1 (m->priv->server_challenge, client_challenge, m->priv->cookie);
1036 if (g_strcmp0 (sha1, alleged_sha1) == 0)
1038 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
1042 g_free (m->priv->reject_reason);
1043 m->priv->reject_reason = g_strdup_printf ("SHA-1 mismatch");
1044 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1048 g_strfreev (tokens);
1053 mechanism_server_data_send (GDBusAuthMechanism *mechanism,
1054 gsize *out_data_len)
1056 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1059 const gchar *cookie_context;
1062 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL);
1063 g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL);
1064 g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL);
1069 /* TODO: use GDBusAuthObserver here to get the cookie context to use? */
1070 cookie_context = "org_gtk_gdbus_general";
1074 if (!keyring_generate_entry (cookie_context,
1079 g_free (m->priv->reject_reason);
1080 m->priv->reject_reason = g_strdup_printf ("Error adding entry to keyring: %s", error->message);
1081 g_error_free (error);
1082 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1086 m->priv->server_challenge = random_ascii_string (16);
1087 s = g_strdup_printf ("%s %d %s",
1090 m->priv->server_challenge);
1091 *out_data_len = strlen (s);
1093 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA;
1100 mechanism_server_get_reject_reason (GDBusAuthMechanism *mechanism)
1102 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1104 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL);
1105 g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL);
1106 g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_REJECTED, NULL);
1108 return g_strdup (m->priv->reject_reason);
1112 mechanism_server_shutdown (GDBusAuthMechanism *mechanism)
1114 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1116 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
1117 g_return_if_fail (m->priv->is_server && !m->priv->is_client);
1119 m->priv->is_server = FALSE;
1122 /* ---------------------------------------------------------------------------------------------------- */
1124 static GDBusAuthMechanismState
1125 mechanism_client_get_state (GDBusAuthMechanism *mechanism)
1127 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1129 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID);
1130 g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, G_DBUS_AUTH_MECHANISM_STATE_INVALID);
1132 return m->priv->state;
1136 mechanism_client_initiate (GDBusAuthMechanism *mechanism,
1137 gsize *out_initial_response_len)
1139 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1140 gchar *initial_response;
1142 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL);
1143 g_return_val_if_fail (!m->priv->is_server && !m->priv->is_client, NULL);
1145 m->priv->is_client = TRUE;
1146 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA;
1148 *out_initial_response_len = 0;
1151 initial_response = g_strdup_printf ("%" G_GINT64_FORMAT, (gint64) getuid ());
1152 *out_initial_response_len = strlen (initial_response);
1153 #elif defined (G_OS_WIN32)
1154 initial_response = _g_dbus_win32_get_user_sid ();
1155 *out_initial_response_len = strlen (initial_response);
1157 #error Please implement for your OS
1159 g_assert (initial_response != NULL);
1161 return initial_response;
1165 mechanism_client_data_receive (GDBusAuthMechanism *mechanism,
1169 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1171 const gchar *cookie_context;
1173 const gchar *server_challenge;
1174 gchar *client_challenge;
1180 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
1181 g_return_if_fail (m->priv->is_client && !m->priv->is_server);
1182 g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA);
1186 client_challenge = NULL;
1188 tokens = g_strsplit (data, " ", 0);
1189 if (g_strv_length (tokens) != 3)
1191 g_free (m->priv->reject_reason);
1192 m->priv->reject_reason = g_strdup_printf ("Malformed data '%s'", data);
1193 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1197 cookie_context = tokens[0];
1198 cookie_id = g_ascii_strtoll (tokens[1], &endp, 10);
1201 g_free (m->priv->reject_reason);
1202 m->priv->reject_reason = g_strdup_printf ("Malformed cookie_id '%s'", tokens[1]);
1203 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1206 server_challenge = tokens[2];
1209 cookie = keyring_lookup_entry (cookie_context, cookie_id, &error);
1212 g_free (m->priv->reject_reason);
1213 m->priv->reject_reason = g_strdup_printf ("Problems looking up entry in keyring: %s", error->message);
1214 g_error_free (error);
1215 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1219 client_challenge = random_ascii_string (16);
1220 sha1 = generate_sha1 (server_challenge, client_challenge, cookie);
1221 m->priv->to_send = g_strdup_printf ("%s %s", client_challenge, sha1);
1223 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND;
1226 g_strfreev (tokens);
1228 g_free (client_challenge);
1232 mechanism_client_data_send (GDBusAuthMechanism *mechanism,
1233 gsize *out_data_len)
1235 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1237 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL);
1238 g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, NULL);
1239 g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL);
1241 g_assert (m->priv->to_send != NULL);
1243 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
1245 *out_data_len = strlen (m->priv->to_send);
1246 return g_strdup (m->priv->to_send);
1250 mechanism_client_shutdown (GDBusAuthMechanism *mechanism)
1252 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1254 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
1255 g_return_if_fail (m->priv->is_client && !m->priv->is_server);
1257 m->priv->is_client = FALSE;
1260 /* ---------------------------------------------------------------------------------------------------- */