| Index: chrome/browser/chromeos/cros/onc_network_parser.cc
|
| diff --git a/chrome/browser/chromeos/cros/onc_network_parser.cc b/chrome/browser/chromeos/cros/onc_network_parser.cc
|
| index eedf10948d22b3917d642a0213f3d6346464893c..82b183fa8ebb29ada401c8bfa81758678a9722b2 100644
|
| --- a/chrome/browser/chromeos/cros/onc_network_parser.cc
|
| +++ b/chrome/browser/chromeos/cros/onc_network_parser.cc
|
| @@ -4,8 +4,8 @@
|
|
|
| #include "chrome/browser/chromeos/cros/onc_network_parser.h"
|
|
|
| -#include <pk11pub.h>
|
| #include <keyhi.h>
|
| +#include <pk11pub.h>
|
|
|
| #include "base/base64.h"
|
| #include "base/json/json_value_serializer.h"
|
| @@ -186,8 +186,10 @@ std::string ConvertValueToString(const base::Value& value) {
|
|
|
| // -------------------- OncNetworkParser --------------------
|
|
|
| -OncNetworkParser::OncNetworkParser(const std::string& onc_blob)
|
| +OncNetworkParser::OncNetworkParser(const std::string& onc_blob,
|
| + NetworkUIData::ONCSource onc_source)
|
| : NetworkParser(get_onc_mapper()),
|
| + onc_source_(onc_source),
|
| network_configs_(NULL),
|
| certificates_(NULL) {
|
| VLOG(2) << __func__ << ": OncNetworkParser called on " << onc_blob;
|
| @@ -229,6 +231,28 @@ int OncNetworkParser::GetNetworkConfigsSize() const {
|
| return network_configs_ ? network_configs_->GetSize() : 0;
|
| }
|
|
|
| +Network* OncNetworkParser::ParseNetwork(int n) {
|
| + CHECK(network_configs_);
|
| + CHECK(static_cast<size_t>(n) < network_configs_->GetSize());
|
| + CHECK_GE(n, 0);
|
| + DictionaryValue* info = NULL;
|
| + if (!network_configs_->GetDictionary(n, &info)) {
|
| + parse_error_ = l10n_util::GetStringUTF8(
|
| + IDS_NETWORK_CONFIG_ERROR_NETWORK_PROP_DICT_MALFORMED);
|
| + return NULL;
|
| + }
|
| +
|
| + if (VLOG_IS_ON(2)) {
|
| + std::string network_json;
|
| + base::JSONWriter::Write(static_cast<base::Value*>(info),
|
| + true, &network_json);
|
| + VLOG(2) << "Parsing network at index " << n
|
| + << ": " << network_json;
|
| + }
|
| +
|
| + return CreateNetworkFromInfo(std::string(), *info);
|
| +}
|
| +
|
| int OncNetworkParser::GetCertificatesSize() const {
|
| return certificates_ ? certificates_->GetSize() : 0;
|
| }
|
| @@ -293,28 +317,6 @@ scoped_refptr<net::X509Certificate> OncNetworkParser::ParseCertificate(
|
| return NULL;
|
| }
|
|
|
| -Network* OncNetworkParser::ParseNetwork(int n) {
|
| - CHECK(network_configs_);
|
| - CHECK(static_cast<size_t>(n) < network_configs_->GetSize());
|
| - CHECK_GE(n, 0);
|
| - DictionaryValue* info = NULL;
|
| - if (!network_configs_->GetDictionary(n, &info)) {
|
| - parse_error_ = l10n_util::GetStringUTF8(
|
| - IDS_NETWORK_CONFIG_ERROR_NETWORK_PROP_DICT_MALFORMED);
|
| - return NULL;
|
| - }
|
| -
|
| - if (VLOG_IS_ON(2)) {
|
| - std::string network_json;
|
| - base::JSONWriter::Write(static_cast<base::Value*>(info),
|
| - true, &network_json);
|
| - VLOG(2) << "Parsing network at index " << n
|
| - << ": " << network_json;
|
| - }
|
| -
|
| - return CreateNetworkFromInfo(std::string(), *info);
|
| -}
|
| -
|
| Network* OncNetworkParser::CreateNetworkFromInfo(
|
| const std::string& service_path,
|
| const DictionaryValue& info) {
|
| @@ -325,6 +327,13 @@ Network* OncNetworkParser::CreateNetworkFromInfo(
|
| return NULL;
|
| }
|
| scoped_ptr<Network> network(CreateNewNetwork(type, service_path));
|
| +
|
| + // Initialize UI data.
|
| + NetworkUIData ui_data;
|
| + ui_data.set_onc_source(onc_source_);
|
| + ui_data.FillDictionary(network->ui_data());
|
| +
|
| + // Parse all properties recursively.
|
| if (!ParseNestedObject(network.get(),
|
| "NetworkConfiguration",
|
| static_cast<const base::Value&>(info),
|
| @@ -336,14 +345,90 @@ Network* OncNetworkParser::CreateNetworkFromInfo(
|
| IDS_NETWORK_CONFIG_ERROR_NETWORK_PROP_DICT_MALFORMED);
|
| return NULL;
|
| }
|
| +
|
| + // Update the UI data property.
|
| + std::string ui_data_json;
|
| + base::JSONWriter::Write(network->ui_data(), false, &ui_data_json);
|
| + base::StringValue ui_data_string_value(ui_data_json);
|
| + network->UpdatePropertyMap(PROPERTY_INDEX_UI_DATA, ui_data_string_value);
|
| +
|
| if (VLOG_IS_ON(2)) {
|
| VLOG(2) << "Created Network '" << network->name()
|
| << "' from info. Path:" << service_path
|
| << " Type:" << ConnectionTypeToString(type);
|
| }
|
| +
|
| return network.release();
|
| }
|
|
|
| +bool OncNetworkParser::ParseNestedObject(Network* network,
|
| + const std::string& onc_type,
|
| + const base::Value& value,
|
| + OncValueSignature* signature,
|
| + ParserPointer parser) {
|
| + bool any_errors = false;
|
| + if (!value.IsType(base::Value::TYPE_DICTIONARY)) {
|
| + VLOG(1) << network->name() << ": expected object of type " << onc_type;
|
| + parse_error_ = l10n_util::GetStringUTF8(
|
| + IDS_NETWORK_CONFIG_ERROR_NETWORK_PROP_DICT_MALFORMED);
|
| + return false;
|
| + }
|
| + VLOG(2) << "Parsing nested object of type " << onc_type;
|
| + const DictionaryValue* dict = NULL;
|
| + value.GetAsDictionary(&dict);
|
| + for (DictionaryValue::key_iterator iter = dict->begin_keys();
|
| + iter != dict->end_keys(); ++iter) {
|
| + const std::string& key = *iter;
|
| +
|
| + // Recommended keys are only of interest to the UI code and the UI reads it
|
| + // directly from the ONC blob.
|
| + if (key == "Recommended")
|
| + continue;
|
| +
|
| + base::Value* inner_value = NULL;
|
| + dict->GetWithoutPathExpansion(key, &inner_value);
|
| + CHECK(inner_value != NULL);
|
| + int field_index;
|
| + for (field_index = 0; signature[field_index].field != NULL; ++field_index) {
|
| + if (key == signature[field_index].field)
|
| + break;
|
| + }
|
| + if (signature[field_index].field == NULL) {
|
| + VLOG(1) << network->name() << ": unexpected field: "
|
| + << key << ", in type: " << onc_type;
|
| + any_errors = true;
|
| + continue;
|
| + }
|
| + if (!inner_value->IsType(signature[field_index].type)) {
|
| + VLOG(1) << network->name() << ": field with wrong type: " << key
|
| + << ", actual type: " << inner_value->GetType()
|
| + << ", expected type: " << signature[field_index].type;
|
| + any_errors = true;
|
| + continue;
|
| + }
|
| + PropertyIndex index = signature[field_index].index;
|
| + // We need to UpdatePropertyMap now since parser might want to
|
| + // change the mapped value.
|
| + network->UpdatePropertyMap(index, *inner_value);
|
| + if (!parser(this, index, *inner_value, network)) {
|
| + VLOG(1) << network->name() << ": field not parsed: " << key;
|
| + any_errors = true;
|
| + continue;
|
| + }
|
| + if (VLOG_IS_ON(2)) {
|
| + std::string value_json;
|
| + base::JSONWriter::Write(inner_value, true, &value_json);
|
| + VLOG(2) << network->name() << ": Successfully parsed [" << key
|
| + << "(" << index << ")] = " << value_json;
|
| + }
|
| + }
|
| + if (any_errors) {
|
| + parse_error_ = l10n_util::GetStringUTF8(
|
| + IDS_NETWORK_CONFIG_ERROR_NETWORK_PROP_DICT_MALFORMED);
|
| + }
|
| + return !any_errors;
|
| +}
|
| +
|
| Network* OncNetworkParser::CreateNewNetwork(
|
| ConnectionType type, const std::string& service_path) {
|
| Network* network = NetworkParser::CreateNewNetwork(type, service_path);
|
| @@ -379,6 +464,77 @@ std::string OncNetworkParser::GetGuidFromDictionary(
|
| return guid_string;
|
| }
|
|
|
| +// static
|
| +bool OncNetworkParser::ParseNetworkConfigurationValue(
|
| + OncNetworkParser* parser,
|
| + PropertyIndex index,
|
| + const base::Value& value,
|
| + Network* network) {
|
| + switch (index) {
|
| + case PROPERTY_INDEX_ONC_WIFI: {
|
| + return parser->ParseNestedObject(network,
|
| + "WiFi",
|
| + value,
|
| + wifi_signature,
|
| + OncWifiNetworkParser::ParseWifiValue);
|
| + }
|
| + case PROPERTY_INDEX_ONC_VPN: {
|
| + if (!CheckNetworkType(network, TYPE_VPN, "VPN"))
|
| + return false;
|
| + VirtualNetwork* virtual_network = static_cast<VirtualNetwork*>(network);
|
| + // Got the "VPN" field. Immediately store the VPN.Type field
|
| + // value so that we can properly validate fields in the VPN
|
| + // object based on the type.
|
| + const DictionaryValue* dict = NULL;
|
| + CHECK(value.GetAsDictionary(&dict));
|
| + std::string provider_type_string;
|
| + if (!dict->GetString("Type", &provider_type_string)) {
|
| + VLOG(1) << network->name() << ": VPN.Type is missing";
|
| + return false;
|
| + }
|
| + ProviderType provider_type =
|
| + OncVirtualNetworkParser::ParseProviderType(provider_type_string);
|
| + virtual_network->set_provider_type(provider_type);
|
| + return parser->ParseNestedObject(network,
|
| + "VPN",
|
| + value,
|
| + vpn_signature,
|
| + OncVirtualNetworkParser::ParseVPNValue);
|
| + return true;
|
| + }
|
| + case PROPERTY_INDEX_ONC_REMOVE:
|
| + VLOG(1) << network->name() << ": Remove field not yet implemented";
|
| + return false;
|
| + case PROPERTY_INDEX_TYPE: {
|
| + // Update property with native value for type.
|
| + std::string str =
|
| + NativeNetworkParser::network_type_mapper()->GetKey(network->type());
|
| + scoped_ptr<StringValue> val(Value::CreateStringValue(str));
|
| + network->UpdatePropertyMap(PROPERTY_INDEX_TYPE, *val.get());
|
| + return true;
|
| + }
|
| + case PROPERTY_INDEX_GUID:
|
| + case PROPERTY_INDEX_NAME:
|
| + // Fall back to generic parser for these.
|
| + return parser->ParseValue(index, value, network);
|
| + default:
|
| + break;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +// static
|
| +bool OncNetworkParser::CheckNetworkType(Network* network,
|
| + ConnectionType expected,
|
| + const std::string& onc_type) {
|
| + if (expected != network->type()) {
|
| + LOG(WARNING) << network->name() << ": "
|
| + << onc_type << " field unexpected for this type network";
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| scoped_refptr<net::X509Certificate>
|
| OncNetworkParser::ParseServerOrCaCertificate(
|
| int cert_index,
|
| @@ -548,159 +704,6 @@ scoped_refptr<net::X509Certificate> OncNetworkParser::ParseClientCertificate(
|
| return cert_result;
|
| }
|
|
|
| -bool OncNetworkParser::ParseNestedObject(Network* network,
|
| - const std::string& onc_type,
|
| - const base::Value& value,
|
| - OncValueSignature* signature,
|
| - ParserPointer parser) {
|
| - bool any_errors = false;
|
| - if (!value.IsType(base::Value::TYPE_DICTIONARY)) {
|
| - VLOG(1) << network->name() << ": expected object of type " << onc_type;
|
| - parse_error_ = l10n_util::GetStringUTF8(
|
| - IDS_NETWORK_CONFIG_ERROR_NETWORK_PROP_DICT_MALFORMED);
|
| - return false;
|
| - }
|
| - VLOG(2) << "Parsing nested object of type " << onc_type;
|
| - const DictionaryValue* dict = NULL;
|
| - value.GetAsDictionary(&dict);
|
| - for (DictionaryValue::key_iterator iter = dict->begin_keys();
|
| - iter != dict->end_keys(); ++iter) {
|
| - const std::string& key = *iter;
|
| - base::Value* inner_value = NULL;
|
| - dict->GetWithoutPathExpansion(key, &inner_value);
|
| - CHECK(inner_value != NULL);
|
| - int field_index;
|
| - for (field_index = 0; signature[field_index].field != NULL; ++field_index) {
|
| - if (key == signature[field_index].field)
|
| - break;
|
| - }
|
| - if (signature[field_index].field == NULL) {
|
| - VLOG(1) << network->name() << ": unexpected field: "
|
| - << key << ", in type: " << onc_type;
|
| - any_errors = true;
|
| - continue;
|
| - }
|
| - if (!inner_value->IsType(signature[field_index].type)) {
|
| - VLOG(1) << network->name() << ": field with wrong type: " << key
|
| - << ", actual type: " << inner_value->GetType()
|
| - << ", expected type: " << signature[field_index].type;
|
| - any_errors = true;
|
| - continue;
|
| - }
|
| - PropertyIndex index = signature[field_index].index;
|
| - // We need to UpdatePropertyMap now since parser might want to
|
| - // change the mapped value.
|
| - network->UpdatePropertyMap(index, *inner_value);
|
| - if (!parser(this, index, *inner_value, network)) {
|
| - VLOG(1) << network->name() << ": field not parsed: " << key;
|
| - any_errors = true;
|
| - continue;
|
| - }
|
| - if (VLOG_IS_ON(2)) {
|
| - std::string value_json;
|
| - base::JSONWriter::Write(inner_value, true, &value_json);
|
| - VLOG(2) << network->name() << ": Successfully parsed [" << key
|
| - << "(" << index << ")] = " << value_json;
|
| - }
|
| - }
|
| - if (any_errors)
|
| - parse_error_ = l10n_util::GetStringUTF8(
|
| - IDS_NETWORK_CONFIG_ERROR_NETWORK_PROP_DICT_MALFORMED);
|
| - return !any_errors;
|
| -}
|
| -
|
| -// static
|
| -bool OncNetworkParser::CheckNetworkType(Network* network,
|
| - ConnectionType expected,
|
| - const std::string& onc_type) {
|
| - if (expected != network->type()) {
|
| - LOG(WARNING) << network->name() << ": "
|
| - << onc_type << " field unexpected for this type network";
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -// static
|
| -bool OncNetworkParser::ParseNetworkConfigurationValue(
|
| - OncNetworkParser* parser,
|
| - PropertyIndex index,
|
| - const base::Value& value,
|
| - Network* network) {
|
| - switch (index) {
|
| - case PROPERTY_INDEX_ONC_WIFI: {
|
| - return parser->ParseNestedObject(network,
|
| - "WiFi",
|
| - value,
|
| - wifi_signature,
|
| - OncWifiNetworkParser::ParseWifiValue);
|
| - }
|
| - case PROPERTY_INDEX_ONC_VPN: {
|
| - if (!CheckNetworkType(network, TYPE_VPN, "VPN"))
|
| - return false;
|
| - VirtualNetwork* virtual_network = static_cast<VirtualNetwork*>(network);
|
| - // Got the "VPN" field. Immediately store the VPN.Type field
|
| - // value so that we can properly validate fields in the VPN
|
| - // object based on the type.
|
| - const DictionaryValue* dict = NULL;
|
| - CHECK(value.GetAsDictionary(&dict));
|
| - std::string provider_type_string;
|
| - if (!dict->GetString("Type", &provider_type_string)) {
|
| - VLOG(1) << network->name() << ": VPN.Type is missing";
|
| - return false;
|
| - }
|
| - ProviderType provider_type =
|
| - OncVirtualNetworkParser::ParseProviderType(provider_type_string);
|
| - virtual_network->set_provider_type(provider_type);
|
| - return parser->ParseNestedObject(network,
|
| - "VPN",
|
| - value,
|
| - vpn_signature,
|
| - OncVirtualNetworkParser::ParseVPNValue);
|
| - return true;
|
| - }
|
| - case PROPERTY_INDEX_ONC_REMOVE:
|
| - VLOG(1) << network->name() << ": Remove field not yet implemented";
|
| - return false;
|
| - case PROPERTY_INDEX_TYPE: {
|
| - // Update property with native value for type.
|
| - std::string str =
|
| - NativeNetworkParser::network_type_mapper()->GetKey(network->type());
|
| - scoped_ptr<StringValue> val(Value::CreateStringValue(str));
|
| - network->UpdatePropertyMap(PROPERTY_INDEX_TYPE, *val.get());
|
| - return true;
|
| - }
|
| - case PROPERTY_INDEX_GUID:
|
| - case PROPERTY_INDEX_NAME:
|
| - // Fall back to generic parser for these.
|
| - return parser->ParseValue(index, value, network);
|
| - default:
|
| - break;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -// static
|
| -bool OncNetworkParser::DeleteCertAndKeyByNickname(const std::string& label) {
|
| - net::CertificateList cert_list;
|
| - ListCertsWithNickname(label, &cert_list);
|
| - net::CertDatabase cert_db;
|
| - bool result = true;
|
| - for (net::CertificateList::iterator iter = cert_list.begin();
|
| - iter != cert_list.end(); ++iter) {
|
| - // If we fail, we try and delete the rest still.
|
| - // TODO(gspencer): this isn't very "transactional". If we fail on some, but
|
| - // not all, then it's possible to leave things in a weird state.
|
| - // Luckily there should only be one cert with a particular
|
| - // label, and the cert not being found is one of the few reasons the
|
| - // delete could fail, but still... The other choice is to return
|
| - // failure immediately, but that doesn't seem to do what is intended.
|
| - if (!cert_db.DeleteCertAndKey(iter->get()))
|
| - result = false;
|
| - }
|
| - return result;
|
| -}
|
| -
|
| // static
|
| void OncNetworkParser::ListCertsWithNickname(const std::string& label,
|
| net::CertificateList* result) {
|
| @@ -741,6 +744,27 @@ void OncNetworkParser::ListCertsWithNickname(const std::string& label,
|
| }
|
|
|
| // static
|
| +bool OncNetworkParser::DeleteCertAndKeyByNickname(const std::string& label) {
|
| + net::CertificateList cert_list;
|
| + ListCertsWithNickname(label, &cert_list);
|
| + net::CertDatabase cert_db;
|
| + bool result = true;
|
| + for (net::CertificateList::iterator iter = cert_list.begin();
|
| + iter != cert_list.end(); ++iter) {
|
| + // If we fail, we try and delete the rest still.
|
| + // TODO(gspencer): this isn't very "transactional". If we fail on some, but
|
| + // not all, then it's possible to leave things in a weird state.
|
| + // Luckily there should only be one cert with a particular
|
| + // label, and the cert not being found is one of the few reasons the
|
| + // delete could fail, but still... The other choice is to return
|
| + // failure immediately, but that doesn't seem to do what is intended.
|
| + if (!cert_db.DeleteCertAndKey(iter->get()))
|
| + result = false;
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +// static
|
| std::string OncNetworkParser::GetPkcs11IdFromCertGuid(const std::string& guid) {
|
| // We have to look up the GUID to find the PKCS#11 ID that is needed.
|
| net::CertificateList cert_list;
|
|
|