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