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