blob: 7abff9908d26df82156ca34d4bcc04a680fa1edf [file] [log] [blame]
Darin Petkovc529c832012-04-18 14:59:42 +02001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Darin Petkov083047b2011-06-23 20:42:48 -07002// 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
Ben Chanfad4a0b2012-04-18 15:49:59 -070010#include "shill/scope_logger.h"
11
Darin Petkov083047b2011-06-23 20:42:48 -070012using std::set;
13using std::string;
Darin Petkovb2841fd2011-06-30 12:54:12 -070014using std::vector;
Darin Petkov083047b2011-06-23 20:42:48 -070015
16namespace shill {
17
Darin Petkov86964e02011-06-29 13:49:28 -070018KeyFileStore::KeyFileStore(GLib *glib)
19 : glib_(glib),
20 crypto_(glib),
21 key_file_(NULL) {}
Darin Petkov083047b2011-06-23 20:42:48 -070022
23KeyFileStore::~KeyFileStore() {
24 ReleaseKeyFile();
25}
26
27void KeyFileStore::ReleaseKeyFile() {
28 if (key_file_) {
29 glib_->KeyFileFree(key_file_);
30 key_file_ = NULL;
31 }
32}
33
Paul Stewart0756db92012-01-27 08:34:47 -080034bool KeyFileStore::IsNonEmpty() const {
Paul Stewart5dc40aa2011-10-28 19:43:43 -070035 int64 file_size = 0;
36 return file_util::GetFileSize(path_, &file_size) && file_size != 0;
37}
38
Darin Petkov083047b2011-06-23 20:42:48 -070039bool KeyFileStore::Open() {
40 CHECK(!path_.empty());
41 CHECK(!key_file_);
Darin Petkov86964e02011-06-29 13:49:28 -070042 crypto_.Init();
Darin Petkov083047b2011-06-23 20:42:48 -070043 key_file_ = glib_->KeyFileNew();
Paul Stewart5dc40aa2011-10-28 19:43:43 -070044 if (!IsNonEmpty()) {
Darin Petkov083047b2011-06-23 20:42:48 -070045 LOG(INFO) << "Creating a new key file at " << path_.value();
46 return true;
47 }
48 GError *error = NULL;
49 if (glib_->KeyFileLoadFromFile(
50 key_file_,
51 path_.value().c_str(),
52 static_cast<GKeyFileFlags>(G_KEY_FILE_KEEP_COMMENTS |
53 G_KEY_FILE_KEEP_TRANSLATIONS),
54 &error)) {
55 return true;
56 }
57 LOG(ERROR) << "Failed to load key file from " << path_.value() << ": "
58 << glib_->ConvertErrorToMessage(error);
59 ReleaseKeyFile();
60 return false;
61}
62
63bool KeyFileStore::Close() {
Chris Masoneb9c00592011-10-06 13:10:39 -070064 bool success = Flush();
65 ReleaseKeyFile();
66 return success;
67}
68
69bool KeyFileStore::Flush() {
Darin Petkov083047b2011-06-23 20:42:48 -070070 CHECK(key_file_);
71 GError *error = NULL;
72 gsize length = 0;
73 gchar *data = glib_->KeyFileToData(key_file_, &length, &error);
Darin Petkov083047b2011-06-23 20:42:48 -070074
75 bool success = true;
76 if (path_.empty()) {
77 LOG(ERROR) << "Empty key file path.";
78 success = false;
79 }
80 if (success && (!data || error)) {
81 LOG(ERROR) << "Failed to convert key file to string: "
82 << glib_->ConvertErrorToMessage(error);
83 success = false;
84 }
mukesh agrawalf60e4062011-05-27 13:13:41 -070085 if (success) {
86 int written = file_util::WriteFile(path_, data, length);
87 if (written < 0 ||
88 static_cast<unsigned int>(written) != length) {
89 LOG(ERROR) << "Failed to store key file: " << path_.value();
90 success = false;
91 }
Darin Petkov083047b2011-06-23 20:42:48 -070092 }
93 glib_->Free(data);
94 return success;
95}
96
Paul Stewart0756db92012-01-27 08:34:47 -080097set<string> KeyFileStore::GetGroups() const {
Darin Petkov083047b2011-06-23 20:42:48 -070098 CHECK(key_file_);
99 gsize length = 0;
Paul Stewarta41e38d2011-11-11 07:47:29 -0800100 gchar **groups = glib_->KeyFileGetGroups(key_file_, &length);
Darin Petkov083047b2011-06-23 20:42:48 -0700101 if (!groups) {
102 LOG(ERROR) << "Unable to obtain groups.";
103 return set<string>();
104 }
105 set<string> group_set(groups, groups + length);
106 glib_->Strfreev(groups);
107 return group_set;
108}
109
Paul Stewarta41e38d2011-11-11 07:47:29 -0800110// Returns a set so that caller can easily test whether a particular group
111// is contained within this collection.
Paul Stewart0756db92012-01-27 08:34:47 -0800112set<string> KeyFileStore::GetGroupsWithKey(const string &key) const {
Paul Stewarta41e38d2011-11-11 07:47:29 -0800113 set<string> groups = GetGroups();
114 set<string> groups_with_key;
115 for (set<string>::iterator it = groups.begin(); it != groups.end(); ++it) {
116 if (glib_->KeyFileHasKey(key_file_, (*it).c_str(), key.c_str(), NULL)) {
117 groups_with_key.insert(*it);
118 }
119 }
120 return groups_with_key;
121}
122
Paul Stewart0756db92012-01-27 08:34:47 -0800123bool KeyFileStore::ContainsGroup(const string &group) const {
Darin Petkov083047b2011-06-23 20:42:48 -0700124 CHECK(key_file_);
125 return glib_->KeyFileHasGroup(key_file_, group.c_str());
126}
127
128bool KeyFileStore::DeleteKey(const string &group, const string &key) {
129 CHECK(key_file_);
130 GError *error = NULL;
131 glib_->KeyFileRemoveKey(key_file_, group.c_str(), key.c_str(), &error);
Chris Masone9d779932011-08-25 16:33:41 -0700132 if (error && error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
Darin Petkov083047b2011-06-23 20:42:48 -0700133 LOG(ERROR) << "Failed to delete (" << group << ":" << key << "): "
134 << glib_->ConvertErrorToMessage(error);
135 return false;
136 }
137 return true;
138}
139
140bool KeyFileStore::DeleteGroup(const string &group) {
141 CHECK(key_file_);
142 GError *error = NULL;
143 glib_->KeyFileRemoveGroup(key_file_, group.c_str(), &error);
Chris Masone9d779932011-08-25 16:33:41 -0700144 if (error && error->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND) {
Darin Petkov86964e02011-06-29 13:49:28 -0700145 LOG(ERROR) << "Failed to delete group " << group << ": "
Darin Petkov083047b2011-06-23 20:42:48 -0700146 << glib_->ConvertErrorToMessage(error);
147 return false;
148 }
149 return true;
150}
151
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700152bool KeyFileStore::SetHeader(const string &header) {
153 GError *error = NULL;
154 glib_->KeyFileSetComment(key_file_, NULL, NULL, header.c_str(), &error);
155 if (error) {
156 LOG(ERROR) << "Failed to to set header: "
157 << glib_->ConvertErrorToMessage(error);
158 return false;
159 }
160 return true;
161}
162
Darin Petkov083047b2011-06-23 20:42:48 -0700163bool KeyFileStore::GetString(const string &group,
164 const string &key,
Paul Stewart0756db92012-01-27 08:34:47 -0800165 string *value) const {
Darin Petkov083047b2011-06-23 20:42:48 -0700166 CHECK(key_file_);
167 GError *error = NULL;
168 gchar *data =
169 glib_->KeyFileGetString(key_file_, group.c_str(), key.c_str(), &error);
170 if (!data) {
Darin Petkovc529c832012-04-18 14:59:42 +0200171 string s = glib_->ConvertErrorToMessage(error);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700172 SLOG(Storage, 10) << "Failed to lookup (" << group << ":" << key << "): "
173 << s;
Darin Petkov083047b2011-06-23 20:42:48 -0700174 return false;
175 }
176 if (value) {
177 *value = data;
178 }
179 glib_->Free(data);
180 return true;
181}
182
183bool KeyFileStore::SetString(const string &group,
184 const string &key,
185 const string &value) {
186 CHECK(key_file_);
187 glib_->KeyFileSetString(key_file_, group.c_str(), key.c_str(), value.c_str());
188 return true;
189}
190
191bool KeyFileStore::GetBool(const string &group,
192 const string &key,
Paul Stewart0756db92012-01-27 08:34:47 -0800193 bool *value) const {
Darin Petkov083047b2011-06-23 20:42:48 -0700194 CHECK(key_file_);
195 GError *error = NULL;
196 gboolean data =
197 glib_->KeyFileGetBoolean(key_file_, group.c_str(), key.c_str(), &error);
198 if (error) {
Darin Petkovc529c832012-04-18 14:59:42 +0200199 string s = glib_->ConvertErrorToMessage(error);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700200 SLOG(Storage, 10) << "Failed to lookup (" << group << ":" << key << "): "
201 << s;
Darin Petkov083047b2011-06-23 20:42:48 -0700202 return false;
203 }
204 if (value) {
205 *value = data;
206 }
207 return true;
208}
209
210bool KeyFileStore::SetBool(const string &group, const string &key, bool value) {
211 CHECK(key_file_);
212 glib_->KeyFileSetBoolean(key_file_,
213 group.c_str(),
214 key.c_str(),
215 value ? TRUE : FALSE);
216 return true;
217}
218
Paul Stewart0756db92012-01-27 08:34:47 -0800219bool KeyFileStore::GetInt(
220 const string &group, const string &key, int *value) const {
Darin Petkov083047b2011-06-23 20:42:48 -0700221 CHECK(key_file_);
222 GError *error = NULL;
223 gint data =
224 glib_->KeyFileGetInteger(key_file_, group.c_str(), key.c_str(), &error);
225 if (error) {
Darin Petkovc529c832012-04-18 14:59:42 +0200226 string s = glib_->ConvertErrorToMessage(error);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700227 SLOG(Storage, 10) << "Failed to lookup (" << group << ":" << key << "): "
228 << s;
Darin Petkov083047b2011-06-23 20:42:48 -0700229 return false;
230 }
231 if (value) {
232 *value = data;
233 }
234 return true;
235}
236
237bool KeyFileStore::SetInt(const string &group, const string &key, int value) {
238 CHECK(key_file_);
239 glib_->KeyFileSetInteger(key_file_, group.c_str(), key.c_str(), value);
240 return true;
241}
242
Darin Petkovb2841fd2011-06-30 12:54:12 -0700243bool KeyFileStore::GetStringList(const string &group,
244 const string &key,
Paul Stewart0756db92012-01-27 08:34:47 -0800245 vector<string> *value) const {
Darin Petkovb2841fd2011-06-30 12:54:12 -0700246 CHECK(key_file_);
247 gsize length = 0;
248 GError *error = NULL;
249 gchar **data = glib_->KeyFileGetStringList(key_file_,
250 group.c_str(),
251 key.c_str(),
252 &length,
253 &error);
254 if (!data) {
Darin Petkovc529c832012-04-18 14:59:42 +0200255 string s = glib_->ConvertErrorToMessage(error);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700256 SLOG(Storage, 10) << "Failed to lookup (" << group << ":" << key << "): "
257 << s;
Darin Petkovb2841fd2011-06-30 12:54:12 -0700258 return false;
259 }
260 if (value) {
261 value->assign(data, data + length);
262 }
263 glib_->Strfreev(data);
264 return true;
265}
266
267bool KeyFileStore::SetStringList(const string &group,
268 const string &key,
269 const vector<string> &value) {
270 CHECK(key_file_);
271 vector<const char *> list;
272 for (vector<string>::const_iterator it = value.begin();
273 it != value.end(); ++it) {
274 list.push_back(it->c_str());
275 }
276 glib_->KeyFileSetStringList(key_file_,
277 group.c_str(),
278 key.c_str(),
279 list.data(),
280 list.size());
281 return true;
282}
283
Darin Petkov86964e02011-06-29 13:49:28 -0700284bool KeyFileStore::GetCryptedString(const string &group,
285 const string &key,
286 string *value) {
287 if (!GetString(group, key, value)) {
288 return false;
289 }
290 if (value) {
291 *value = crypto_.Decrypt(*value);
292 }
293 return true;
294}
295
296bool KeyFileStore::SetCryptedString(const string &group,
297 const string &key,
298 const string &value) {
299 return SetString(group, key, crypto_.Encrypt(value));
300}
301
Darin Petkov083047b2011-06-23 20:42:48 -0700302} // namespace shill