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