2006-10-21 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / dbus / dbus-keyring.c
index 67ae056..018f45a 100644 (file)
@@ -1,9 +1,9 @@
 /* -*- mode: C; c-file-style: "gnu" -*- */
 /* dbus-keyring.c Store secret cookies in your homedir
  *
- * Copyright (C) 2003  Red Hat Inc.
+ * Copyright (C) 2003, 2004  Red Hat Inc.
  *
- * Licensed under the Academic Free License version 1.2
+ * Licensed under the Academic Free License version 2.1
  * 
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -23,6 +23,7 @@
 
 #include "dbus-keyring.h"
 #include "dbus-userdb.h"
+#include "dbus-protocol.h"
 #include <dbus/dbus-string.h>
 #include <dbus/dbus-list.h>
 #include <dbus/dbus-sysdeps.h>
  */
 #define MAX_TIME_TRAVEL_SECONDS (60*5)
 
+/**
+ * Maximum number of keys in the keyring before
+ * we just ignore the rest
+ */
+#ifdef DBUS_BUILD_TESTS
+#define MAX_KEYS_IN_FILE 10
+#else
+#define MAX_KEYS_IN_FILE 256
+#endif
+
+/**
+ * A single key from the cookie file
+ */
 typedef struct
 {
   dbus_int32_t id; /**< identifier used to refer to the key */
@@ -133,7 +147,7 @@ _dbus_keyring_new (void)
   return keyring;
 
  out_4:
-  _dbus_string_free (&keyring->username);
+  _dbus_string_free (&keyring->filename_lock);
  out_3:
   _dbus_string_free (&keyring->filename);
  out_2:
@@ -277,7 +291,7 @@ add_new_key (DBusKey  **keys_p,
   DBusKey *new;
   DBusString bytes;
   int id;
-  unsigned long timestamp;
+  long timestamp;
   const unsigned char *s;
   dbus_bool_t retval;
   DBusKey *keys;
@@ -337,6 +351,7 @@ add_new_key (DBusKey  **keys_p,
     }
 
   keys = new;
+  *keys_p = keys; /* otherwise *keys_p ends up invalid */
   n_keys += 1;
 
   if (!_dbus_string_init (&keys[n_keys-1].secret))
@@ -355,17 +370,15 @@ add_new_key (DBusKey  **keys_p,
                           0))
     {
       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+      _dbus_string_free (&keys[n_keys-1].secret);
+      n_keys -= 1;
       goto out;
     }
   
   retval = TRUE;
   
  out:
-  if (retval)
-    {
-      *n_keys_p = n_keys;
-      *keys_p = keys;
-    }
+  *n_keys_p = n_keys;
   
   _dbus_string_free (&bytes);
   return retval;
@@ -402,6 +415,9 @@ _dbus_keyring_reload (DBusKeyring *keyring,
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
   
+  if (!_dbus_check_dir_is_private_to_user (&keyring->directory, error))
+    return FALSE;
+    
   if (!_dbus_string_init (&contents))
     {
       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
@@ -414,7 +430,7 @@ _dbus_keyring_reload (DBusKeyring *keyring,
       _dbus_string_free (&contents);
       return FALSE;
     }
-
+   
   keys = NULL;
   n_keys = 0;
   retval = FALSE;
@@ -451,7 +467,10 @@ _dbus_keyring_reload (DBusKeyring *keyring,
       _dbus_warn ("Secret keyring file contains non-ASCII! Ignoring existing contents\n");
       _dbus_string_set_length (&contents, 0);
     }
-  
+
+  /* FIXME this is badly inefficient for large keyring files
+   * (not that large keyring files exist outside of test suites)
+   */
   while (_dbus_string_pop_line (&contents, &line))
     {
       int next;
@@ -459,7 +478,12 @@ _dbus_keyring_reload (DBusKeyring *keyring,
       int id;
       long timestamp;
       int len;
+      int end;
       DBusKey *new;
+
+      /* Don't load more than the max. */
+      if (n_keys >= (add_new ? MAX_KEYS_IN_FILE - 1 : MAX_KEYS_IN_FILE))
+        break;
       
       next = 0;
       if (!_dbus_string_parse_int (&line, 0, &val, &next))
@@ -468,7 +492,7 @@ _dbus_keyring_reload (DBusKeyring *keyring,
           continue;
         }
 
-      if (val > _DBUS_INT_MAX || val < 0)
+      if (val > _DBUS_INT32_MAX || val < 0)
         {
           _dbus_verbose ("invalid secret key ID at start of line\n");
           continue;
@@ -523,13 +547,20 @@ _dbus_keyring_reload (DBusKeyring *keyring,
       
       keys[n_keys-1].id = id;
       keys[n_keys-1].creation_time = timestamp;
-      if (!_dbus_string_hex_decode (&line, next,
-                                    &keys[n_keys-1].secret,
-                                    0))
-        {
-          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
-          goto out;
-        }
+      if (!_dbus_string_hex_decode (&line, next, &end,
+                                    &keys[n_keys-1].secret, 0))
+       {
+         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+         goto out;
+       }
+
+      if (_dbus_string_get_length (&line) != end)
+       {
+         _dbus_verbose ("invalid hex encoding in keyring file\n");
+         _dbus_string_free (&keys[n_keys - 1].secret);
+         n_keys -= 1;
+         continue;
+       }
     }
 
   _dbus_verbose ("Successfully loaded %d existing keys\n",
@@ -540,7 +571,7 @@ _dbus_keyring_reload (DBusKeyring *keyring,
       if (!add_new_key (&keys, &n_keys, error))
         {
           _dbus_verbose ("Failed to generate new key: %s\n",
-                         error ? "(unknown)" : error->message);
+                         error ? error->message : "(unknown)");
           goto out;
         }
 
@@ -584,7 +615,8 @@ _dbus_keyring_reload (DBusKeyring *keyring,
         goto out;
     }
 
-  dbus_free (keyring->keys);
+  if (keyring->keys)
+    free_keys (keyring->keys, keyring->n_keys);
   keyring->keys = keys;
   keyring->n_keys = n_keys;
   keys = NULL;
@@ -637,11 +669,14 @@ _dbus_keyring_reload (DBusKeyring *keyring,
  * Increments reference count of the keyring
  *
  * @param keyring the keyring
+ * @returns the keyring
  */
-void
+DBusKeyring *
 _dbus_keyring_ref (DBusKeyring *keyring)
 {
   keyring->refcount += 1;
+
+  return keyring;
 }
 
 /**
@@ -693,7 +728,10 @@ _dbus_keyring_new_homedir (const DBusString *username,
   error_set = FALSE;
   
   if (!_dbus_string_init (&homedir))
-    return FALSE;
+    {
+      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+      return NULL;
+    }
 
   _dbus_string_init_const (&dotdir, ".dbus-keyrings");
   
@@ -724,7 +762,7 @@ _dbus_keyring_new_homedir (const DBusString *username,
      {
        _dbus_string_set_length (&homedir, 0);
        if (!_dbus_string_append (&homedir, override))
-         _dbus_assert_not_reached ("no memory");
+         goto failed;
 
        _dbus_verbose ("Using fake homedir for testing: %s\n",
                       _dbus_string_get_const_data (&homedir));
@@ -764,8 +802,6 @@ _dbus_keyring_new_homedir (const DBusString *username,
   if (!_dbus_string_copy (&homedir, 0,
                           &keyring->directory, 0))
     goto failed;
-
-  _dbus_string_free (&homedir);
   
   if (!_dbus_concat_dir_and_file (&keyring->directory,
                                   &dotdir))
@@ -806,6 +842,8 @@ _dbus_keyring_new_homedir (const DBusString *username,
                      tmp_error.message);
       dbus_error_free (&tmp_error);
     }
+
+  _dbus_string_free (&homedir);
   
   return keyring;
   
@@ -813,11 +851,11 @@ _dbus_keyring_new_homedir (const DBusString *username,
   if (!error_set)
     dbus_set_error_const (error,
                           DBUS_ERROR_NO_MEMORY,
-                          "No memory to create keyring");
+                          NULL);
   if (keyring)
     _dbus_keyring_unref (keyring);
   _dbus_string_free (&homedir);
-  return FALSE;
+  return NULL;
 
 }
 
@@ -1118,6 +1156,14 @@ _dbus_keyring_test (void)
 
   printf (" %d keys in test\n", ring1->n_keys);
 
+  /* Test ref/unref */
+  _dbus_keyring_ref (ring1);
+  _dbus_keyring_ref (ring2);
+  _dbus_keyring_unref (ring1);
+  _dbus_keyring_unref (ring2);
+
+
+  /* really unref */
   _dbus_keyring_unref (ring1);
   _dbus_keyring_unref (ring2);