+ DBusString contents;
+ DBusString line;
+ dbus_bool_t retval;
+ dbus_bool_t have_lock;
+ DBusKey *keys;
+ int n_keys;
+ int i;
+ long now;
+ DBusError tmp_error;
+
+ _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);
+ return FALSE;
+ }
+
+ if (!_dbus_string_init (&line))
+ {
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+ _dbus_string_free (&contents);
+ return FALSE;
+ }
+
+ keys = NULL;
+ n_keys = 0;
+ retval = FALSE;
+ have_lock = FALSE;
+
+ _dbus_get_real_time (&now, NULL);
+
+ if (add_new)
+ {
+ if (!_dbus_keyring_lock (keyring))
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Could not lock keyring file to add to it");
+ goto out;
+ }
+
+ have_lock = TRUE;
+ }
+
+ dbus_error_init (&tmp_error);
+ if (!_dbus_file_get_contents (&contents,
+ &keyring->filename,
+ &tmp_error))
+ {
+ _dbus_verbose ("Failed to load keyring file: %s\n",
+ tmp_error.message);
+ /* continue with empty keyring file, so we recreate it */
+ dbus_error_free (&tmp_error);
+ }
+
+ if (!_dbus_string_validate_ascii (&contents, 0,
+ _dbus_string_get_length (&contents)))
+ {
+ _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;
+ long val;
+ 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))
+ {
+ _dbus_verbose ("could not parse secret key ID at start of line\n");
+ continue;
+ }
+
+ if (val > _DBUS_INT32_MAX || val < 0)
+ {
+ _dbus_verbose ("invalid secret key ID at start of line\n");
+ continue;
+ }
+
+ id = val;
+
+ _dbus_string_skip_blank (&line, next, &next);
+
+ if (!_dbus_string_parse_int (&line, next, ×tamp, &next))
+ {
+ _dbus_verbose ("could not parse secret key timestamp\n");
+ continue;
+ }
+
+ if (timestamp < 0 ||
+ (now + MAX_TIME_TRAVEL_SECONDS) < timestamp ||
+ (now - EXPIRE_KEYS_TIMEOUT_SECONDS) > timestamp)
+ {
+ _dbus_verbose ("dropping/ignoring %ld-seconds old key with timestamp %ld as current time is %ld\n",
+ now - timestamp, timestamp, now);
+ continue;
+ }
+
+ _dbus_string_skip_blank (&line, next, &next);
+
+ len = _dbus_string_get_length (&line);
+
+ if ((len - next) == 0)
+ {
+ _dbus_verbose ("no secret key after ID and timestamp\n");
+ continue;
+ }
+
+ /* We have all three parts */
+ new = dbus_realloc (keys, sizeof (DBusKey) * (n_keys + 1));
+ if (new == NULL)
+ {
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+ goto out;
+ }
+
+ keys = new;
+ n_keys += 1;
+
+ if (!_dbus_string_init (&keys[n_keys-1].secret))
+ {
+ n_keys -= 1; /* we don't want to free the one we didn't init */
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+ goto out;
+ }
+
+ keys[n_keys-1].id = id;
+ keys[n_keys-1].creation_time = timestamp;
+ 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",
+ n_keys);
+
+ if (add_new)
+ {
+ if (!add_new_key (&keys, &n_keys, error))
+ {
+ _dbus_verbose ("Failed to generate new key: %s\n",
+ error ? error->message : "(unknown)");
+ goto out;
+ }
+
+ _dbus_string_set_length (&contents, 0);
+
+ i = 0;
+ while (i < n_keys)
+ {
+ if (!_dbus_string_append_int (&contents,
+ keys[i].id))
+ goto nomem;
+
+ if (!_dbus_string_append_byte (&contents, ' '))
+ goto nomem;
+
+ if (!_dbus_string_append_int (&contents,
+ keys[i].creation_time))
+ goto nomem;
+
+ if (!_dbus_string_append_byte (&contents, ' '))
+ goto nomem;