1 /* GDBus - GLib D-Bus Library
3 * Copyright (C) 2008-2010 Red Hat, Inc.
5 * SPDX-License-Identifier: LGPL-2.1-or-later
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General
18 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 * Author: David Zeuthen <davidz@redhat.com>
28 #include <sys/types.h>
30 #include <glib/gstdio.h>
37 #include "gwin32sid.h"
44 #include "gdbusauthmechanismsha1.h"
45 #include "gcredentials.h"
46 #include "gdbuserror.h"
47 #include "glocalfileinfo.h"
48 #include "gioenumtypes.h"
50 #include "gdbusprivate.h"
51 #include "glib-private.h"
56 * Arbitrary timeouts for keys in the keyring.
57 * For interoperability, these match the reference implementation, libdbus.
58 * To make them easier to compare, their names also match libdbus
59 * (see dbus/dbus-keyring.c).
63 * Maximum age of a key before we create a new key to use in challenges:
66 #define NEW_KEY_TIMEOUT_SECONDS (60*5)
69 * Time before we drop a key from the keyring: 7 minutes.
70 * Authentication will succeed if it takes less than
71 * EXPIRE_KEYS_TIMEOUT_SECONDS - NEW_KEY_TIMEOUT_SECONDS (2 minutes)
73 * The spec says "delete any cookies that are old (the timeout can be
76 #define EXPIRE_KEYS_TIMEOUT_SECONDS (NEW_KEY_TIMEOUT_SECONDS + (60*2))
79 * Maximum amount of time a key can be in the future due to clock skew
80 * with a shared home directory: 5 minutes.
81 * The spec says "a reasonable time in the future".
83 #define MAX_TIME_TRAVEL_SECONDS (60*5)
86 struct _GDBusAuthMechanismSha1Private
90 GDBusAuthMechanismState state;
91 gchar *reject_reason; /* non-NULL iff (state == G_DBUS_AUTH_MECHANISM_STATE_REJECTED) */
93 /* used on the client side */
96 /* used on the server side */
98 gchar *server_challenge;
101 static gint mechanism_get_priority (void);
102 static const gchar *mechanism_get_name (void);
104 static gboolean mechanism_is_supported (GDBusAuthMechanism *mechanism);
105 static gchar *mechanism_encode_data (GDBusAuthMechanism *mechanism,
108 gsize *out_data_len);
109 static gchar *mechanism_decode_data (GDBusAuthMechanism *mechanism,
112 gsize *out_data_len);
113 static GDBusAuthMechanismState mechanism_server_get_state (GDBusAuthMechanism *mechanism);
114 static void mechanism_server_initiate (GDBusAuthMechanism *mechanism,
115 const gchar *initial_response,
116 gsize initial_response_len);
117 static void mechanism_server_data_receive (GDBusAuthMechanism *mechanism,
120 static gchar *mechanism_server_data_send (GDBusAuthMechanism *mechanism,
121 gsize *out_data_len);
122 static gchar *mechanism_server_get_reject_reason (GDBusAuthMechanism *mechanism);
123 static void mechanism_server_shutdown (GDBusAuthMechanism *mechanism);
124 static GDBusAuthMechanismState mechanism_client_get_state (GDBusAuthMechanism *mechanism);
125 static gchar *mechanism_client_initiate (GDBusAuthMechanism *mechanism,
126 GDBusConnectionFlags conn_flags,
127 gsize *out_initial_response_len);
128 static void mechanism_client_data_receive (GDBusAuthMechanism *mechanism,
131 static gchar *mechanism_client_data_send (GDBusAuthMechanism *mechanism,
132 gsize *out_data_len);
133 static void mechanism_client_shutdown (GDBusAuthMechanism *mechanism);
135 /* ---------------------------------------------------------------------------------------------------- */
137 G_DEFINE_TYPE_WITH_PRIVATE (GDBusAuthMechanismSha1, _g_dbus_auth_mechanism_sha1, G_TYPE_DBUS_AUTH_MECHANISM)
139 /* ---------------------------------------------------------------------------------------------------- */
142 _g_dbus_auth_mechanism_sha1_finalize (GObject *object)
144 GDBusAuthMechanismSha1 *mechanism = G_DBUS_AUTH_MECHANISM_SHA1 (object);
146 g_free (mechanism->priv->reject_reason);
147 g_free (mechanism->priv->to_send);
149 g_free (mechanism->priv->cookie);
150 g_free (mechanism->priv->server_challenge);
152 if (G_OBJECT_CLASS (_g_dbus_auth_mechanism_sha1_parent_class)->finalize != NULL)
153 G_OBJECT_CLASS (_g_dbus_auth_mechanism_sha1_parent_class)->finalize (object);
157 _g_dbus_auth_mechanism_sha1_class_init (GDBusAuthMechanismSha1Class *klass)
159 GObjectClass *gobject_class;
160 GDBusAuthMechanismClass *mechanism_class;
162 gobject_class = G_OBJECT_CLASS (klass);
163 gobject_class->finalize = _g_dbus_auth_mechanism_sha1_finalize;
165 mechanism_class = G_DBUS_AUTH_MECHANISM_CLASS (klass);
166 mechanism_class->get_priority = mechanism_get_priority;
167 mechanism_class->get_name = mechanism_get_name;
168 mechanism_class->is_supported = mechanism_is_supported;
169 mechanism_class->encode_data = mechanism_encode_data;
170 mechanism_class->decode_data = mechanism_decode_data;
171 mechanism_class->server_get_state = mechanism_server_get_state;
172 mechanism_class->server_initiate = mechanism_server_initiate;
173 mechanism_class->server_data_receive = mechanism_server_data_receive;
174 mechanism_class->server_data_send = mechanism_server_data_send;
175 mechanism_class->server_get_reject_reason = mechanism_server_get_reject_reason;
176 mechanism_class->server_shutdown = mechanism_server_shutdown;
177 mechanism_class->client_get_state = mechanism_client_get_state;
178 mechanism_class->client_initiate = mechanism_client_initiate;
179 mechanism_class->client_data_receive = mechanism_client_data_receive;
180 mechanism_class->client_data_send = mechanism_client_data_send;
181 mechanism_class->client_shutdown = mechanism_client_shutdown;
185 _g_dbus_auth_mechanism_sha1_init (GDBusAuthMechanismSha1 *mechanism)
187 mechanism->priv = _g_dbus_auth_mechanism_sha1_get_instance_private (mechanism);
190 /* ---------------------------------------------------------------------------------------------------- */
193 mechanism_get_priority (void)
199 mechanism_get_name (void)
201 return "DBUS_COOKIE_SHA1";
205 mechanism_is_supported (GDBusAuthMechanism *mechanism)
207 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), FALSE);
212 mechanism_encode_data (GDBusAuthMechanism *mechanism,
222 mechanism_decode_data (GDBusAuthMechanism *mechanism,
230 /* ---------------------------------------------------------------------------------------------------- */
236 ret = g_random_int_range (0, 60);
247 random_ascii_string (guint len)
252 challenge = g_string_new (NULL);
253 for (n = 0; n < len; n++)
254 g_string_append_c (challenge, random_ascii ());
255 return g_string_free (challenge, FALSE);
259 random_blob (guint len)
264 challenge = g_string_new (NULL);
265 for (n = 0; n < len; n++)
266 g_string_append_c (challenge, g_random_int_range (0, 256));
267 return g_string_free (challenge, FALSE);
270 /* ---------------------------------------------------------------------------------------------------- */
272 /* ensure keyring dir exists and permissions are correct */
274 ensure_keyring_directory (GError **error)
283 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
285 e = g_getenv ("G_DBUS_COOKIE_SHA1_KEYRING_DIR");
292 path = g_build_filename (g_get_home_dir (),
298 if (stat (path, &statbuf) != 0)
306 g_io_error_from_errno (errsv),
307 _("Error when getting information for directory “%s”: %s"),
310 g_clear_pointer (&path, g_free);
314 else if (S_ISDIR (statbuf.st_mode))
316 if (g_getenv ("G_DBUS_COOKIE_SHA1_KEYRING_DIR_IGNORE_PERMISSION") == NULL &&
317 (statbuf.st_mode & 0777) != 0700)
322 _("Permissions on directory “%s” are malformed. Expected mode 0700, got 0%o"),
324 (guint) (statbuf.st_mode & 0777));
325 g_clear_pointer (&path, g_free);
329 return g_steal_pointer (&path);
331 #else /* if !G_OS_UNIX */
332 /* On non-Unix platforms, check that it exists as a directory, but don’t do
333 * permissions checks at the moment. */
334 if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
337 #pragma GCC diagnostic push
338 #pragma GCC diagnostic warning "-Wcpp"
339 #warning Please implement permission checking on this non-UNIX platform
340 #pragma GCC diagnostic pop
341 #endif /* __GNUC__ */
342 return g_steal_pointer (&path);
344 #endif /* if !G_OS_UNIX */
346 /* Only create the directory if not running as setuid */
347 is_setuid = GLIB_PRIVATE_CALL (g_check_setuid) ();
349 g_mkdir_with_parents (path, 0700) != 0)
354 g_io_error_from_errno (errsv),
355 _("Error creating directory “%s”: %s"),
358 g_clear_pointer (&path, g_free);
365 G_IO_ERROR_PERMISSION_DENIED,
366 _("Error creating directory “%s”: %s"),
368 _("Operation not supported"));
369 g_clear_pointer (&path, g_free);
373 return g_steal_pointer (&path);
376 /* ---------------------------------------------------------------------------------------------------- */
378 /* looks up an entry in the keyring */
380 keyring_lookup_entry (const gchar *cookie_context,
391 g_return_val_if_fail (cookie_context != NULL, NULL);
392 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
399 keyring_dir = ensure_keyring_directory (error);
400 if (keyring_dir == NULL)
403 path = g_build_filename (keyring_dir, cookie_context, NULL);
405 if (!g_file_get_contents (path,
410 g_prefix_error (error,
411 _("Error opening keyring “%s” for reading: "),
415 g_assert (contents != NULL);
417 lines = g_strsplit (contents, "\n", 0);
418 for (n = 0; lines[n] != NULL; n++)
420 const gchar *line = lines[n];
428 tokens = g_strsplit (line, " ", 0);
429 if (g_strv_length (tokens) != 3)
434 _("Line %d of the keyring at “%s” with content “%s” is malformed"),
442 line_id = g_ascii_strtoll (tokens[0], &endp, 10);
448 _("First token of line %d of the keyring at “%s” with content “%s” is malformed"),
456 (void)g_ascii_strtoll (tokens[1], &endp, 10); /* do not care what the timestamp is */
462 _("Second token of line %d of the keyring at “%s” with content “%s” is malformed"),
470 if (line_id == cookie_id)
473 ret = tokens[2]; /* steal pointer */
482 /* BOOH, didn't find the cookie */
486 _("Didn’t find cookie with id %d in the keyring at “%s”"),
491 g_free (keyring_dir);
498 /* function for logging important events that the system administrator should take notice of */
501 _log (const gchar *message,
507 va_start (var_args, message);
508 s = g_strdup_vprintf (message, var_args);
511 /* TODO: might want to send this to syslog instead */
512 g_printerr ("GDBus-DBUS_COOKIE_SHA1: %s\n", s);
516 /* Returns FD for lock file, if it was created exclusively (didn't exist already,
517 * and was created successfully) */
519 create_lock_exclusive (const gchar *lock_path,
526 ret = g_open (lock_path, O_CREAT | O_EXCL | O_CLOEXEC, 0600);
530 GLocalFileStat stat_buf;
532 /* Get the modification time to distinguish between the lock being stale
533 * or highly contested. */
534 if (mtime_nsec != NULL &&
535 g_local_file_stat (lock_path, G_LOCAL_FILE_STAT_FIELD_MTIME, G_LOCAL_FILE_STAT_FIELD_ALL, &stat_buf) == 0)
536 *mtime_nsec = _g_stat_mtime (&stat_buf) * G_USEC_PER_SEC * 1000 + _g_stat_mtim_nsec (&stat_buf);
537 else if (mtime_nsec != NULL)
542 g_io_error_from_errno (errsv),
543 _("Error creating lock file “%s”: %s"),
553 keyring_acquire_lock (const gchar *path,
560 gint64 lock_mtime_nsec = 0, lock_mtime_nsec_prev = 0;
562 /* Total possible sleep period = max_tries * timeout_usec = 0.5s */
563 const guint max_tries = 50;
564 const guint timeout_usec = 1000 * 10;
566 g_return_val_if_fail (path != NULL, -1);
567 g_return_val_if_fail (error == NULL || *error == NULL, -1);
570 lock = g_strconcat (path, ".lock", NULL);
572 /* This is what the D-Bus spec says
573 * (https://dbus.freedesktop.org/doc/dbus-specification.html#auth-mechanisms-sha)
575 * Create a lockfile name by appending ".lock" to the name of the
576 * cookie file. The server should attempt to create this file using
577 * O_CREAT | O_EXCL. If file creation fails, the lock
578 * fails. Servers should retry for a reasonable period of time,
579 * then they may choose to delete an existing lock to keep users
580 * from having to manually delete a stale lock. [1]
582 * [1] : Lockfiles are used instead of real file locking fcntl() because
583 * real locking implementations are still flaky on network filesystems
586 for (num_tries = 0; num_tries < max_tries; num_tries++)
588 lock_mtime_nsec_prev = lock_mtime_nsec;
590 /* Ignore the error until the final call. */
591 ret = create_lock_exclusive (lock, &lock_mtime_nsec, NULL);
595 /* sleep 10ms, then try again */
596 g_usleep (timeout_usec);
598 /* If the mtime of the lock file changed, don’t count the retry, as it
599 * seems like there’s contention between processes for the lock file,
600 * rather than a stale lock file from a crashed process. */
601 if (num_tries > 0 && lock_mtime_nsec != lock_mtime_nsec_prev)
605 if (num_tries == max_tries)
607 /* ok, we slept 50*10ms = 0.5 seconds. Conclude that the lock file must be
608 * stale (nuke it from orbit)
610 if (g_unlink (lock) != 0)
615 g_io_error_from_errno (errsv),
616 _("Error deleting stale lock file “%s”: %s"),
622 _log ("Deleted stale lock file '%s'", lock);
624 /* Try one last time to create it, now that we've deleted the stale one */
625 ret = create_lock_exclusive (lock, NULL, error);
636 keyring_release_lock (const gchar *path,
643 g_return_val_if_fail (path != NULL, FALSE);
644 g_return_val_if_fail (lock_fd != -1, FALSE);
645 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
648 lock = g_strdup_printf ("%s.lock", path);
649 if (close (lock_fd) != 0)
654 g_io_error_from_errno (errsv),
655 _("Error closing (unlinked) lock file “%s”: %s"),
660 if (g_unlink (lock) != 0)
665 g_io_error_from_errno (errsv),
666 _("Error unlinking lock file “%s”: %s"),
680 /* adds an entry to the keyring, taking care of locking and deleting stale/future entries */
682 keyring_generate_entry (const gchar *cookie_context,
691 GError *local_error = NULL;
694 GString *new_contents;
699 gboolean changed_file;
702 g_return_val_if_fail (cookie_context != NULL, FALSE);
703 g_return_val_if_fail (out_id != NULL, FALSE);
704 g_return_val_if_fail (out_cookie != NULL, FALSE);
705 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
717 keyring_dir = ensure_keyring_directory (error);
718 if (keyring_dir == NULL)
721 path = g_build_filename (keyring_dir, cookie_context, NULL);
723 lock_fd = keyring_acquire_lock (path, error);
728 if (!g_file_get_contents (path,
733 if (local_error->domain == G_FILE_ERROR && local_error->code == G_FILE_ERROR_NOENT)
735 /* file doesn't have to exist */
736 g_clear_error (&local_error);
740 g_propagate_prefixed_error (error,
741 g_steal_pointer (&local_error),
742 _("Error opening keyring “%s” for writing: "),
748 new_contents = g_string_new (NULL);
749 now = g_get_real_time () / G_USEC_PER_SEC;
750 changed_file = FALSE;
753 if (contents != NULL)
756 lines = g_strsplit (contents, "\n", 0);
757 for (n = 0; lines[n] != NULL; n++)
759 const gchar *line = lines[n];
769 tokens = g_strsplit (line, " ", 0);
770 if (g_strv_length (tokens) != 3)
775 _("Line %d of the keyring at “%s” with content “%s” is malformed"),
783 line_id = g_ascii_strtoll (tokens[0], &endp, 10);
789 _("First token of line %d of the keyring at “%s” with content “%s” is malformed"),
797 line_when = g_ascii_strtoll (tokens[1], &endp, 10);
803 _("Second token of line %d of the keyring at “%s” with content “%s” is malformed"),
814 * Once the lockfile has been created, the server loads the
815 * cookie file. It should then delete any cookies that are
816 * old (the timeout can be fairly short), or more than a
817 * reasonable time in the future (so that cookies never
818 * accidentally become permanent, if the clock was set far
819 * into the future at some point). If no recent keys remain,
820 * the server may generate a new key.
826 /* Oddball case: entry is more recent than our current wall-clock time..
827 * This is OK, it means that another server on another machine but with
828 * same $HOME wrote the entry. */
829 if (line_when - now > MAX_TIME_TRAVEL_SECONDS)
832 _log ("Deleted SHA1 cookie from %" G_GUINT64_FORMAT " seconds in the future", line_when - now);
837 /* Discard entry if it's too old. */
838 if (now - line_when > EXPIRE_KEYS_TIMEOUT_SECONDS)
846 changed_file = FALSE;
850 g_string_append_printf (new_contents,
851 "%d %" G_GUINT64_FORMAT " %s\n",
855 max_line_id = MAX (line_id, max_line_id);
856 /* Only reuse entry if not older than 5 minutes.
858 * (We need a bit of grace time compared to 7 minutes above.. otherwise
859 * there's a race where we reuse the 6min59.9 secs old entry and a
860 * split-second later another server purges the now 7 minute old entry.)
862 if (now - line_when < NEW_KEY_TIMEOUT_SECONDS)
867 use_cookie = tokens[2]; /* steal memory */
875 } /* for each line */
882 *out_cookie = use_cookie;
888 *out_id = max_line_id + 1;
889 raw_cookie = random_blob (32);
890 *out_cookie = _g_dbus_hexencode (raw_cookie, 32);
893 g_string_append_printf (new_contents,
894 "%d %" G_GINT64_FORMAT " %s\n",
896 g_get_real_time () / G_USEC_PER_SEC,
901 /* and now actually write the cookie file if there are changes (this is atomic) */
904 if (!g_file_set_contents_full (path,
907 G_FILE_SET_CONTENTS_CONSISTENT,
912 g_free (*out_cookie);
920 /* Any error should have been propagated to @error by now */
921 g_assert (local_error == NULL);
925 if (!keyring_release_lock (path, lock_fd, &local_error))
931 *error = local_error;
935 g_prefix_error (error,
936 _("(Additionally, releasing the lock for “%s” also failed: %s) "),
938 local_error->message);
939 g_error_free (local_error);
944 g_error_free (local_error);
949 g_free (keyring_dir);
953 if (new_contents != NULL)
954 g_string_free (new_contents, TRUE);
959 /* ---------------------------------------------------------------------------------------------------- */
962 generate_sha1 (const gchar *server_challenge,
963 const gchar *client_challenge,
969 str = g_string_new (server_challenge);
970 g_string_append_c (str, ':');
971 g_string_append (str, client_challenge);
972 g_string_append_c (str, ':');
973 g_string_append (str, cookie);
974 sha1 = g_compute_checksum_for_string (G_CHECKSUM_SHA1, str->str, -1);
975 g_string_free (str, TRUE);
980 /* ---------------------------------------------------------------------------------------------------- */
982 static GDBusAuthMechanismState
983 mechanism_server_get_state (GDBusAuthMechanism *mechanism)
985 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
987 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID);
988 g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, G_DBUS_AUTH_MECHANISM_STATE_INVALID);
990 return m->priv->state;
994 mechanism_server_initiate (GDBusAuthMechanism *mechanism,
995 const gchar *initial_response,
996 gsize initial_response_len)
998 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1000 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
1001 g_return_if_fail (!m->priv->is_server && !m->priv->is_client);
1003 m->priv->is_server = TRUE;
1004 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1006 if (initial_response != NULL && initial_response_len > 0)
1012 uid = g_ascii_strtoll (initial_response, &endp, 10);
1015 if (uid == getuid ())
1017 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND;
1020 #elif defined(G_OS_WIN32)
1023 sid = _g_win32_current_process_sid_string (NULL);
1025 if (g_strcmp0 (initial_response, sid) == 0)
1026 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND;
1030 #error Please implement for your OS
1036 mechanism_server_data_receive (GDBusAuthMechanism *mechanism,
1040 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1042 const gchar *client_challenge;
1043 const gchar *alleged_sha1;
1046 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
1047 g_return_if_fail (m->priv->is_server && !m->priv->is_client);
1048 g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA);
1053 tokens = g_strsplit (data, " ", 0);
1054 if (g_strv_length (tokens) != 2)
1056 g_free (m->priv->reject_reason);
1057 m->priv->reject_reason = g_strdup_printf ("Malformed data '%s'", data);
1058 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1062 client_challenge = tokens[0];
1063 alleged_sha1 = tokens[1];
1065 sha1 = generate_sha1 (m->priv->server_challenge, client_challenge, m->priv->cookie);
1067 if (g_strcmp0 (sha1, alleged_sha1) == 0)
1069 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
1073 g_free (m->priv->reject_reason);
1074 m->priv->reject_reason = g_strdup_printf ("SHA-1 mismatch");
1075 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1079 g_strfreev (tokens);
1084 mechanism_server_data_send (GDBusAuthMechanism *mechanism,
1085 gsize *out_data_len)
1087 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1090 const gchar *cookie_context;
1093 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL);
1094 g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL);
1095 g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL);
1100 /* TODO: use GDBusAuthObserver here to get the cookie context to use? */
1101 cookie_context = "org_gtk_gdbus_general";
1105 if (!keyring_generate_entry (cookie_context,
1110 g_free (m->priv->reject_reason);
1111 m->priv->reject_reason = g_strdup_printf ("Error adding entry to keyring: %s", error->message);
1112 g_error_free (error);
1113 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1117 m->priv->server_challenge = random_ascii_string (16);
1118 s = g_strdup_printf ("%s %d %s",
1121 m->priv->server_challenge);
1122 *out_data_len = strlen (s);
1124 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA;
1131 mechanism_server_get_reject_reason (GDBusAuthMechanism *mechanism)
1133 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1135 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL);
1136 g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL);
1137 g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_REJECTED, NULL);
1139 return g_strdup (m->priv->reject_reason);
1143 mechanism_server_shutdown (GDBusAuthMechanism *mechanism)
1145 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1147 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
1148 g_return_if_fail (m->priv->is_server && !m->priv->is_client);
1150 m->priv->is_server = FALSE;
1153 /* ---------------------------------------------------------------------------------------------------- */
1155 static GDBusAuthMechanismState
1156 mechanism_client_get_state (GDBusAuthMechanism *mechanism)
1158 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1160 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), G_DBUS_AUTH_MECHANISM_STATE_INVALID);
1161 g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, G_DBUS_AUTH_MECHANISM_STATE_INVALID);
1163 return m->priv->state;
1167 mechanism_client_initiate (GDBusAuthMechanism *mechanism,
1168 GDBusConnectionFlags conn_flags,
1169 gsize *out_initial_response_len)
1171 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1172 gchar *initial_response;
1174 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL);
1175 g_return_val_if_fail (!m->priv->is_server && !m->priv->is_client, NULL);
1177 m->priv->is_client = TRUE;
1179 *out_initial_response_len = 0;
1182 initial_response = g_strdup_printf ("%" G_GINT64_FORMAT, (gint64) getuid ());
1183 #elif defined (G_OS_WIN32)
1184 initial_response = _g_win32_current_process_sid_string (NULL);
1186 #error Please implement for your OS
1188 if (initial_response)
1190 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA;
1191 *out_initial_response_len = strlen (initial_response);
1195 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1198 return initial_response;
1202 mechanism_client_data_receive (GDBusAuthMechanism *mechanism,
1206 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1208 const gchar *cookie_context;
1210 const gchar *server_challenge;
1211 gchar *client_challenge;
1217 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
1218 g_return_if_fail (m->priv->is_client && !m->priv->is_server);
1219 g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA);
1223 client_challenge = NULL;
1225 tokens = g_strsplit (data, " ", 0);
1226 if (g_strv_length (tokens) != 3)
1228 g_free (m->priv->reject_reason);
1229 m->priv->reject_reason = g_strdup_printf ("Malformed data '%s'", data);
1230 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1234 cookie_context = tokens[0];
1235 cookie_id = g_ascii_strtoll (tokens[1], &endp, 10);
1238 g_free (m->priv->reject_reason);
1239 m->priv->reject_reason = g_strdup_printf ("Malformed cookie_id '%s'", tokens[1]);
1240 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1243 server_challenge = tokens[2];
1246 cookie = keyring_lookup_entry (cookie_context, cookie_id, &error);
1249 g_free (m->priv->reject_reason);
1250 m->priv->reject_reason = g_strdup_printf ("Problems looking up entry in keyring: %s", error->message);
1251 g_error_free (error);
1252 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
1256 client_challenge = random_ascii_string (16);
1257 sha1 = generate_sha1 (server_challenge, client_challenge, cookie);
1258 m->priv->to_send = g_strdup_printf ("%s %s", client_challenge, sha1);
1260 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND;
1263 g_strfreev (tokens);
1265 g_free (client_challenge);
1269 mechanism_client_data_send (GDBusAuthMechanism *mechanism,
1270 gsize *out_data_len)
1272 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1274 g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism), NULL);
1275 g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, NULL);
1276 g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL);
1278 g_assert (m->priv->to_send != NULL);
1280 m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
1282 *out_data_len = strlen (m->priv->to_send);
1283 return g_strdup (m->priv->to_send);
1287 mechanism_client_shutdown (GDBusAuthMechanism *mechanism)
1289 GDBusAuthMechanismSha1 *m = G_DBUS_AUTH_MECHANISM_SHA1 (mechanism);
1291 g_return_if_fail (G_IS_DBUS_AUTH_MECHANISM_SHA1 (mechanism));
1292 g_return_if_fail (m->priv->is_client && !m->priv->is_server);
1294 m->priv->is_client = FALSE;
1297 /* ---------------------------------------------------------------------------------------------------- */