1 // Copyright (c) 2013 The Chromium 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 "chrome/browser/chromeos/net/proxy_config_handler.h" 6 7 #include "base/bind.h" 8 #include "base/json/json_writer.h" 9 #include "base/logging.h" 10 #include "base/prefs/pref_registry_simple.h" 11 #include "base/prefs/pref_service.h" 12 #include "base/values.h" 13 #include "chrome/browser/chromeos/net/onc_utils.h" 14 #include "chrome/browser/prefs/proxy_config_dictionary.h" 15 #include "chrome/common/pref_names.h" 16 #include "chromeos/dbus/dbus_thread_manager.h" 17 #include "chromeos/dbus/shill_service_client.h" 18 #include "chromeos/network/network_handler_callbacks.h" 19 #include "chromeos/network/network_profile.h" 20 #include "chromeos/network/network_profile_handler.h" 21 #include "chromeos/network/network_state.h" 22 #include "chromeos/network/network_state_handler.h" 23 #include "components/user_prefs/pref_registry_syncable.h" 24 #include "dbus/object_path.h" 25 #include "third_party/cros_system_api/dbus/service_constants.h" 26 27 namespace chromeos { 28 29 namespace { 30 31 const base::DictionaryValue* GetNetworkConfigByGUID( 32 const base::ListValue& network_configs, 33 const std::string& guid) { 34 for (base::ListValue::const_iterator it = network_configs.begin(); 35 it != network_configs.end(); 36 ++it) { 37 const base::DictionaryValue* network = NULL; 38 (*it)->GetAsDictionary(&network); 39 std::string current_guid; 40 network->GetStringWithoutPathExpansion(onc::network_config::kGUID, 41 ¤t_guid); 42 if (current_guid == guid) 43 return network; 44 } 45 return NULL; 46 } 47 48 scoped_ptr<ProxyConfigDictionary> GetProxyPolicy( 49 const PrefService* pref_service, 50 const char* pref_name, 51 const NetworkState& network, 52 bool* network_is_managed) { 53 *network_is_managed = false; 54 55 if (!pref_service || network.guid().empty()) 56 return scoped_ptr<ProxyConfigDictionary>(); 57 58 const PrefService::Preference* preference = 59 pref_service->FindPreference(pref_name); 60 if (!preference) { 61 // The preference may not exit in tests. 62 return scoped_ptr<ProxyConfigDictionary>(); 63 } 64 65 // User prefs are not stored in this Preference yet but only the policy. 66 // 67 // The policy server incorrectly configures the OpenNetworkConfiguration user 68 // policy as Recommended. To work around that, we handle the Recommended and 69 // the Mandatory value in the same way. 70 // TODO(pneubeck): Remove this workaround, once the server is fixed. See 71 // http://crbug.com/280553 . 72 if (preference->IsDefaultValue()) { 73 // No policy set. 74 return scoped_ptr<ProxyConfigDictionary>(); 75 } 76 const base::Value* onc_policy_value = preference->GetValue(); 77 DCHECK(onc_policy_value); 78 79 const base::ListValue* onc_policy = NULL; 80 onc_policy_value->GetAsList(&onc_policy); 81 DCHECK(onc_policy); 82 83 const base::DictionaryValue* network_policy = 84 GetNetworkConfigByGUID(*onc_policy, network.guid()); 85 if (!network_policy) { 86 // This network isn't managed by this policy. 87 return scoped_ptr<ProxyConfigDictionary>(); 88 } 89 90 const base::DictionaryValue* proxy_policy = NULL; 91 network_policy->GetDictionaryWithoutPathExpansion( 92 onc::network_config::kProxySettings, &proxy_policy); 93 if (!proxy_policy) { 94 // This policy doesn't set a proxy for this network. Nonetheless, this 95 // disallows changes by the user. 96 *network_is_managed = true; 97 return scoped_ptr<ProxyConfigDictionary>(); 98 } 99 100 scoped_ptr<base::DictionaryValue> proxy_dict = 101 onc::ConvertOncProxySettingsToProxyConfig(*proxy_policy); 102 *network_is_managed = true; 103 return make_scoped_ptr(new ProxyConfigDictionary(proxy_dict.get())); 104 } 105 106 } // namespace 107 108 namespace proxy_config { 109 110 scoped_ptr<ProxyConfigDictionary> GetProxyConfigForNetwork( 111 const PrefService* profile_prefs, 112 const PrefService* local_state_prefs, 113 const NetworkState& network, 114 onc::ONCSource* onc_source) { 115 VLOG(2) << "GetProxyConfigForNetwork network: " << network.path() 116 << " , guid: " << network.guid(); 117 *onc_source = onc::ONC_SOURCE_NONE; 118 bool network_is_managed = false; 119 120 scoped_ptr<ProxyConfigDictionary> proxy_config = 121 GetProxyPolicy(profile_prefs, 122 prefs::kOpenNetworkConfiguration, 123 network, 124 &network_is_managed); 125 if (network_is_managed) { 126 VLOG(1) << "Network " << network.path() << " is managed by user policy."; 127 *onc_source = onc::ONC_SOURCE_USER_POLICY; 128 return proxy_config.Pass(); 129 } 130 proxy_config = GetProxyPolicy(local_state_prefs, 131 prefs::kDeviceOpenNetworkConfiguration, 132 network, 133 &network_is_managed); 134 if (network_is_managed) { 135 VLOG(1) << "Network " << network.path() << " is managed by device policy."; 136 *onc_source = onc::ONC_SOURCE_DEVICE_POLICY; 137 return proxy_config.Pass(); 138 } 139 140 if (network.profile_path().empty()) 141 return scoped_ptr<ProxyConfigDictionary>(); 142 143 const NetworkProfile* profile = NetworkHandler::Get() 144 ->network_profile_handler()->GetProfileForPath(network.profile_path()); 145 if (!profile) { 146 LOG(WARNING) << "Unknown profile_path '" << network.profile_path() << "'."; 147 return scoped_ptr<ProxyConfigDictionary>(); 148 } 149 if (!profile_prefs && profile->type() == NetworkProfile::TYPE_USER) { 150 // This case occurs, for example, if called from the proxy config tracker 151 // created for the system request context and the signin screen. Both don't 152 // use profile prefs and shouldn't depend on the user's not shared proxy 153 // settings. 154 VLOG(1) 155 << "Don't use unshared settings for system context or signin screen."; 156 return scoped_ptr<ProxyConfigDictionary>(); 157 } 158 159 // No policy set for this network, read instead the user's (shared or 160 // unshared) configuration. 161 // The user's proxy setting is not stored in the Chrome preference yet. We 162 // still rely on Shill storing it. 163 const base::DictionaryValue& value = network.proxy_config(); 164 if (value.empty()) 165 return scoped_ptr<ProxyConfigDictionary>(); 166 return make_scoped_ptr(new ProxyConfigDictionary(&value)); 167 } 168 169 void SetProxyConfigForNetwork(const ProxyConfigDictionary& proxy_config, 170 const NetworkState& network) { 171 chromeos::ShillServiceClient* shill_service_client = 172 DBusThreadManager::Get()->GetShillServiceClient(); 173 174 // The user's proxy setting is not stored in the Chrome preference yet. We 175 // still rely on Shill storing it. 176 ProxyPrefs::ProxyMode mode; 177 if (!proxy_config.GetMode(&mode) || mode == ProxyPrefs::MODE_DIRECT) { 178 // TODO(pneubeck): Consider removing this legacy code. Return empty string 179 // for direct mode for portal check to work correctly. 180 shill_service_client->ClearProperty( 181 dbus::ObjectPath(network.path()), 182 flimflam::kProxyConfigProperty, 183 base::Bind(&base::DoNothing), 184 base::Bind(&network_handler::ShillErrorCallbackFunction, 185 "SetProxyConfig.ClearProperty Failed", 186 network.path(), 187 network_handler::ErrorCallback())); 188 } else { 189 std::string proxy_config_str; 190 base::JSONWriter::Write(&proxy_config.GetDictionary(), &proxy_config_str); 191 shill_service_client->SetProperty( 192 dbus::ObjectPath(network.path()), 193 flimflam::kProxyConfigProperty, 194 base::StringValue(proxy_config_str), 195 base::Bind(&base::DoNothing), 196 base::Bind(&network_handler::ShillErrorCallbackFunction, 197 "SetProxyConfig.SetProperty Failed", 198 network.path(), 199 network_handler::ErrorCallback())); 200 } 201 202 if (NetworkHandler::IsInitialized()) { 203 NetworkHandler::Get()->network_state_handler() 204 ->RequestUpdateForNetwork(network.path()); 205 } 206 } 207 208 void RegisterPrefs(PrefRegistrySimple* registry) { 209 registry->RegisterListPref(prefs::kDeviceOpenNetworkConfiguration); 210 } 211 212 void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { 213 registry->RegisterBooleanPref( 214 prefs::kUseSharedProxies, 215 false, 216 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 217 218 registry->RegisterListPref(prefs::kOpenNetworkConfiguration, 219 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 220 } 221 222 } // namespace proxy_config 223 224 } // namespace chromeos 225