blob: 32c8683a14ae4bb13d5231937d011a1234df692c [file] [log] [blame]
Peter Qiuc0beca52015-09-03 11:25:46 -07001//
2// Copyright (C) 2012 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
Darin Petkov083047b2011-06-23 20:42:48 -070016
17#include "shill/key_file_store.h"
18
Paul Stewart5b9ec982013-01-18 14:12:14 -080019#include <map>
20
Peter Qiu3e7aff52014-03-26 13:03:40 -070021#include <base/files/important_file_writer.h>
Ben Chan11c213f2014-09-05 08:21:06 -070022#include <base/files/file_util.h>
Ben Chana0ddf462014-02-06 11:32:42 -080023#include <base/strings/string_number_conversions.h>
mukesh agrawal432d5a12015-08-25 17:57:17 -070024#include <base/strings/stringprintf.h>
Gary Morain96970242012-04-20 10:59:58 -070025#include <fcntl.h>
26#include <sys/stat.h>
27#include <sys/types.h>
Paul Stewart79963642013-06-12 15:44:17 -070028#include <unistd.h>
Darin Petkov083047b2011-06-23 20:42:48 -070029
Paul Stewart5b9ec982013-01-18 14:12:14 -080030#include "shill/key_value_store.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070031#include "shill/logging.h"
mukesh agrawal3ff527c2014-04-08 17:07:56 -070032#include "shill/scoped_umask.h"
Ben Chanfad4a0b2012-04-18 15:49:59 -070033
Paul Stewart5b9ec982013-01-18 14:12:14 -080034using std::map;
Darin Petkov083047b2011-06-23 20:42:48 -070035using std::set;
36using std::string;
Darin Petkovb2841fd2011-06-30 12:54:12 -070037using std::vector;
Darin Petkov083047b2011-06-23 20:42:48 -070038
39namespace shill {
40
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -070041namespace Logging {
42static auto kModuleLogScope = ScopeLogger::kStorage;
Paul Stewart8ae18742015-06-16 13:13:10 -070043static string ObjectID(const KeyFileStore* k) { return "(key_file_store)"; }
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -070044}
45
mukesh agrawal432d5a12015-08-25 17:57:17 -070046namespace {
47string ConvertErrorToMessage(GError* error) {
48 if (!error) {
49 return "Unknown GLib error.";
50 }
51 string message =
52 base::StringPrintf("GError(%d): %s", error->code, error->message);
53 g_error_free(error);
54 return message;
55}
56} // namespace
57
Paul Stewart2ebc16d2012-08-23 10:38:39 -070058const char KeyFileStore::kCorruptSuffix[] = ".corrupted";
59
mukesh agrawal78e05842015-08-27 11:29:19 -070060KeyFileStore::KeyFileStore(const base::FilePath& path)
mukesh agrawal1a25fac2015-08-25 18:38:58 -070061 : crypto_(),
mukesh agrawal78e05842015-08-27 11:29:19 -070062 key_file_(nullptr),
63 path_(path) {
64 CHECK(!path_.empty());
65}
Darin Petkov083047b2011-06-23 20:42:48 -070066
67KeyFileStore::~KeyFileStore() {
68 ReleaseKeyFile();
69}
70
71void KeyFileStore::ReleaseKeyFile() {
72 if (key_file_) {
mukesh agrawal432d5a12015-08-25 17:57:17 -070073 g_key_file_free(key_file_);
Ben Chancc225ef2014-09-30 13:26:51 -070074 key_file_ = nullptr;
Darin Petkov083047b2011-06-23 20:42:48 -070075 }
76}
77
Paul Stewart0756db92012-01-27 08:34:47 -080078bool KeyFileStore::IsNonEmpty() const {
Ben Chan7fab8972014-08-10 17:14:46 -070079 int64_t file_size = 0;
Ben Chana0ddf462014-02-06 11:32:42 -080080 return base::GetFileSize(path_, &file_size) && file_size != 0;
Paul Stewart5dc40aa2011-10-28 19:43:43 -070081}
82
Darin Petkov083047b2011-06-23 20:42:48 -070083bool KeyFileStore::Open() {
Darin Petkov083047b2011-06-23 20:42:48 -070084 CHECK(!key_file_);
Darin Petkov86964e02011-06-29 13:49:28 -070085 crypto_.Init();
mukesh agrawal432d5a12015-08-25 17:57:17 -070086 key_file_ = g_key_file_new();
Paul Stewart5dc40aa2011-10-28 19:43:43 -070087 if (!IsNonEmpty()) {
Darin Petkov083047b2011-06-23 20:42:48 -070088 LOG(INFO) << "Creating a new key file at " << path_.value();
89 return true;
90 }
Paul Stewart8ae18742015-06-16 13:13:10 -070091 GError* error = nullptr;
mukesh agrawal432d5a12015-08-25 17:57:17 -070092 if (g_key_file_load_from_file(
Darin Petkov083047b2011-06-23 20:42:48 -070093 key_file_,
94 path_.value().c_str(),
95 static_cast<GKeyFileFlags>(G_KEY_FILE_KEEP_COMMENTS |
96 G_KEY_FILE_KEEP_TRANSLATIONS),
97 &error)) {
98 return true;
99 }
100 LOG(ERROR) << "Failed to load key file from " << path_.value() << ": "
mukesh agrawal432d5a12015-08-25 17:57:17 -0700101 << ConvertErrorToMessage(error);
Darin Petkov083047b2011-06-23 20:42:48 -0700102 ReleaseKeyFile();
103 return false;
104}
105
106bool KeyFileStore::Close() {
Chris Masoneb9c00592011-10-06 13:10:39 -0700107 bool success = Flush();
108 ReleaseKeyFile();
109 return success;
110}
111
112bool KeyFileStore::Flush() {
Darin Petkov083047b2011-06-23 20:42:48 -0700113 CHECK(key_file_);
Paul Stewart8ae18742015-06-16 13:13:10 -0700114 GError* error = nullptr;
Darin Petkov083047b2011-06-23 20:42:48 -0700115 gsize length = 0;
mukesh agrawal432d5a12015-08-25 17:57:17 -0700116 gchar* data = g_key_file_to_data(key_file_, &length, &error);
Darin Petkov083047b2011-06-23 20:42:48 -0700117
118 bool success = true;
mukesh agrawala45f9a22015-08-27 15:26:36 -0700119 if (!data || error) {
Darin Petkov083047b2011-06-23 20:42:48 -0700120 LOG(ERROR) << "Failed to convert key file to string: "
mukesh agrawal432d5a12015-08-25 17:57:17 -0700121 << ConvertErrorToMessage(error);
Darin Petkov083047b2011-06-23 20:42:48 -0700122 success = false;
123 }
mukesh agrawalf60e4062011-05-27 13:13:41 -0700124 if (success) {
Samuel Tan82128c12015-09-24 20:58:01 -0700125 ScopedUmask owner_only_umask(~(S_IRUSR | S_IWUSR) & 0777);
Peter Qiu3e7aff52014-03-26 13:03:40 -0700126 success = base::ImportantFileWriter::WriteFileAtomically(path_, data);
Peter Qiu3e7aff52014-03-26 13:03:40 -0700127 if (!success) {
128 LOG(ERROR) << "Failed to store key file: " << path_.value();
mukesh agrawalf60e4062011-05-27 13:13:41 -0700129 }
Darin Petkov083047b2011-06-23 20:42:48 -0700130 }
mukesh agrawal432d5a12015-08-25 17:57:17 -0700131 g_free(data);
Darin Petkov083047b2011-06-23 20:42:48 -0700132 return success;
133}
134
Paul Stewart2ebc16d2012-08-23 10:38:39 -0700135bool KeyFileStore::MarkAsCorrupted() {
136 LOG(INFO) << "In " << __func__ << " for " << path_.value();
Paul Stewart2ebc16d2012-08-23 10:38:39 -0700137 string corrupted_path = path_.value() + kCorruptSuffix;
138 int ret = rename(path_.value().c_str(), corrupted_path.c_str());
139 if (ret != 0) {
140 PLOG(ERROR) << "File rename failed";
141 return false;
142 }
143 return true;
144}
145
Paul Stewart0756db92012-01-27 08:34:47 -0800146set<string> KeyFileStore::GetGroups() const {
Darin Petkov083047b2011-06-23 20:42:48 -0700147 CHECK(key_file_);
148 gsize length = 0;
mukesh agrawal432d5a12015-08-25 17:57:17 -0700149 gchar** groups = g_key_file_get_groups(key_file_, &length);
Darin Petkov083047b2011-06-23 20:42:48 -0700150 if (!groups) {
151 LOG(ERROR) << "Unable to obtain groups.";
152 return set<string>();
153 }
154 set<string> group_set(groups, groups + length);
mukesh agrawal432d5a12015-08-25 17:57:17 -0700155 g_strfreev(groups);
Darin Petkov083047b2011-06-23 20:42:48 -0700156 return group_set;
157}
158
Paul Stewarta41e38d2011-11-11 07:47:29 -0800159// Returns a set so that caller can easily test whether a particular group
160// is contained within this collection.
Paul Stewart8ae18742015-06-16 13:13:10 -0700161set<string> KeyFileStore::GetGroupsWithKey(const string& key) const {
Paul Stewarta41e38d2011-11-11 07:47:29 -0800162 set<string> groups = GetGroups();
163 set<string> groups_with_key;
Paul Stewart8ae18742015-06-16 13:13:10 -0700164 for (const auto& group : groups) {
mukesh agrawal432d5a12015-08-25 17:57:17 -0700165 if (g_key_file_has_key(key_file_, group.c_str(), key.c_str(), nullptr)) {
Paul Stewart6db7b242014-05-02 15:34:21 -0700166 groups_with_key.insert(group);
Paul Stewarta41e38d2011-11-11 07:47:29 -0800167 }
168 }
169 return groups_with_key;
170}
171
Paul Stewart5b9ec982013-01-18 14:12:14 -0800172set<string> KeyFileStore::GetGroupsWithProperties(
Paul Stewart8ae18742015-06-16 13:13:10 -0700173 const KeyValueStore& properties) const {
Paul Stewart5b9ec982013-01-18 14:12:14 -0800174 set<string> groups = GetGroups();
175 set<string> groups_with_properties;
Paul Stewart8ae18742015-06-16 13:13:10 -0700176 for (const auto& group : groups) {
Paul Stewart6db7b242014-05-02 15:34:21 -0700177 if (DoesGroupMatchProperties(group, properties)) {
178 groups_with_properties.insert(group);
Paul Stewart5b9ec982013-01-18 14:12:14 -0800179 }
180 }
181 return groups_with_properties;
182}
183
Paul Stewart8ae18742015-06-16 13:13:10 -0700184bool KeyFileStore::ContainsGroup(const string& group) const {
Darin Petkov083047b2011-06-23 20:42:48 -0700185 CHECK(key_file_);
mukesh agrawal432d5a12015-08-25 17:57:17 -0700186 return g_key_file_has_group(key_file_, group.c_str());
Darin Petkov083047b2011-06-23 20:42:48 -0700187}
188
Paul Stewart8ae18742015-06-16 13:13:10 -0700189bool KeyFileStore::DeleteKey(const string& group, const string& key) {
Darin Petkov083047b2011-06-23 20:42:48 -0700190 CHECK(key_file_);
Paul Stewart8ae18742015-06-16 13:13:10 -0700191 GError* error = nullptr;
mukesh agrawal432d5a12015-08-25 17:57:17 -0700192 g_key_file_remove_key(key_file_, group.c_str(), key.c_str(), &error);
Chris Masone9d779932011-08-25 16:33:41 -0700193 if (error && error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
Darin Petkov083047b2011-06-23 20:42:48 -0700194 LOG(ERROR) << "Failed to delete (" << group << ":" << key << "): "
mukesh agrawal432d5a12015-08-25 17:57:17 -0700195 << ConvertErrorToMessage(error);
Darin Petkov083047b2011-06-23 20:42:48 -0700196 return false;
197 }
198 return true;
199}
200
Paul Stewart8ae18742015-06-16 13:13:10 -0700201bool KeyFileStore::DeleteGroup(const string& group) {
Darin Petkov083047b2011-06-23 20:42:48 -0700202 CHECK(key_file_);
Paul Stewart8ae18742015-06-16 13:13:10 -0700203 GError* error = nullptr;
mukesh agrawal432d5a12015-08-25 17:57:17 -0700204 g_key_file_remove_group(key_file_, group.c_str(), &error);
Chris Masone9d779932011-08-25 16:33:41 -0700205 if (error && error->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND) {
Darin Petkov86964e02011-06-29 13:49:28 -0700206 LOG(ERROR) << "Failed to delete group " << group << ": "
mukesh agrawal432d5a12015-08-25 17:57:17 -0700207 << ConvertErrorToMessage(error);
Darin Petkov083047b2011-06-23 20:42:48 -0700208 return false;
209 }
210 return true;
211}
212
Paul Stewart8ae18742015-06-16 13:13:10 -0700213bool KeyFileStore::SetHeader(const string& header) {
214 GError* error = nullptr;
mukesh agrawal432d5a12015-08-25 17:57:17 -0700215 g_key_file_set_comment(key_file_, nullptr, nullptr, header.c_str(), &error);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700216 if (error) {
217 LOG(ERROR) << "Failed to to set header: "
mukesh agrawal432d5a12015-08-25 17:57:17 -0700218 << ConvertErrorToMessage(error);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700219 return false;
220 }
221 return true;
222}
223
Paul Stewart8ae18742015-06-16 13:13:10 -0700224bool KeyFileStore::GetString(const string& group,
225 const string& key,
226 string* value) const {
Darin Petkov083047b2011-06-23 20:42:48 -0700227 CHECK(key_file_);
Paul Stewart8ae18742015-06-16 13:13:10 -0700228 GError* error = nullptr;
229 gchar* data =
mukesh agrawal432d5a12015-08-25 17:57:17 -0700230 g_key_file_get_string(key_file_, group.c_str(), key.c_str(), &error);
Darin Petkov083047b2011-06-23 20:42:48 -0700231 if (!data) {
mukesh agrawal432d5a12015-08-25 17:57:17 -0700232 string s = ConvertErrorToMessage(error);
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700233 SLOG(this, 10) << "Failed to lookup (" << group << ":" << key << "): " << s;
Darin Petkov083047b2011-06-23 20:42:48 -0700234 return false;
235 }
236 if (value) {
237 *value = data;
238 }
mukesh agrawal432d5a12015-08-25 17:57:17 -0700239 g_free(data);
Darin Petkov083047b2011-06-23 20:42:48 -0700240 return true;
241}
242
Paul Stewart8ae18742015-06-16 13:13:10 -0700243bool KeyFileStore::SetString(const string& group,
244 const string& key,
245 const string& value) {
Darin Petkov083047b2011-06-23 20:42:48 -0700246 CHECK(key_file_);
mukesh agrawal432d5a12015-08-25 17:57:17 -0700247 g_key_file_set_string(key_file_, group.c_str(), key.c_str(), value.c_str());
Darin Petkov083047b2011-06-23 20:42:48 -0700248 return true;
249}
250
Paul Stewart8ae18742015-06-16 13:13:10 -0700251bool KeyFileStore::GetBool(const string& group,
252 const string& key,
253 bool* value) const {
Darin Petkov083047b2011-06-23 20:42:48 -0700254 CHECK(key_file_);
Paul Stewart8ae18742015-06-16 13:13:10 -0700255 GError* error = nullptr;
Darin Petkov083047b2011-06-23 20:42:48 -0700256 gboolean data =
mukesh agrawal432d5a12015-08-25 17:57:17 -0700257 g_key_file_get_boolean(key_file_, group.c_str(), key.c_str(), &error);
Darin Petkov083047b2011-06-23 20:42:48 -0700258 if (error) {
mukesh agrawal432d5a12015-08-25 17:57:17 -0700259 string s = ConvertErrorToMessage(error);
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700260 SLOG(this, 10) << "Failed to lookup (" << group << ":" << key << "): " << s;
Darin Petkov083047b2011-06-23 20:42:48 -0700261 return false;
262 }
263 if (value) {
264 *value = data;
265 }
266 return true;
267}
268
Paul Stewart8ae18742015-06-16 13:13:10 -0700269bool KeyFileStore::SetBool(const string& group, const string& key, bool value) {
Darin Petkov083047b2011-06-23 20:42:48 -0700270 CHECK(key_file_);
mukesh agrawal432d5a12015-08-25 17:57:17 -0700271 g_key_file_set_boolean(key_file_,
272 group.c_str(),
273 key.c_str(),
274 value ? TRUE : FALSE);
Darin Petkov083047b2011-06-23 20:42:48 -0700275 return true;
276}
277
Paul Stewart0756db92012-01-27 08:34:47 -0800278bool KeyFileStore::GetInt(
Paul Stewart8ae18742015-06-16 13:13:10 -0700279 const string& group, const string& key, int* value) const {
Darin Petkov083047b2011-06-23 20:42:48 -0700280 CHECK(key_file_);
Paul Stewart8ae18742015-06-16 13:13:10 -0700281 GError* error = nullptr;
Darin Petkov083047b2011-06-23 20:42:48 -0700282 gint data =
mukesh agrawal432d5a12015-08-25 17:57:17 -0700283 g_key_file_get_integer(key_file_, group.c_str(), key.c_str(), &error);
Darin Petkov083047b2011-06-23 20:42:48 -0700284 if (error) {
mukesh agrawal432d5a12015-08-25 17:57:17 -0700285 string s = ConvertErrorToMessage(error);
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700286 SLOG(this, 10) << "Failed to lookup (" << group << ":" << key << "): " << s;
Darin Petkov083047b2011-06-23 20:42:48 -0700287 return false;
288 }
289 if (value) {
290 *value = data;
291 }
292 return true;
293}
294
Paul Stewart8ae18742015-06-16 13:13:10 -0700295bool KeyFileStore::SetInt(const string& group, const string& key, int value) {
Darin Petkov083047b2011-06-23 20:42:48 -0700296 CHECK(key_file_);
mukesh agrawal432d5a12015-08-25 17:57:17 -0700297 g_key_file_set_integer(key_file_, group.c_str(), key.c_str(), value);
Darin Petkov083047b2011-06-23 20:42:48 -0700298 return true;
299}
300
Paul Stewartdab3b5a2012-07-11 18:25:10 -0700301bool KeyFileStore::GetUint64(
Paul Stewart8ae18742015-06-16 13:13:10 -0700302 const string& group, const string& key, uint64_t* value) const {
Ben Chan7fab8972014-08-10 17:14:46 -0700303 // Read the value in as a string and then convert to uint64_t because glib's
Paul Stewartdab3b5a2012-07-11 18:25:10 -0700304 // g_key_file_set_uint64 appears not to work correctly on 32-bit platforms
305 // in unit tests.
306 string data_string;
307 if (!GetString(group, key, &data_string)) {
308 return false;
309 }
310
Ben Chan7fab8972014-08-10 17:14:46 -0700311 uint64_t data;
Paul Stewartdab3b5a2012-07-11 18:25:10 -0700312 if (!base::StringToUint64(data_string, &data)) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700313 SLOG(this, 10) << "Failed to convert (" << group << ":" << key << "): "
314 << "string to uint64_t conversion failed";
Paul Stewartdab3b5a2012-07-11 18:25:10 -0700315 return false;
316 }
317
318 if (value) {
319 *value = data;
320 }
321
322 return true;
323}
324
325bool KeyFileStore::SetUint64(
Paul Stewart8ae18742015-06-16 13:13:10 -0700326 const string& group, const string& key, uint64_t value) {
Paul Stewartdab3b5a2012-07-11 18:25:10 -0700327 // Convert the value to a string first, then save the value because glib's
328 // g_key_file_get_uint64 appears not to work on 32-bit platforms in our
329 // unit tests.
330 return SetString(group, key, base::Uint64ToString(value));
331}
332
Paul Stewart8ae18742015-06-16 13:13:10 -0700333bool KeyFileStore::GetStringList(const string& group,
334 const string& key,
335 vector<string>* value) const {
Darin Petkovb2841fd2011-06-30 12:54:12 -0700336 CHECK(key_file_);
337 gsize length = 0;
Paul Stewart8ae18742015-06-16 13:13:10 -0700338 GError* error = nullptr;
mukesh agrawal432d5a12015-08-25 17:57:17 -0700339 gchar** data = g_key_file_get_string_list(key_file_,
340 group.c_str(),
341 key.c_str(),
342 &length,
343 &error);
Darin Petkovb2841fd2011-06-30 12:54:12 -0700344 if (!data) {
mukesh agrawal432d5a12015-08-25 17:57:17 -0700345 string s = ConvertErrorToMessage(error);
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700346 SLOG(this, 10) << "Failed to lookup (" << group << ":" << key << "): " << s;
Darin Petkovb2841fd2011-06-30 12:54:12 -0700347 return false;
348 }
349 if (value) {
350 value->assign(data, data + length);
351 }
mukesh agrawal432d5a12015-08-25 17:57:17 -0700352 g_strfreev(data);
Darin Petkovb2841fd2011-06-30 12:54:12 -0700353 return true;
354}
355
Paul Stewart8ae18742015-06-16 13:13:10 -0700356bool KeyFileStore::SetStringList(const string& group,
357 const string& key,
358 const vector<string>& value) {
Darin Petkovb2841fd2011-06-30 12:54:12 -0700359 CHECK(key_file_);
Paul Stewart8ae18742015-06-16 13:13:10 -0700360 vector<const char*> list;
361 for (const auto& string_entry : value) {
Paul Stewart6db7b242014-05-02 15:34:21 -0700362 list.push_back(string_entry.c_str());
Darin Petkovb2841fd2011-06-30 12:54:12 -0700363 }
mukesh agrawal432d5a12015-08-25 17:57:17 -0700364 g_key_file_set_string_list(key_file_,
365 group.c_str(),
366 key.c_str(),
367 list.data(),
368 list.size());
Darin Petkovb2841fd2011-06-30 12:54:12 -0700369 return true;
370}
371
Paul Stewart8ae18742015-06-16 13:13:10 -0700372bool KeyFileStore::GetCryptedString(const string& group,
373 const string& key,
374 string* value) {
Darin Petkov86964e02011-06-29 13:49:28 -0700375 if (!GetString(group, key, value)) {
376 return false;
377 }
378 if (value) {
379 *value = crypto_.Decrypt(*value);
380 }
381 return true;
382}
383
Paul Stewart8ae18742015-06-16 13:13:10 -0700384bool KeyFileStore::SetCryptedString(const string& group,
385 const string& key,
386 const string& value) {
Darin Petkov86964e02011-06-29 13:49:28 -0700387 return SetString(group, key, crypto_.Encrypt(value));
388}
389
Paul Stewart5b9ec982013-01-18 14:12:14 -0800390bool KeyFileStore::DoesGroupMatchProperties(
Paul Stewart8ae18742015-06-16 13:13:10 -0700391 const string& group, const KeyValueStore& properties) const {
Peter Qiud31fb582015-07-15 14:33:32 -0700392 for (const auto& property : properties.properties()) {
Alex Vakulenko8151c342015-10-23 11:08:33 -0700393 if (property.second.IsTypeCompatible<bool>()) {
Peter Qiud31fb582015-07-15 14:33:32 -0700394 bool value;
395 if (!GetBool(group, property.first, &value) ||
396 value != property.second.Get<bool>()) {
397 return false;
398 }
Alex Vakulenko8151c342015-10-23 11:08:33 -0700399 } else if (property.second.IsTypeCompatible<int32_t>()) {
Peter Qiud31fb582015-07-15 14:33:32 -0700400 int value;
401 if (!GetInt(group, property.first, &value) ||
402 value != property.second.Get<int32_t>()) {
403 return false;
404 }
Alex Vakulenko8151c342015-10-23 11:08:33 -0700405 } else if (property.second.IsTypeCompatible<string>()) {
Peter Qiud31fb582015-07-15 14:33:32 -0700406 string value;
407 if (!GetString(group, property.first, &value) ||
408 value != property.second.Get<string>()) {
409 return false;
410 }
Paul Stewart5b9ec982013-01-18 14:12:14 -0800411 }
412 }
413 return true;
414}
415
Darin Petkov083047b2011-06-23 20:42:48 -0700416} // namespace shill