blob: 4fefef05f6a835c7a153093083af599f093c499d [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>
Gary Morain96970242012-04-20 10:59:58 -07009#include <fcntl.h>
10#include <sys/stat.h>
11#include <sys/types.h>
Darin Petkov083047b2011-06-23 20:42:48 -070012
Ben Chanfad4a0b2012-04-18 15:49:59 -070013#include "shill/scope_logger.h"
14
Darin Petkov083047b2011-06-23 20:42:48 -070015using std::set;
16using std::string;
Darin Petkovb2841fd2011-06-30 12:54:12 -070017using std::vector;
Darin Petkov083047b2011-06-23 20:42:48 -070018
19namespace shill {
20
Darin Petkov86964e02011-06-29 13:49:28 -070021KeyFileStore::KeyFileStore(GLib *glib)
22 : glib_(glib),
23 crypto_(glib),
24 key_file_(NULL) {}
Darin Petkov083047b2011-06-23 20:42:48 -070025
26KeyFileStore::~KeyFileStore() {
27 ReleaseKeyFile();
28}
29
30void KeyFileStore::ReleaseKeyFile() {
31 if (key_file_) {
32 glib_->KeyFileFree(key_file_);
33 key_file_ = NULL;
34 }
35}
36
Paul Stewart0756db92012-01-27 08:34:47 -080037bool KeyFileStore::IsNonEmpty() const {
Paul Stewart5dc40aa2011-10-28 19:43:43 -070038 int64 file_size = 0;
39 return file_util::GetFileSize(path_, &file_size) && file_size != 0;
40}
41
Darin Petkov083047b2011-06-23 20:42:48 -070042bool KeyFileStore::Open() {
43 CHECK(!path_.empty());
44 CHECK(!key_file_);
Darin Petkov86964e02011-06-29 13:49:28 -070045 crypto_.Init();
Darin Petkov083047b2011-06-23 20:42:48 -070046 key_file_ = glib_->KeyFileNew();
Paul Stewart5dc40aa2011-10-28 19:43:43 -070047 if (!IsNonEmpty()) {
Darin Petkov083047b2011-06-23 20:42:48 -070048 LOG(INFO) << "Creating a new key file at " << path_.value();
49 return true;
50 }
51 GError *error = NULL;
52 if (glib_->KeyFileLoadFromFile(
53 key_file_,
54 path_.value().c_str(),
55 static_cast<GKeyFileFlags>(G_KEY_FILE_KEEP_COMMENTS |
56 G_KEY_FILE_KEEP_TRANSLATIONS),
57 &error)) {
58 return true;
59 }
60 LOG(ERROR) << "Failed to load key file from " << path_.value() << ": "
61 << glib_->ConvertErrorToMessage(error);
62 ReleaseKeyFile();
63 return false;
64}
65
66bool KeyFileStore::Close() {
Chris Masoneb9c00592011-10-06 13:10:39 -070067 bool success = Flush();
68 ReleaseKeyFile();
69 return success;
70}
71
72bool KeyFileStore::Flush() {
Darin Petkov083047b2011-06-23 20:42:48 -070073 CHECK(key_file_);
74 GError *error = NULL;
75 gsize length = 0;
76 gchar *data = glib_->KeyFileToData(key_file_, &length, &error);
Darin Petkov083047b2011-06-23 20:42:48 -070077
78 bool success = true;
79 if (path_.empty()) {
80 LOG(ERROR) << "Empty key file path.";
81 success = false;
82 }
83 if (success && (!data || error)) {
84 LOG(ERROR) << "Failed to convert key file to string: "
85 << glib_->ConvertErrorToMessage(error);
86 success = false;
87 }
mukesh agrawalf60e4062011-05-27 13:13:41 -070088 if (success) {
Gary Morain96970242012-04-20 10:59:58 -070089 // The profile file must be accessible by the owner only.
90 int fd = creat(path_.value().c_str(), S_IRUSR | S_IWUSR);
91 if (fd < 0) {
92 LOG(ERROR) << "Failed to create key file " << path_.value();
mukesh agrawalf60e4062011-05-27 13:13:41 -070093 success = false;
Gary Morain96970242012-04-20 10:59:58 -070094 } else {
95 int written = file_util::WriteFileDescriptor(fd, data, length);
96 if (written < 0 || (static_cast<gsize>(written) != length)) {
97 LOG(ERROR) << "Failed to store key file: " << path_.value();
98 success = false;
99 }
100 close(fd);
mukesh agrawalf60e4062011-05-27 13:13:41 -0700101 }
Darin Petkov083047b2011-06-23 20:42:48 -0700102 }
103 glib_->Free(data);
104 return success;
105}
106
Paul Stewart0756db92012-01-27 08:34:47 -0800107set<string> KeyFileStore::GetGroups() const {
Darin Petkov083047b2011-06-23 20:42:48 -0700108 CHECK(key_file_);
109 gsize length = 0;
Paul Stewarta41e38d2011-11-11 07:47:29 -0800110 gchar **groups = glib_->KeyFileGetGroups(key_file_, &length);
Darin Petkov083047b2011-06-23 20:42:48 -0700111 if (!groups) {
112 LOG(ERROR) << "Unable to obtain groups.";
113 return set<string>();
114 }
115 set<string> group_set(groups, groups + length);
116 glib_->Strfreev(groups);
117 return group_set;
118}
119
Paul Stewarta41e38d2011-11-11 07:47:29 -0800120// Returns a set so that caller can easily test whether a particular group
121// is contained within this collection.
Paul Stewart0756db92012-01-27 08:34:47 -0800122set<string> KeyFileStore::GetGroupsWithKey(const string &key) const {
Paul Stewarta41e38d2011-11-11 07:47:29 -0800123 set<string> groups = GetGroups();
124 set<string> groups_with_key;
125 for (set<string>::iterator it = groups.begin(); it != groups.end(); ++it) {
126 if (glib_->KeyFileHasKey(key_file_, (*it).c_str(), key.c_str(), NULL)) {
127 groups_with_key.insert(*it);
128 }
129 }
130 return groups_with_key;
131}
132
Paul Stewart0756db92012-01-27 08:34:47 -0800133bool KeyFileStore::ContainsGroup(const string &group) const {
Darin Petkov083047b2011-06-23 20:42:48 -0700134 CHECK(key_file_);
135 return glib_->KeyFileHasGroup(key_file_, group.c_str());
136}
137
138bool KeyFileStore::DeleteKey(const string &group, const string &key) {
139 CHECK(key_file_);
140 GError *error = NULL;
141 glib_->KeyFileRemoveKey(key_file_, group.c_str(), key.c_str(), &error);
Chris Masone9d779932011-08-25 16:33:41 -0700142 if (error && error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
Darin Petkov083047b2011-06-23 20:42:48 -0700143 LOG(ERROR) << "Failed to delete (" << group << ":" << key << "): "
144 << glib_->ConvertErrorToMessage(error);
145 return false;
146 }
147 return true;
148}
149
150bool KeyFileStore::DeleteGroup(const string &group) {
151 CHECK(key_file_);
152 GError *error = NULL;
153 glib_->KeyFileRemoveGroup(key_file_, group.c_str(), &error);
Chris Masone9d779932011-08-25 16:33:41 -0700154 if (error && error->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND) {
Darin Petkov86964e02011-06-29 13:49:28 -0700155 LOG(ERROR) << "Failed to delete group " << group << ": "
Darin Petkov083047b2011-06-23 20:42:48 -0700156 << glib_->ConvertErrorToMessage(error);
157 return false;
158 }
159 return true;
160}
161
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700162bool KeyFileStore::SetHeader(const string &header) {
163 GError *error = NULL;
164 glib_->KeyFileSetComment(key_file_, NULL, NULL, header.c_str(), &error);
165 if (error) {
166 LOG(ERROR) << "Failed to to set header: "
167 << glib_->ConvertErrorToMessage(error);
168 return false;
169 }
170 return true;
171}
172
Darin Petkov083047b2011-06-23 20:42:48 -0700173bool KeyFileStore::GetString(const string &group,
174 const string &key,
Paul Stewart0756db92012-01-27 08:34:47 -0800175 string *value) const {
Darin Petkov083047b2011-06-23 20:42:48 -0700176 CHECK(key_file_);
177 GError *error = NULL;
178 gchar *data =
179 glib_->KeyFileGetString(key_file_, group.c_str(), key.c_str(), &error);
180 if (!data) {
Darin Petkovc529c832012-04-18 14:59:42 +0200181 string s = glib_->ConvertErrorToMessage(error);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700182 SLOG(Storage, 10) << "Failed to lookup (" << group << ":" << key << "): "
183 << s;
Darin Petkov083047b2011-06-23 20:42:48 -0700184 return false;
185 }
186 if (value) {
187 *value = data;
188 }
189 glib_->Free(data);
190 return true;
191}
192
193bool KeyFileStore::SetString(const string &group,
194 const string &key,
195 const string &value) {
196 CHECK(key_file_);
197 glib_->KeyFileSetString(key_file_, group.c_str(), key.c_str(), value.c_str());
198 return true;
199}
200
201bool KeyFileStore::GetBool(const string &group,
202 const string &key,
Paul Stewart0756db92012-01-27 08:34:47 -0800203 bool *value) const {
Darin Petkov083047b2011-06-23 20:42:48 -0700204 CHECK(key_file_);
205 GError *error = NULL;
206 gboolean data =
207 glib_->KeyFileGetBoolean(key_file_, group.c_str(), key.c_str(), &error);
208 if (error) {
Darin Petkovc529c832012-04-18 14:59:42 +0200209 string s = glib_->ConvertErrorToMessage(error);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700210 SLOG(Storage, 10) << "Failed to lookup (" << group << ":" << key << "): "
211 << s;
Darin Petkov083047b2011-06-23 20:42:48 -0700212 return false;
213 }
214 if (value) {
215 *value = data;
216 }
217 return true;
218}
219
220bool KeyFileStore::SetBool(const string &group, const string &key, bool value) {
221 CHECK(key_file_);
222 glib_->KeyFileSetBoolean(key_file_,
223 group.c_str(),
224 key.c_str(),
225 value ? TRUE : FALSE);
226 return true;
227}
228
Paul Stewart0756db92012-01-27 08:34:47 -0800229bool KeyFileStore::GetInt(
230 const string &group, const string &key, int *value) const {
Darin Petkov083047b2011-06-23 20:42:48 -0700231 CHECK(key_file_);
232 GError *error = NULL;
233 gint data =
234 glib_->KeyFileGetInteger(key_file_, group.c_str(), key.c_str(), &error);
235 if (error) {
Darin Petkovc529c832012-04-18 14:59:42 +0200236 string s = glib_->ConvertErrorToMessage(error);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700237 SLOG(Storage, 10) << "Failed to lookup (" << group << ":" << key << "): "
238 << s;
Darin Petkov083047b2011-06-23 20:42:48 -0700239 return false;
240 }
241 if (value) {
242 *value = data;
243 }
244 return true;
245}
246
247bool KeyFileStore::SetInt(const string &group, const string &key, int value) {
248 CHECK(key_file_);
249 glib_->KeyFileSetInteger(key_file_, group.c_str(), key.c_str(), value);
250 return true;
251}
252
Darin Petkovb2841fd2011-06-30 12:54:12 -0700253bool KeyFileStore::GetStringList(const string &group,
254 const string &key,
Paul Stewart0756db92012-01-27 08:34:47 -0800255 vector<string> *value) const {
Darin Petkovb2841fd2011-06-30 12:54:12 -0700256 CHECK(key_file_);
257 gsize length = 0;
258 GError *error = NULL;
259 gchar **data = glib_->KeyFileGetStringList(key_file_,
260 group.c_str(),
261 key.c_str(),
262 &length,
263 &error);
264 if (!data) {
Darin Petkovc529c832012-04-18 14:59:42 +0200265 string s = glib_->ConvertErrorToMessage(error);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700266 SLOG(Storage, 10) << "Failed to lookup (" << group << ":" << key << "): "
267 << s;
Darin Petkovb2841fd2011-06-30 12:54:12 -0700268 return false;
269 }
270 if (value) {
271 value->assign(data, data + length);
272 }
273 glib_->Strfreev(data);
274 return true;
275}
276
277bool KeyFileStore::SetStringList(const string &group,
278 const string &key,
279 const vector<string> &value) {
280 CHECK(key_file_);
281 vector<const char *> list;
282 for (vector<string>::const_iterator it = value.begin();
283 it != value.end(); ++it) {
284 list.push_back(it->c_str());
285 }
286 glib_->KeyFileSetStringList(key_file_,
287 group.c_str(),
288 key.c_str(),
289 list.data(),
290 list.size());
291 return true;
292}
293
Darin Petkov86964e02011-06-29 13:49:28 -0700294bool KeyFileStore::GetCryptedString(const string &group,
295 const string &key,
296 string *value) {
297 if (!GetString(group, key, value)) {
298 return false;
299 }
300 if (value) {
301 *value = crypto_.Decrypt(*value);
302 }
303 return true;
304}
305
306bool KeyFileStore::SetCryptedString(const string &group,
307 const string &key,
308 const string &value) {
309 return SetString(group, key, crypto_.Encrypt(value));
310}
311
Darin Petkov083047b2011-06-23 20:42:48 -0700312} // namespace shill