blob: fa823aaa30d55a0c0e91875c77d6bdd8579f9957 [file] [log] [blame]
Darin Petkov083047b2011-06-23 20:42:48 -07001// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "shill/key_file_store.h"
6
7#include <base/file_util.h>
8#include <base/logging.h>
9
10using std::set;
11using std::string;
Darin Petkovb2841fd2011-06-30 12:54:12 -070012using std::vector;
Darin Petkov083047b2011-06-23 20:42:48 -070013
14namespace shill {
15
Darin Petkov86964e02011-06-29 13:49:28 -070016KeyFileStore::KeyFileStore(GLib *glib)
17 : glib_(glib),
18 crypto_(glib),
19 key_file_(NULL) {}
Darin Petkov083047b2011-06-23 20:42:48 -070020
21KeyFileStore::~KeyFileStore() {
22 ReleaseKeyFile();
23}
24
25void KeyFileStore::ReleaseKeyFile() {
26 if (key_file_) {
27 glib_->KeyFileFree(key_file_);
28 key_file_ = NULL;
29 }
30}
31
Paul Stewart0756db92012-01-27 08:34:47 -080032bool KeyFileStore::IsNonEmpty() const {
Paul Stewart5dc40aa2011-10-28 19:43:43 -070033 int64 file_size = 0;
34 return file_util::GetFileSize(path_, &file_size) && file_size != 0;
35}
36
Darin Petkov083047b2011-06-23 20:42:48 -070037bool KeyFileStore::Open() {
38 CHECK(!path_.empty());
39 CHECK(!key_file_);
Darin Petkov86964e02011-06-29 13:49:28 -070040 crypto_.Init();
Darin Petkov083047b2011-06-23 20:42:48 -070041 key_file_ = glib_->KeyFileNew();
Paul Stewart5dc40aa2011-10-28 19:43:43 -070042 if (!IsNonEmpty()) {
Darin Petkov083047b2011-06-23 20:42:48 -070043 LOG(INFO) << "Creating a new key file at " << path_.value();
44 return true;
45 }
46 GError *error = NULL;
47 if (glib_->KeyFileLoadFromFile(
48 key_file_,
49 path_.value().c_str(),
50 static_cast<GKeyFileFlags>(G_KEY_FILE_KEEP_COMMENTS |
51 G_KEY_FILE_KEEP_TRANSLATIONS),
52 &error)) {
53 return true;
54 }
55 LOG(ERROR) << "Failed to load key file from " << path_.value() << ": "
56 << glib_->ConvertErrorToMessage(error);
57 ReleaseKeyFile();
58 return false;
59}
60
61bool KeyFileStore::Close() {
Chris Masoneb9c00592011-10-06 13:10:39 -070062 bool success = Flush();
63 ReleaseKeyFile();
64 return success;
65}
66
67bool KeyFileStore::Flush() {
Darin Petkov083047b2011-06-23 20:42:48 -070068 CHECK(key_file_);
69 GError *error = NULL;
70 gsize length = 0;
71 gchar *data = glib_->KeyFileToData(key_file_, &length, &error);
Darin Petkov083047b2011-06-23 20:42:48 -070072
73 bool success = true;
74 if (path_.empty()) {
75 LOG(ERROR) << "Empty key file path.";
76 success = false;
77 }
78 if (success && (!data || error)) {
79 LOG(ERROR) << "Failed to convert key file to string: "
80 << glib_->ConvertErrorToMessage(error);
81 success = false;
82 }
mukesh agrawalf60e4062011-05-27 13:13:41 -070083 if (success) {
84 int written = file_util::WriteFile(path_, data, length);
85 if (written < 0 ||
86 static_cast<unsigned int>(written) != length) {
87 LOG(ERROR) << "Failed to store key file: " << path_.value();
88 success = false;
89 }
Darin Petkov083047b2011-06-23 20:42:48 -070090 }
91 glib_->Free(data);
92 return success;
93}
94
Paul Stewart0756db92012-01-27 08:34:47 -080095set<string> KeyFileStore::GetGroups() const {
Darin Petkov083047b2011-06-23 20:42:48 -070096 CHECK(key_file_);
97 gsize length = 0;
Paul Stewarta41e38d2011-11-11 07:47:29 -080098 gchar **groups = glib_->KeyFileGetGroups(key_file_, &length);
Darin Petkov083047b2011-06-23 20:42:48 -070099 if (!groups) {
100 LOG(ERROR) << "Unable to obtain groups.";
101 return set<string>();
102 }
103 set<string> group_set(groups, groups + length);
104 glib_->Strfreev(groups);
105 return group_set;
106}
107
Paul Stewarta41e38d2011-11-11 07:47:29 -0800108// Returns a set so that caller can easily test whether a particular group
109// is contained within this collection.
Paul Stewart0756db92012-01-27 08:34:47 -0800110set<string> KeyFileStore::GetGroupsWithKey(const string &key) const {
Paul Stewarta41e38d2011-11-11 07:47:29 -0800111 set<string> groups = GetGroups();
112 set<string> groups_with_key;
113 for (set<string>::iterator it = groups.begin(); it != groups.end(); ++it) {
114 if (glib_->KeyFileHasKey(key_file_, (*it).c_str(), key.c_str(), NULL)) {
115 groups_with_key.insert(*it);
116 }
117 }
118 return groups_with_key;
119}
120
Paul Stewart0756db92012-01-27 08:34:47 -0800121bool KeyFileStore::ContainsGroup(const string &group) const {
Darin Petkov083047b2011-06-23 20:42:48 -0700122 CHECK(key_file_);
123 return glib_->KeyFileHasGroup(key_file_, group.c_str());
124}
125
126bool KeyFileStore::DeleteKey(const string &group, const string &key) {
127 CHECK(key_file_);
128 GError *error = NULL;
129 glib_->KeyFileRemoveKey(key_file_, group.c_str(), key.c_str(), &error);
Chris Masone9d779932011-08-25 16:33:41 -0700130 if (error && error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
Darin Petkov083047b2011-06-23 20:42:48 -0700131 LOG(ERROR) << "Failed to delete (" << group << ":" << key << "): "
132 << glib_->ConvertErrorToMessage(error);
133 return false;
134 }
135 return true;
136}
137
138bool KeyFileStore::DeleteGroup(const string &group) {
139 CHECK(key_file_);
140 GError *error = NULL;
141 glib_->KeyFileRemoveGroup(key_file_, group.c_str(), &error);
Chris Masone9d779932011-08-25 16:33:41 -0700142 if (error && error->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND) {
Darin Petkov86964e02011-06-29 13:49:28 -0700143 LOG(ERROR) << "Failed to delete group " << group << ": "
Darin Petkov083047b2011-06-23 20:42:48 -0700144 << glib_->ConvertErrorToMessage(error);
145 return false;
146 }
147 return true;
148}
149
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700150bool KeyFileStore::SetHeader(const string &header) {
151 GError *error = NULL;
152 glib_->KeyFileSetComment(key_file_, NULL, NULL, header.c_str(), &error);
153 if (error) {
154 LOG(ERROR) << "Failed to to set header: "
155 << glib_->ConvertErrorToMessage(error);
156 return false;
157 }
158 return true;
159}
160
Darin Petkov083047b2011-06-23 20:42:48 -0700161bool KeyFileStore::GetString(const string &group,
162 const string &key,
Paul Stewart0756db92012-01-27 08:34:47 -0800163 string *value) const {
Darin Petkov083047b2011-06-23 20:42:48 -0700164 CHECK(key_file_);
165 GError *error = NULL;
166 gchar *data =
167 glib_->KeyFileGetString(key_file_, group.c_str(), key.c_str(), &error);
168 if (!data) {
169 LOG(ERROR) << "Failed to lookup (" << group << ":" << key << "): "
170 << glib_->ConvertErrorToMessage(error);
171 return false;
172 }
173 if (value) {
174 *value = data;
175 }
176 glib_->Free(data);
177 return true;
178}
179
180bool KeyFileStore::SetString(const string &group,
181 const string &key,
182 const string &value) {
183 CHECK(key_file_);
184 glib_->KeyFileSetString(key_file_, group.c_str(), key.c_str(), value.c_str());
185 return true;
186}
187
188bool KeyFileStore::GetBool(const string &group,
189 const string &key,
Paul Stewart0756db92012-01-27 08:34:47 -0800190 bool *value) const {
Darin Petkov083047b2011-06-23 20:42:48 -0700191 CHECK(key_file_);
192 GError *error = NULL;
193 gboolean data =
194 glib_->KeyFileGetBoolean(key_file_, group.c_str(), key.c_str(), &error);
195 if (error) {
196 LOG(ERROR) << "Failed to lookup (" << group << ":" << key << "): "
197 << glib_->ConvertErrorToMessage(error);
198 return false;
199 }
200 if (value) {
201 *value = data;
202 }
203 return true;
204}
205
206bool KeyFileStore::SetBool(const string &group, const string &key, bool value) {
207 CHECK(key_file_);
208 glib_->KeyFileSetBoolean(key_file_,
209 group.c_str(),
210 key.c_str(),
211 value ? TRUE : FALSE);
212 return true;
213}
214
Paul Stewart0756db92012-01-27 08:34:47 -0800215bool KeyFileStore::GetInt(
216 const string &group, const string &key, int *value) const {
Darin Petkov083047b2011-06-23 20:42:48 -0700217 CHECK(key_file_);
218 GError *error = NULL;
219 gint data =
220 glib_->KeyFileGetInteger(key_file_, group.c_str(), key.c_str(), &error);
221 if (error) {
222 LOG(ERROR) << "Failed to lookup (" << group << ":" << key << "): "
223 << glib_->ConvertErrorToMessage(error);
224 return false;
225 }
226 if (value) {
227 *value = data;
228 }
229 return true;
230}
231
232bool KeyFileStore::SetInt(const string &group, const string &key, int value) {
233 CHECK(key_file_);
234 glib_->KeyFileSetInteger(key_file_, group.c_str(), key.c_str(), value);
235 return true;
236}
237
Darin Petkovb2841fd2011-06-30 12:54:12 -0700238bool KeyFileStore::GetStringList(const string &group,
239 const string &key,
Paul Stewart0756db92012-01-27 08:34:47 -0800240 vector<string> *value) const {
Darin Petkovb2841fd2011-06-30 12:54:12 -0700241 CHECK(key_file_);
242 gsize length = 0;
243 GError *error = NULL;
244 gchar **data = glib_->KeyFileGetStringList(key_file_,
245 group.c_str(),
246 key.c_str(),
247 &length,
248 &error);
249 if (!data) {
250 LOG(ERROR) << "Failed to lookup (" << group << ":" << key << "): "
251 << glib_->ConvertErrorToMessage(error);
252 return false;
253 }
254 if (value) {
255 value->assign(data, data + length);
256 }
257 glib_->Strfreev(data);
258 return true;
259}
260
261bool KeyFileStore::SetStringList(const string &group,
262 const string &key,
263 const vector<string> &value) {
264 CHECK(key_file_);
265 vector<const char *> list;
266 for (vector<string>::const_iterator it = value.begin();
267 it != value.end(); ++it) {
268 list.push_back(it->c_str());
269 }
270 glib_->KeyFileSetStringList(key_file_,
271 group.c_str(),
272 key.c_str(),
273 list.data(),
274 list.size());
275 return true;
276}
277
Darin Petkov86964e02011-06-29 13:49:28 -0700278bool KeyFileStore::GetCryptedString(const string &group,
279 const string &key,
280 string *value) {
281 if (!GetString(group, key, value)) {
282 return false;
283 }
284 if (value) {
285 *value = crypto_.Decrypt(*value);
286 }
287 return true;
288}
289
290bool KeyFileStore::SetCryptedString(const string &group,
291 const string &key,
292 const string &value) {
293 return SetString(group, key, crypto_.Encrypt(value));
294}
295
Darin Petkov083047b2011-06-23 20:42:48 -0700296} // namespace shill