Coverage Report

Created: 2026-09-03 06:40

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