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