Coverage Report

Created: 2026-10-14 08:19

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