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