blob: 9fc2d1972b786e0b6da24e8fac091703d6c06884 [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 Stewart5dc40aa2011-10-28 19:43:43 -070032bool KeyFileStore::IsNonEmpty() {
33 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
95set<string> KeyFileStore::GetGroups() {
96 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.
110set<string> KeyFileStore::GetGroupsWithKey(const string &key) {
111 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
Darin Petkov083047b2011-06-23 20:42:48 -0700121bool KeyFileStore::ContainsGroup(const string &group) {
122 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,
163 string *value) {
164 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,
190 bool *value) {
191 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
215bool KeyFileStore::GetInt(const string &group, const string &key, int *value) {
216 CHECK(key_file_);
217 GError *error = NULL;
218 gint data =
219 glib_->KeyFileGetInteger(key_file_, group.c_str(), key.c_str(), &error);
220 if (error) {
221 LOG(ERROR) << "Failed to lookup (" << group << ":" << key << "): "
222 << glib_->ConvertErrorToMessage(error);
223 return false;
224 }
225 if (value) {
226 *value = data;
227 }
228 return true;
229}
230
231bool KeyFileStore::SetInt(const string &group, const string &key, int value) {
232 CHECK(key_file_);
233 glib_->KeyFileSetInteger(key_file_, group.c_str(), key.c_str(), value);
234 return true;
235}
236
Darin Petkovb2841fd2011-06-30 12:54:12 -0700237bool KeyFileStore::GetStringList(const string &group,
238 const string &key,
239 vector<string> *value) {
240 CHECK(key_file_);
241 gsize length = 0;
242 GError *error = NULL;
243 gchar **data = glib_->KeyFileGetStringList(key_file_,
244 group.c_str(),
245 key.c_str(),
246 &length,
247 &error);
248 if (!data) {
249 LOG(ERROR) << "Failed to lookup (" << group << ":" << key << "): "
250 << glib_->ConvertErrorToMessage(error);
251 return false;
252 }
253 if (value) {
254 value->assign(data, data + length);
255 }
256 glib_->Strfreev(data);
257 return true;
258}
259
260bool KeyFileStore::SetStringList(const string &group,
261 const string &key,
262 const vector<string> &value) {
263 CHECK(key_file_);
264 vector<const char *> list;
265 for (vector<string>::const_iterator it = value.begin();
266 it != value.end(); ++it) {
267 list.push_back(it->c_str());
268 }
269 glib_->KeyFileSetStringList(key_file_,
270 group.c_str(),
271 key.c_str(),
272 list.data(),
273 list.size());
274 return true;
275}
276
Darin Petkov86964e02011-06-29 13:49:28 -0700277bool KeyFileStore::GetCryptedString(const string &group,
278 const string &key,
279 string *value) {
280 if (!GetString(group, key, value)) {
281 return false;
282 }
283 if (value) {
284 *value = crypto_.Decrypt(*value);
285 }
286 return true;
287}
288
289bool KeyFileStore::SetCryptedString(const string &group,
290 const string &key,
291 const string &value) {
292 return SetString(group, key, crypto_.Encrypt(value));
293}
294
Darin Petkov083047b2011-06-23 20:42:48 -0700295} // namespace shill