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