1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2/* dbus-keyring.c Store secret cookies in your homedir
3 *
4 * Copyright (C) 2003, 2004  Red Hat Inc.
5 *
6 * Licensed under the Academic Free License version 2.1
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21 *
22 */
23
24#include <config.h>
25#include "dbus-keyring.h"
26#include "dbus-protocol.h"
27#include <dbus/dbus-string.h>
28#include <dbus/dbus-list.h>
29#include <dbus/dbus-sysdeps.h>
30
31/**
32 * @defgroup DBusKeyring keyring class
33 * @ingroup  DBusInternals
34 * @brief DBusKeyring data structure
35 *
36 * Types and functions related to DBusKeyring. DBusKeyring is intended
37 * to manage cookies used to authenticate clients to servers.  This is
38 * essentially the "verify that client can read the user's homedir"
39 * authentication mechanism.  Both client and server must have access
40 * to the homedir.
41 *
42 * The secret keys are not kept in locked memory, and are written to a
43 * file in the user's homedir. However they are transient (only used
44 * by a single server instance for a fixed period of time, then
45 * discarded). Also, the keys are not sent over the wire.
46 *
47 * @todo there's a memory leak on some codepath in here, I saw it once
48 * when running make check - probably some specific initial cookies
49 * present in the cookie file, then depending on what we do with them.
50 */
51
52/**
53 * @defgroup DBusKeyringInternals DBusKeyring implementation details
54 * @ingroup  DBusInternals
55 * @brief DBusKeyring implementation details
56 *
57 * The guts of DBusKeyring.
58 *
59 * @{
60 */
61
62/** The maximum age of a key before we create a new key to use in
63 * challenges.  This isn't super-reliably enforced, since system
64 * clocks can change or be wrong, but we make a best effort to only
65 * use keys for a short time.
66 */
67#define NEW_KEY_TIMEOUT_SECONDS     (60*5)
68/**
69 * The time after which we drop a key from the secrets file.
70 * The EXPIRE_KEYS_TIMEOUT_SECONDS - NEW_KEY_TIMEOUT_SECONDS is the minimum
71 * time window a client has to complete authentication.
72 */
73#define EXPIRE_KEYS_TIMEOUT_SECONDS (NEW_KEY_TIMEOUT_SECONDS + (60*2))
74/**
75 * The maximum amount of time a key can be in the future.
76 */
77#define MAX_TIME_TRAVEL_SECONDS (60*5)
78
79/**
80 * Maximum number of keys in the keyring before
81 * we just ignore the rest
82 */
83#ifdef DBUS_BUILD_TESTS
84#define MAX_KEYS_IN_FILE 10
85#else
86#define MAX_KEYS_IN_FILE 256
87#endif
88
89/**
90 * A single key from the cookie file
91 */
92typedef struct
93{
94  dbus_int32_t id; /**< identifier used to refer to the key */
95
96  long creation_time; /**< when the key was generated,
97                       *   as unix timestamp. signed long
98                       *   matches struct timeval.
99                       */
100
101  DBusString secret; /**< the actual key */
102
103} DBusKey;
104
105/**
106 * @brief Internals of DBusKeyring.
107 *
108 * DBusKeyring internals. DBusKeyring is an opaque object, it must be
109 * used via accessor functions.
110 */
111struct DBusKeyring
112{
113  int refcount;             /**< Reference count */
114  DBusString directory;     /**< Directory the below two items are inside */
115  DBusString filename;      /**< Keyring filename */
116  DBusString filename_lock; /**< Name of lockfile */
117  DBusKey *keys; /**< Keys loaded from the file */
118  int n_keys;    /**< Number of keys */
119  DBusCredentials *credentials; /**< Credentials containing user the keyring is for */
120};
121
122static DBusKeyring*
123_dbus_keyring_new (void)
124{
125  DBusKeyring *keyring;
126
127  keyring = dbus_new0 (DBusKeyring, 1);
128  if (keyring == NULL)
129    goto out_0;
130
131  if (!_dbus_string_init (&keyring->directory))
132    goto out_1;
133
134  if (!_dbus_string_init (&keyring->filename))
135    goto out_2;
136
137  if (!_dbus_string_init (&keyring->filename_lock))
138    goto out_3;
139
140  keyring->refcount = 1;
141  keyring->keys = NULL;
142  keyring->n_keys = 0;
143
144  return keyring;
145
146 out_3:
147  _dbus_string_free (&keyring->filename);
148 out_2:
149  _dbus_string_free (&keyring->directory);
150 out_1:
151  dbus_free (keyring);
152 out_0:
153  return NULL;
154}
155
156static void
157free_keys (DBusKey *keys,
158           int      n_keys)
159{
160  int i;
161
162  /* should be safe for args NULL, 0 */
163
164  i = 0;
165  while (i < n_keys)
166    {
167      _dbus_string_free (&keys[i].secret);
168      ++i;
169    }
170
171  dbus_free (keys);
172}
173
174/* Our locking scheme is highly unreliable.  However, there is
175 * unfortunately no reliable locking scheme in user home directories;
176 * between bugs in Linux NFS, people using Tru64 or other total crap
177 * NFS, AFS, random-file-system-of-the-week, and so forth, fcntl() in
178 * homedirs simply generates tons of bug reports. This has been
179 * learned through hard experience with GConf, unfortunately.
180 *
181 * This bad hack might work better for the kind of lock we have here,
182 * which we don't expect to hold for any length of time.  Crashing
183 * while we hold it should be unlikely, and timing out such that we
184 * delete a stale lock should also be unlikely except when the
185 * filesystem is running really slowly.  Stuff might break in corner
186 * cases but as long as it's not a security-level breakage it should
187 * be OK.
188 */
189
190/** Maximum number of timeouts waiting for lock before we decide it's stale */
191#define MAX_LOCK_TIMEOUTS 32
192/** Length of each timeout while waiting for a lock */
193#define LOCK_TIMEOUT_MILLISECONDS 250
194
195static dbus_bool_t
196_dbus_keyring_lock (DBusKeyring *keyring)
197{
198  int n_timeouts;
199
200  n_timeouts = 0;
201  while (n_timeouts < MAX_LOCK_TIMEOUTS)
202    {
203      DBusError error = DBUS_ERROR_INIT;
204
205      if (_dbus_create_file_exclusively (&keyring->filename_lock,
206                                         &error))
207        break;
208
209      _dbus_verbose ("Did not get lock file, sleeping %d milliseconds (%s)\n",
210                     LOCK_TIMEOUT_MILLISECONDS, error.message);
211      dbus_error_free (&error);
212
213      _dbus_sleep_milliseconds (LOCK_TIMEOUT_MILLISECONDS);
214
215      ++n_timeouts;
216    }
217
218  if (n_timeouts == MAX_LOCK_TIMEOUTS)
219    {
220      DBusError error = DBUS_ERROR_INIT;
221
222      _dbus_verbose ("Lock file timed out %d times, assuming stale\n",
223                     n_timeouts);
224
225      if (!_dbus_delete_file (&keyring->filename_lock, &error))
226        {
227          _dbus_verbose ("Couldn't delete old lock file: %s\n",
228                         error.message);
229          dbus_error_free (&error);
230          return FALSE;
231        }
232
233      if (!_dbus_create_file_exclusively (&keyring->filename_lock,
234                                          &error))
235        {
236          _dbus_verbose ("Couldn't create lock file after deleting stale one: %s\n",
237                         error.message);
238          dbus_error_free (&error);
239          return FALSE;
240        }
241    }
242
243  return TRUE;
244}
245
246static void
247_dbus_keyring_unlock (DBusKeyring *keyring)
248{
249  DBusError error = DBUS_ERROR_INIT;
250
251  if (!_dbus_delete_file (&keyring->filename_lock, &error))
252    {
253      _dbus_warn ("Failed to delete lock file: %s\n",
254                  error.message);
255      dbus_error_free (&error);
256    }
257}
258
259static DBusKey*
260find_key_by_id (DBusKey *keys,
261                int      n_keys,
262                int      id)
263{
264  int i;
265
266  i = 0;
267  while (i < n_keys)
268    {
269      if (keys[i].id == id)
270        return &keys[i];
271
272      ++i;
273    }
274
275  return NULL;
276}
277
278static dbus_bool_t
279add_new_key (DBusKey  **keys_p,
280             int       *n_keys_p,
281             DBusError *error)
282{
283  DBusKey *new;
284  DBusString bytes;
285  int id;
286  long timestamp;
287  const unsigned char *s;
288  dbus_bool_t retval;
289  DBusKey *keys;
290  int n_keys;
291
292  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
293
294  if (!_dbus_string_init (&bytes))
295    {
296      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
297      return FALSE;
298    }
299
300  keys = *keys_p;
301  n_keys = *n_keys_p;
302  retval = FALSE;
303
304  /* Generate an integer ID and then the actual key. */
305 retry:
306
307  if (!_dbus_generate_random_bytes (&bytes, 4))
308    {
309      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
310      goto out;
311    }
312
313  s = (const unsigned char*) _dbus_string_get_const_data (&bytes);
314
315  id = s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24);
316  if (id < 0)
317    id = - id;
318  _dbus_assert (id >= 0);
319
320  if (find_key_by_id (keys, n_keys, id) != NULL)
321    {
322      _dbus_string_set_length (&bytes, 0);
323      _dbus_verbose ("Key ID %d already existed, trying another one\n",
324                     id);
325      goto retry;
326    }
327
328  _dbus_verbose ("Creating key with ID %d\n", id);
329
330#define KEY_LENGTH_BYTES 24
331  _dbus_string_set_length (&bytes, 0);
332  if (!_dbus_generate_random_bytes (&bytes, KEY_LENGTH_BYTES))
333    {
334      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
335      goto out;
336    }
337
338  new = dbus_realloc (keys, sizeof (DBusKey) * (n_keys + 1));
339  if (new == NULL)
340    {
341      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
342      goto out;
343    }
344
345  keys = new;
346  *keys_p = keys; /* otherwise *keys_p ends up invalid */
347  n_keys += 1;
348
349  if (!_dbus_string_init (&keys[n_keys-1].secret))
350    {
351      n_keys -= 1; /* we don't want to free the one we didn't init */
352      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
353      goto out;
354    }
355
356  _dbus_get_real_time (&timestamp, NULL);
357
358  keys[n_keys-1].id = id;
359  keys[n_keys-1].creation_time = timestamp;
360  if (!_dbus_string_move (&bytes, 0,
361                          &keys[n_keys-1].secret,
362                          0))
363    {
364      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
365      _dbus_string_free (&keys[n_keys-1].secret);
366      n_keys -= 1;
367      goto out;
368    }
369
370  retval = TRUE;
371
372 out:
373  *n_keys_p = n_keys;
374
375  _dbus_string_free (&bytes);
376  return retval;
377}
378
379/**
380 * Reloads the keyring file, optionally adds one new key to the file,
381 * removes all expired keys from the file iff a key was added, then
382 * resaves the file.  Stores the keys from the file in keyring->keys.
383 * Note that the file is only resaved (written to) if a key is added,
384 * this means that only servers ever write to the file and need to
385 * lock it, which avoids a lot of lock contention at login time and
386 * such.
387 *
388 * @param keyring the keyring
389 * @param add_new #TRUE to add a new key to the file, expire keys, and resave
390 * @param error return location for errors
391 * @returns #FALSE on failure
392 */
393static dbus_bool_t
394_dbus_keyring_reload (DBusKeyring *keyring,
395                      dbus_bool_t  add_new,
396                      DBusError   *error)
397{
398  DBusString contents;
399  DBusString line;
400  dbus_bool_t retval;
401  dbus_bool_t have_lock;
402  DBusKey *keys;
403  int n_keys;
404  int i;
405  long now;
406  DBusError tmp_error;
407
408  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
409
410  if (!_dbus_check_dir_is_private_to_user (&keyring->directory, error))
411    return FALSE;
412
413  if (!_dbus_string_init (&contents))
414    {
415      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
416      return FALSE;
417    }
418
419  if (!_dbus_string_init (&line))
420    {
421      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
422      _dbus_string_free (&contents);
423      return FALSE;
424    }
425
426  keys = NULL;
427  n_keys = 0;
428  retval = FALSE;
429  have_lock = FALSE;
430
431  _dbus_get_real_time (&now, NULL);
432
433  if (add_new)
434    {
435      if (!_dbus_keyring_lock (keyring))
436        {
437          dbus_set_error (error, DBUS_ERROR_FAILED,
438                          "Could not lock keyring file to add to it");
439          goto out;
440        }
441
442      have_lock = TRUE;
443    }
444
445  dbus_error_init (&tmp_error);
446  if (!_dbus_file_get_contents (&contents,
447                                &keyring->filename,
448                                &tmp_error))
449    {
450      _dbus_verbose ("Failed to load keyring file: %s\n",
451                     tmp_error.message);
452      /* continue with empty keyring file, so we recreate it */
453      dbus_error_free (&tmp_error);
454    }
455
456  if (!_dbus_string_validate_ascii (&contents, 0,
457                                    _dbus_string_get_length (&contents)))
458    {
459      _dbus_warn ("Secret keyring file contains non-ASCII! Ignoring existing contents\n");
460      _dbus_string_set_length (&contents, 0);
461    }
462
463  /* FIXME this is badly inefficient for large keyring files
464   * (not that large keyring files exist outside of test suites)
465   */
466  while (_dbus_string_pop_line (&contents, &line))
467    {
468      int next;
469      long val;
470      int id;
471      long timestamp;
472      int len;
473      int end;
474      DBusKey *new;
475
476      /* Don't load more than the max. */
477      if (n_keys >= (add_new ? MAX_KEYS_IN_FILE - 1 : MAX_KEYS_IN_FILE))
478        break;
479
480      next = 0;
481      if (!_dbus_string_parse_int (&line, 0, &val, &next))
482        {
483          _dbus_verbose ("could not parse secret key ID at start of line\n");
484          continue;
485        }
486
487      if (val > _DBUS_INT32_MAX || val < 0)
488        {
489          _dbus_verbose ("invalid secret key ID at start of line\n");
490          continue;
491        }
492
493      id = val;
494
495      _dbus_string_skip_blank (&line, next, &next);
496
497      if (!_dbus_string_parse_int (&line, next, &timestamp, &next))
498        {
499          _dbus_verbose ("could not parse secret key timestamp\n");
500          continue;
501        }
502
503      if (timestamp < 0 ||
504          (now + MAX_TIME_TRAVEL_SECONDS) < timestamp ||
505          (now - EXPIRE_KEYS_TIMEOUT_SECONDS) > timestamp)
506        {
507          _dbus_verbose ("dropping/ignoring %ld-seconds old key with timestamp %ld as current time is %ld\n",
508                         now - timestamp, timestamp, now);
509          continue;
510        }
511
512      _dbus_string_skip_blank (&line, next, &next);
513
514      len = _dbus_string_get_length (&line);
515
516      if ((len - next) == 0)
517        {
518          _dbus_verbose ("no secret key after ID and timestamp\n");
519          continue;
520        }
521
522      /* We have all three parts */
523      new = dbus_realloc (keys, sizeof (DBusKey) * (n_keys + 1));
524      if (new == NULL)
525        {
526          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
527          goto out;
528        }
529
530      keys = new;
531      n_keys += 1;
532
533      if (!_dbus_string_init (&keys[n_keys-1].secret))
534        {
535          n_keys -= 1; /* we don't want to free the one we didn't init */
536          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
537          goto out;
538        }
539
540      keys[n_keys-1].id = id;
541      keys[n_keys-1].creation_time = timestamp;
542      if (!_dbus_string_hex_decode (&line, next, &end,
543                                    &keys[n_keys-1].secret, 0))
544	{
545	  dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
546	  goto out;
547	}
548
549      if (_dbus_string_get_length (&line) != end)
550	{
551	  _dbus_verbose ("invalid hex encoding in keyring file\n");
552	  _dbus_string_free (&keys[n_keys - 1].secret);
553	  n_keys -= 1;
554	  continue;
555	}
556    }
557
558  _dbus_verbose ("Successfully loaded %d existing keys\n",
559                 n_keys);
560
561  if (add_new)
562    {
563      if (!add_new_key (&keys, &n_keys, error))
564        {
565          _dbus_verbose ("Failed to generate new key: %s\n",
566                         error ? error->message : "(unknown)");
567          goto out;
568        }
569
570      _dbus_string_set_length (&contents, 0);
571
572      i = 0;
573      while (i < n_keys)
574        {
575          if (!_dbus_string_append_int (&contents,
576                                        keys[i].id))
577            goto nomem;
578
579          if (!_dbus_string_append_byte (&contents, ' '))
580            goto nomem;
581
582          if (!_dbus_string_append_int (&contents,
583                                        keys[i].creation_time))
584            goto nomem;
585
586          if (!_dbus_string_append_byte (&contents, ' '))
587            goto nomem;
588
589          if (!_dbus_string_hex_encode (&keys[i].secret, 0,
590                                        &contents,
591                                        _dbus_string_get_length (&contents)))
592            goto nomem;
593
594          if (!_dbus_string_append_byte (&contents, '\n'))
595            goto nomem;
596
597          ++i;
598          continue;
599
600        nomem:
601          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
602          goto out;
603        }
604
605      if (!_dbus_string_save_to_file (&contents, &keyring->filename,
606                                      FALSE, error))
607        goto out;
608    }
609
610  if (keyring->keys)
611    free_keys (keyring->keys, keyring->n_keys);
612  keyring->keys = keys;
613  keyring->n_keys = n_keys;
614  keys = NULL;
615  n_keys = 0;
616
617  retval = TRUE;
618
619 out:
620  if (have_lock)
621    _dbus_keyring_unlock (keyring);
622
623  if (! ((retval == TRUE && (error == NULL || error->name == NULL)) ||
624         (retval == FALSE && (error == NULL || error->name != NULL))))
625    {
626      if (error && error->name)
627        _dbus_verbose ("error is %s: %s\n", error->name, error->message);
628      _dbus_warn ("returning %d but error pointer %p name %s\n",
629                  retval, error, error->name ? error->name : "(none)");
630      _dbus_assert_not_reached ("didn't handle errors properly");
631    }
632
633  if (keys != NULL)
634    {
635      i = 0;
636      while (i < n_keys)
637        {
638          _dbus_string_zero (&keys[i].secret);
639          _dbus_string_free (&keys[i].secret);
640          ++i;
641        }
642
643      dbus_free (keys);
644    }
645
646  _dbus_string_free (&contents);
647  _dbus_string_free (&line);
648
649  return retval;
650}
651
652/** @} */ /* end of internals */
653
654/**
655 * @addtogroup DBusKeyring
656 *
657 * @{
658 */
659
660/**
661 * Increments reference count of the keyring
662 *
663 * @param keyring the keyring
664 * @returns the keyring
665 */
666DBusKeyring *
667_dbus_keyring_ref (DBusKeyring *keyring)
668{
669  keyring->refcount += 1;
670
671  return keyring;
672}
673
674/**
675 * Decrements refcount and finalizes if it reaches
676 * zero.
677 *
678 * @param keyring the keyring
679 */
680void
681_dbus_keyring_unref (DBusKeyring *keyring)
682{
683  keyring->refcount -= 1;
684
685  if (keyring->refcount == 0)
686    {
687      if (keyring->credentials)
688        _dbus_credentials_unref (keyring->credentials);
689
690      _dbus_string_free (&keyring->filename);
691      _dbus_string_free (&keyring->filename_lock);
692      _dbus_string_free (&keyring->directory);
693      free_keys (keyring->keys, keyring->n_keys);
694      dbus_free (keyring);
695    }
696}
697
698/**
699 * Creates a new keyring that lives in the ~/.dbus-keyrings directory
700 * of the given user credentials. If the credentials are #NULL or
701 * empty, uses those of the current process.
702 *
703 * @param username username to get keyring for, or #NULL
704 * @param context which keyring to get
705 * @param error return location for errors
706 * @returns the keyring or #NULL on error
707 */
708DBusKeyring*
709_dbus_keyring_new_for_credentials (DBusCredentials  *credentials,
710                                   const DBusString *context,
711                                   DBusError        *error)
712{
713  DBusString ringdir;
714  DBusKeyring *keyring;
715  dbus_bool_t error_set;
716  DBusError tmp_error;
717  DBusCredentials *our_credentials;
718
719  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
720
721  if (_dbus_check_setuid ())
722    {
723      dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED,
724                            "Unable to create DBus keyring when setuid");
725      return NULL;
726    }
727
728  keyring = NULL;
729  error_set = FALSE;
730  our_credentials = NULL;
731
732  if (!_dbus_string_init (&ringdir))
733    {
734      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
735      return NULL;
736    }
737
738  if (credentials != NULL)
739    {
740      our_credentials = _dbus_credentials_copy (credentials);
741    }
742  else
743    {
744      our_credentials = _dbus_credentials_new_from_current_process ();
745    }
746
747  if (our_credentials == NULL)
748    goto failed;
749
750  if (_dbus_credentials_are_anonymous (our_credentials))
751    {
752      if (!_dbus_credentials_add_from_current_process (our_credentials))
753        goto failed;
754    }
755
756  if (!_dbus_append_keyring_directory_for_credentials (&ringdir,
757                                                       our_credentials))
758    goto failed;
759
760  keyring = _dbus_keyring_new ();
761  if (keyring == NULL)
762    goto failed;
763
764  _dbus_assert (keyring->credentials == NULL);
765  keyring->credentials = our_credentials;
766  our_credentials = NULL; /* so we don't unref it again later */
767
768  /* should have been validated already, but paranoia check here */
769  if (!_dbus_keyring_validate_context (context))
770    {
771      error_set = TRUE;
772      dbus_set_error_const (error,
773                            DBUS_ERROR_FAILED,
774                            "Invalid context in keyring creation");
775      goto failed;
776    }
777
778  /* Save keyring dir in the keyring object */
779  if (!_dbus_string_copy (&ringdir, 0,
780                          &keyring->directory, 0))
781    goto failed;
782
783  /* Create keyring->filename based on keyring dir and context */
784  if (!_dbus_string_copy (&keyring->directory, 0,
785                          &keyring->filename, 0))
786    goto failed;
787
788  if (!_dbus_concat_dir_and_file (&keyring->filename,
789                                  context))
790    goto failed;
791
792  /* Create lockfile name */
793  if (!_dbus_string_copy (&keyring->filename, 0,
794                          &keyring->filename_lock, 0))
795    goto failed;
796
797  if (!_dbus_string_append (&keyring->filename_lock, ".lock"))
798    goto failed;
799
800  /* Reload keyring */
801  dbus_error_init (&tmp_error);
802  if (!_dbus_keyring_reload (keyring, FALSE, &tmp_error))
803    {
804      _dbus_verbose ("didn't load an existing keyring: %s\n",
805                     tmp_error.message);
806      dbus_error_free (&tmp_error);
807    }
808
809  /* We don't fail fatally if we can't create the directory,
810   * but the keyring will probably always be empty
811   * unless someone else manages to create it
812   */
813  dbus_error_init (&tmp_error);
814  if (!_dbus_create_directory (&keyring->directory,
815                               &tmp_error))
816    {
817      _dbus_verbose ("Creating keyring directory: %s\n",
818                     tmp_error.message);
819      dbus_error_free (&tmp_error);
820    }
821
822  _dbus_string_free (&ringdir);
823
824  return keyring;
825
826 failed:
827  if (!error_set)
828    dbus_set_error_const (error,
829                          DBUS_ERROR_NO_MEMORY,
830                          NULL);
831  if (our_credentials)
832    _dbus_credentials_unref (our_credentials);
833  if (keyring)
834    _dbus_keyring_unref (keyring);
835  _dbus_string_free (&ringdir);
836  return NULL;
837
838}
839
840/**
841 * Checks whether the context is a valid context.
842 * Contexts that might cause confusion when used
843 * in filenames are not allowed (contexts can't
844 * start with a dot or contain dir separators).
845 *
846 * @todo this is the most inefficient implementation
847 * imaginable.
848 *
849 * @param context the context
850 * @returns #TRUE if valid
851 */
852dbus_bool_t
853_dbus_keyring_validate_context (const DBusString *context)
854{
855  if (_dbus_string_get_length (context) == 0)
856    {
857      _dbus_verbose ("context is zero-length\n");
858      return FALSE;
859    }
860
861  if (!_dbus_string_validate_ascii (context, 0,
862                                    _dbus_string_get_length (context)))
863    {
864      _dbus_verbose ("context not valid ascii\n");
865      return FALSE;
866    }
867
868  /* no directory separators */
869  if (_dbus_string_find (context, 0, "/", NULL))
870    {
871      _dbus_verbose ("context contains a slash\n");
872      return FALSE;
873    }
874
875  if (_dbus_string_find (context, 0, "\\", NULL))
876    {
877      _dbus_verbose ("context contains a backslash\n");
878      return FALSE;
879    }
880
881  /* prevent attempts to use dotfiles or ".." or ".lock"
882   * all of which might allow some kind of attack
883   */
884  if (_dbus_string_find (context, 0, ".", NULL))
885    {
886      _dbus_verbose ("context contains a dot\n");
887      return FALSE;
888    }
889
890  /* no spaces/tabs, those are used for separators in the protocol */
891  if (_dbus_string_find_blank (context, 0, NULL))
892    {
893      _dbus_verbose ("context contains a blank\n");
894      return FALSE;
895    }
896
897  if (_dbus_string_find (context, 0, "\n", NULL))
898    {
899      _dbus_verbose ("context contains a newline\n");
900      return FALSE;
901    }
902
903  if (_dbus_string_find (context, 0, "\r", NULL))
904    {
905      _dbus_verbose ("context contains a carriage return\n");
906      return FALSE;
907    }
908
909  return TRUE;
910}
911
912static DBusKey*
913find_recent_key (DBusKeyring *keyring)
914{
915  int i;
916  long tv_sec, tv_usec;
917
918  _dbus_get_real_time (&tv_sec, &tv_usec);
919
920  i = 0;
921  while (i < keyring->n_keys)
922    {
923      DBusKey *key = &keyring->keys[i];
924
925      _dbus_verbose ("Key %d is %ld seconds old\n",
926                     i, tv_sec - key->creation_time);
927
928      if ((tv_sec - NEW_KEY_TIMEOUT_SECONDS) < key->creation_time)
929        return key;
930
931      ++i;
932    }
933
934  return NULL;
935}
936
937/**
938 * Gets a recent key to use for authentication.
939 * If no recent key exists, creates one. Returns
940 * the key ID. If a key can't be written to the keyring
941 * file so no recent key can be created, returns -1.
942 * All valid keys are > 0.
943 *
944 * @param keyring the keyring
945 * @param error error on failure
946 * @returns key ID to use for auth, or -1 on failure
947 */
948int
949_dbus_keyring_get_best_key (DBusKeyring  *keyring,
950                            DBusError    *error)
951{
952  DBusKey *key;
953
954  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
955
956  key = find_recent_key (keyring);
957  if (key)
958    return key->id;
959
960  /* All our keys are too old, or we've never loaded the
961   * keyring. Create a new one.
962   */
963  if (!_dbus_keyring_reload (keyring, TRUE,
964                             error))
965    return -1;
966
967  key = find_recent_key (keyring);
968  if (key)
969    return key->id;
970  else
971    {
972      dbus_set_error_const (error,
973                            DBUS_ERROR_FAILED,
974                            "No recent-enough key found in keyring, and unable to create a new key");
975      return -1;
976    }
977}
978
979/**
980 * Checks whether the keyring is for the same user as the given credentials.
981 *
982 * @param keyring the keyring
983 * @param credentials the credentials to check
984 *
985 * @returns #TRUE if the keyring belongs to the given user
986 */
987dbus_bool_t
988_dbus_keyring_is_for_credentials (DBusKeyring           *keyring,
989                                  DBusCredentials       *credentials)
990{
991  return _dbus_credentials_same_user (keyring->credentials,
992                                      credentials);
993}
994
995/**
996 * Gets the hex-encoded secret key for the given ID.
997 * Returns #FALSE if not enough memory. Returns #TRUE
998 * but empty key on any other error such as unknown
999 * key ID.
1000 *
1001 * @param keyring the keyring
1002 * @param key_id the key ID
1003 * @param hex_key string to append hex-encoded key to
1004 * @returns #TRUE if we had enough memory
1005 */
1006dbus_bool_t
1007_dbus_keyring_get_hex_key (DBusKeyring       *keyring,
1008                           int                key_id,
1009                           DBusString        *hex_key)
1010{
1011  DBusKey *key;
1012
1013  key = find_key_by_id (keyring->keys,
1014                        keyring->n_keys,
1015                        key_id);
1016  if (key == NULL)
1017    return TRUE; /* had enough memory, so TRUE */
1018
1019  return _dbus_string_hex_encode (&key->secret, 0,
1020                                  hex_key,
1021                                  _dbus_string_get_length (hex_key));
1022}
1023
1024/** @} */ /* end of exposed API */
1025
1026#ifdef DBUS_BUILD_TESTS
1027#include "dbus-test.h"
1028#include <stdio.h>
1029
1030dbus_bool_t
1031_dbus_keyring_test (void)
1032{
1033  DBusString context;
1034  DBusKeyring *ring1;
1035  DBusKeyring *ring2;
1036  int id;
1037  DBusError error;
1038  int i;
1039
1040  ring1 = NULL;
1041  ring2 = NULL;
1042
1043  /* Context validation */
1044
1045  _dbus_string_init_const (&context, "foo");
1046  _dbus_assert (_dbus_keyring_validate_context (&context));
1047  _dbus_string_init_const (&context, "org_freedesktop_blah");
1048  _dbus_assert (_dbus_keyring_validate_context (&context));
1049
1050  _dbus_string_init_const (&context, "");
1051  _dbus_assert (!_dbus_keyring_validate_context (&context));
1052  _dbus_string_init_const (&context, ".foo");
1053  _dbus_assert (!_dbus_keyring_validate_context (&context));
1054  _dbus_string_init_const (&context, "bar.foo");
1055  _dbus_assert (!_dbus_keyring_validate_context (&context));
1056  _dbus_string_init_const (&context, "bar/foo");
1057  _dbus_assert (!_dbus_keyring_validate_context (&context));
1058  _dbus_string_init_const (&context, "bar\\foo");
1059  _dbus_assert (!_dbus_keyring_validate_context (&context));
1060  _dbus_string_init_const (&context, "foo\xfa\xf0");
1061  _dbus_assert (!_dbus_keyring_validate_context (&context));
1062  _dbus_string_init_const (&context, "foo\x80");
1063  _dbus_assert (!_dbus_keyring_validate_context (&context));
1064  _dbus_string_init_const (&context, "foo\x7f");
1065  _dbus_assert (_dbus_keyring_validate_context (&context));
1066  _dbus_string_init_const (&context, "foo bar");
1067  _dbus_assert (!_dbus_keyring_validate_context (&context));
1068
1069  if (!_dbus_string_init (&context))
1070    _dbus_assert_not_reached ("no memory");
1071  if (!_dbus_string_append_byte (&context, '\0'))
1072    _dbus_assert_not_reached ("no memory");
1073  _dbus_assert (!_dbus_keyring_validate_context (&context));
1074  _dbus_string_free (&context);
1075
1076  /* Now verify that if we create a key in keyring 1,
1077   * it is properly loaded in keyring 2
1078   */
1079
1080  _dbus_string_init_const (&context, "org_freedesktop_dbus_testsuite");
1081  dbus_error_init (&error);
1082  ring1 = _dbus_keyring_new_for_credentials (NULL, &context,
1083                                             &error);
1084  _dbus_assert (ring1 != NULL);
1085  _dbus_assert (error.name == NULL);
1086
1087  id = _dbus_keyring_get_best_key (ring1, &error);
1088  if (id < 0)
1089    {
1090      fprintf (stderr, "Could not load keyring: %s\n", error.message);
1091      dbus_error_free (&error);
1092      goto failure;
1093    }
1094
1095  ring2 = _dbus_keyring_new_for_credentials (NULL, &context, &error);
1096  _dbus_assert (ring2 != NULL);
1097  _dbus_assert (error.name == NULL);
1098
1099  if (ring1->n_keys != ring2->n_keys)
1100    {
1101      fprintf (stderr, "Different number of keys in keyrings\n");
1102      goto failure;
1103    }
1104
1105  /* We guarantee we load and save keeping keys in a fixed
1106   * order
1107   */
1108  i = 0;
1109  while (i < ring1->n_keys)
1110    {
1111      if (ring1->keys[i].id != ring2->keys[i].id)
1112        {
1113          fprintf (stderr, "Keyring 1 has first key ID %d and keyring 2 has %d\n",
1114                   ring1->keys[i].id, ring2->keys[i].id);
1115          goto failure;
1116        }
1117
1118      if (ring1->keys[i].creation_time != ring2->keys[i].creation_time)
1119        {
1120          fprintf (stderr, "Keyring 1 has first key time %ld and keyring 2 has %ld\n",
1121                   ring1->keys[i].creation_time, ring2->keys[i].creation_time);
1122          goto failure;
1123        }
1124
1125      if (!_dbus_string_equal (&ring1->keys[i].secret,
1126                               &ring2->keys[i].secret))
1127        {
1128          fprintf (stderr, "Keyrings 1 and 2 have different secrets for same ID/timestamp\n");
1129          goto failure;
1130        }
1131
1132      ++i;
1133    }
1134
1135  printf (" %d keys in test\n", ring1->n_keys);
1136
1137  /* Test ref/unref */
1138  _dbus_keyring_ref (ring1);
1139  _dbus_keyring_ref (ring2);
1140  _dbus_keyring_unref (ring1);
1141  _dbus_keyring_unref (ring2);
1142
1143
1144  /* really unref */
1145  _dbus_keyring_unref (ring1);
1146  _dbus_keyring_unref (ring2);
1147
1148  return TRUE;
1149
1150 failure:
1151  if (ring1)
1152    _dbus_keyring_unref (ring1);
1153  if (ring2)
1154    _dbus_keyring_unref (ring2);
1155
1156  return FALSE;
1157}
1158
1159#endif /* DBUS_BUILD_TESTS */
1160
1161