| // Copyright (c) 2011 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "shill/key_file_store.h" |
| |
| #include <base/file_util.h> |
| #include <base/logging.h> |
| |
| using std::set; |
| using std::string; |
| using std::vector; |
| |
| namespace shill { |
| |
| KeyFileStore::KeyFileStore(GLib *glib) |
| : glib_(glib), |
| crypto_(glib), |
| key_file_(NULL) {} |
| |
| KeyFileStore::~KeyFileStore() { |
| ReleaseKeyFile(); |
| } |
| |
| void KeyFileStore::ReleaseKeyFile() { |
| if (key_file_) { |
| glib_->KeyFileFree(key_file_); |
| key_file_ = NULL; |
| } |
| } |
| |
| bool KeyFileStore::IsNonEmpty() const { |
| int64 file_size = 0; |
| return file_util::GetFileSize(path_, &file_size) && file_size != 0; |
| } |
| |
| bool KeyFileStore::Open() { |
| CHECK(!path_.empty()); |
| CHECK(!key_file_); |
| crypto_.Init(); |
| key_file_ = glib_->KeyFileNew(); |
| if (!IsNonEmpty()) { |
| LOG(INFO) << "Creating a new key file at " << path_.value(); |
| return true; |
| } |
| GError *error = NULL; |
| if (glib_->KeyFileLoadFromFile( |
| key_file_, |
| path_.value().c_str(), |
| static_cast<GKeyFileFlags>(G_KEY_FILE_KEEP_COMMENTS | |
| G_KEY_FILE_KEEP_TRANSLATIONS), |
| &error)) { |
| return true; |
| } |
| LOG(ERROR) << "Failed to load key file from " << path_.value() << ": " |
| << glib_->ConvertErrorToMessage(error); |
| ReleaseKeyFile(); |
| return false; |
| } |
| |
| bool KeyFileStore::Close() { |
| bool success = Flush(); |
| ReleaseKeyFile(); |
| return success; |
| } |
| |
| bool KeyFileStore::Flush() { |
| CHECK(key_file_); |
| GError *error = NULL; |
| gsize length = 0; |
| gchar *data = glib_->KeyFileToData(key_file_, &length, &error); |
| |
| bool success = true; |
| if (path_.empty()) { |
| LOG(ERROR) << "Empty key file path."; |
| success = false; |
| } |
| if (success && (!data || error)) { |
| LOG(ERROR) << "Failed to convert key file to string: " |
| << glib_->ConvertErrorToMessage(error); |
| success = false; |
| } |
| if (success) { |
| int written = file_util::WriteFile(path_, data, length); |
| if (written < 0 || |
| static_cast<unsigned int>(written) != length) { |
| LOG(ERROR) << "Failed to store key file: " << path_.value(); |
| success = false; |
| } |
| } |
| glib_->Free(data); |
| return success; |
| } |
| |
| set<string> KeyFileStore::GetGroups() const { |
| CHECK(key_file_); |
| gsize length = 0; |
| gchar **groups = glib_->KeyFileGetGroups(key_file_, &length); |
| if (!groups) { |
| LOG(ERROR) << "Unable to obtain groups."; |
| return set<string>(); |
| } |
| set<string> group_set(groups, groups + length); |
| glib_->Strfreev(groups); |
| return group_set; |
| } |
| |
| // Returns a set so that caller can easily test whether a particular group |
| // is contained within this collection. |
| set<string> KeyFileStore::GetGroupsWithKey(const string &key) const { |
| set<string> groups = GetGroups(); |
| set<string> groups_with_key; |
| for (set<string>::iterator it = groups.begin(); it != groups.end(); ++it) { |
| if (glib_->KeyFileHasKey(key_file_, (*it).c_str(), key.c_str(), NULL)) { |
| groups_with_key.insert(*it); |
| } |
| } |
| return groups_with_key; |
| } |
| |
| bool KeyFileStore::ContainsGroup(const string &group) const { |
| CHECK(key_file_); |
| return glib_->KeyFileHasGroup(key_file_, group.c_str()); |
| } |
| |
| bool KeyFileStore::DeleteKey(const string &group, const string &key) { |
| CHECK(key_file_); |
| GError *error = NULL; |
| glib_->KeyFileRemoveKey(key_file_, group.c_str(), key.c_str(), &error); |
| if (error && error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) { |
| LOG(ERROR) << "Failed to delete (" << group << ":" << key << "): " |
| << glib_->ConvertErrorToMessage(error); |
| return false; |
| } |
| return true; |
| } |
| |
| bool KeyFileStore::DeleteGroup(const string &group) { |
| CHECK(key_file_); |
| GError *error = NULL; |
| glib_->KeyFileRemoveGroup(key_file_, group.c_str(), &error); |
| if (error && error->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND) { |
| LOG(ERROR) << "Failed to delete group " << group << ": " |
| << glib_->ConvertErrorToMessage(error); |
| return false; |
| } |
| return true; |
| } |
| |
| bool KeyFileStore::SetHeader(const string &header) { |
| GError *error = NULL; |
| glib_->KeyFileSetComment(key_file_, NULL, NULL, header.c_str(), &error); |
| if (error) { |
| LOG(ERROR) << "Failed to to set header: " |
| << glib_->ConvertErrorToMessage(error); |
| return false; |
| } |
| return true; |
| } |
| |
| bool KeyFileStore::GetString(const string &group, |
| const string &key, |
| string *value) const { |
| CHECK(key_file_); |
| GError *error = NULL; |
| gchar *data = |
| glib_->KeyFileGetString(key_file_, group.c_str(), key.c_str(), &error); |
| if (!data) { |
| LOG(ERROR) << "Failed to lookup (" << group << ":" << key << "): " |
| << glib_->ConvertErrorToMessage(error); |
| return false; |
| } |
| if (value) { |
| *value = data; |
| } |
| glib_->Free(data); |
| return true; |
| } |
| |
| bool KeyFileStore::SetString(const string &group, |
| const string &key, |
| const string &value) { |
| CHECK(key_file_); |
| glib_->KeyFileSetString(key_file_, group.c_str(), key.c_str(), value.c_str()); |
| return true; |
| } |
| |
| bool KeyFileStore::GetBool(const string &group, |
| const string &key, |
| bool *value) const { |
| CHECK(key_file_); |
| GError *error = NULL; |
| gboolean data = |
| glib_->KeyFileGetBoolean(key_file_, group.c_str(), key.c_str(), &error); |
| if (error) { |
| LOG(ERROR) << "Failed to lookup (" << group << ":" << key << "): " |
| << glib_->ConvertErrorToMessage(error); |
| return false; |
| } |
| if (value) { |
| *value = data; |
| } |
| return true; |
| } |
| |
| bool KeyFileStore::SetBool(const string &group, const string &key, bool value) { |
| CHECK(key_file_); |
| glib_->KeyFileSetBoolean(key_file_, |
| group.c_str(), |
| key.c_str(), |
| value ? TRUE : FALSE); |
| return true; |
| } |
| |
| bool KeyFileStore::GetInt( |
| const string &group, const string &key, int *value) const { |
| CHECK(key_file_); |
| GError *error = NULL; |
| gint data = |
| glib_->KeyFileGetInteger(key_file_, group.c_str(), key.c_str(), &error); |
| if (error) { |
| LOG(ERROR) << "Failed to lookup (" << group << ":" << key << "): " |
| << glib_->ConvertErrorToMessage(error); |
| return false; |
| } |
| if (value) { |
| *value = data; |
| } |
| return true; |
| } |
| |
| bool KeyFileStore::SetInt(const string &group, const string &key, int value) { |
| CHECK(key_file_); |
| glib_->KeyFileSetInteger(key_file_, group.c_str(), key.c_str(), value); |
| return true; |
| } |
| |
| bool KeyFileStore::GetStringList(const string &group, |
| const string &key, |
| vector<string> *value) const { |
| CHECK(key_file_); |
| gsize length = 0; |
| GError *error = NULL; |
| gchar **data = glib_->KeyFileGetStringList(key_file_, |
| group.c_str(), |
| key.c_str(), |
| &length, |
| &error); |
| if (!data) { |
| LOG(ERROR) << "Failed to lookup (" << group << ":" << key << "): " |
| << glib_->ConvertErrorToMessage(error); |
| return false; |
| } |
| if (value) { |
| value->assign(data, data + length); |
| } |
| glib_->Strfreev(data); |
| return true; |
| } |
| |
| bool KeyFileStore::SetStringList(const string &group, |
| const string &key, |
| const vector<string> &value) { |
| CHECK(key_file_); |
| vector<const char *> list; |
| for (vector<string>::const_iterator it = value.begin(); |
| it != value.end(); ++it) { |
| list.push_back(it->c_str()); |
| } |
| glib_->KeyFileSetStringList(key_file_, |
| group.c_str(), |
| key.c_str(), |
| list.data(), |
| list.size()); |
| return true; |
| } |
| |
| bool KeyFileStore::GetCryptedString(const string &group, |
| const string &key, |
| string *value) { |
| if (!GetString(group, key, value)) { |
| return false; |
| } |
| if (value) { |
| *value = crypto_.Decrypt(*value); |
| } |
| return true; |
| } |
| |
| bool KeyFileStore::SetCryptedString(const string &group, |
| const string &key, |
| const string &value) { |
| return SetString(group, key, crypto_.Encrypt(value)); |
| } |
| |
| } // namespace shill |