1 //
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 //
16 
17 #include "update_engine/connection_manager.h"
18 
19 #include <set>
20 #include <string>
21 
22 #include <base/stl_util.h>
23 #include <base/strings/string_util.h>
24 #include <policy/device_policy.h>
25 #include <shill/dbus-constants.h>
26 #include <shill/dbus-proxies.h>
27 
28 #include "update_engine/common/prefs.h"
29 #include "update_engine/common/utils.h"
30 #include "update_engine/system_state.h"
31 
32 using org::chromium::flimflam::ManagerProxyInterface;
33 using org::chromium::flimflam::ServiceProxyInterface;
34 using std::set;
35 using std::string;
36 
37 namespace chromeos_update_engine {
38 
39 namespace {
40 
ParseConnectionType(const string & type_str)41 NetworkConnectionType ParseConnectionType(const string& type_str) {
42   if (type_str == shill::kTypeEthernet) {
43     return NetworkConnectionType::kEthernet;
44   } else if (type_str == shill::kTypeWifi) {
45     return NetworkConnectionType::kWifi;
46   } else if (type_str == shill::kTypeWimax) {
47     return NetworkConnectionType::kWimax;
48   } else if (type_str == shill::kTypeBluetooth) {
49     return NetworkConnectionType::kBluetooth;
50   } else if (type_str == shill::kTypeCellular) {
51     return NetworkConnectionType::kCellular;
52   }
53   return NetworkConnectionType::kUnknown;
54 }
55 
ParseTethering(const string & tethering_str)56 NetworkTethering ParseTethering(const string& tethering_str) {
57   if (tethering_str == shill::kTetheringNotDetectedState) {
58     return NetworkTethering::kNotDetected;
59   } else if (tethering_str == shill::kTetheringSuspectedState) {
60     return NetworkTethering::kSuspected;
61   } else if (tethering_str == shill::kTetheringConfirmedState) {
62     return NetworkTethering::kConfirmed;
63   }
64   LOG(WARNING) << "Unknown Tethering value: " << tethering_str;
65   return NetworkTethering::kUnknown;
66 }
67 
68 }  // namespace
69 
ConnectionManager(ShillProxyInterface * shill_proxy,SystemState * system_state)70 ConnectionManager::ConnectionManager(ShillProxyInterface* shill_proxy,
71                                      SystemState* system_state)
72     : shill_proxy_(shill_proxy), system_state_(system_state) {}
73 
IsUpdateAllowedOver(NetworkConnectionType type,NetworkTethering tethering) const74 bool ConnectionManager::IsUpdateAllowedOver(NetworkConnectionType type,
75                                             NetworkTethering tethering) const {
76   switch (type) {
77     case NetworkConnectionType::kBluetooth:
78       return false;
79 
80     case NetworkConnectionType::kCellular: {
81       set<string> allowed_types;
82       const policy::DevicePolicy* device_policy =
83           system_state_->device_policy();
84 
85       // A device_policy is loaded in a lazy way right before an update check,
86       // so the device_policy should be already loaded at this point. If it's
87       // not, return a safe value for this setting.
88       if (!device_policy) {
89         LOG(INFO) << "Disabling updates over cellular networks as there's no "
90                      "device policy loaded yet.";
91         return false;
92       }
93 
94       if (device_policy->GetAllowedConnectionTypesForUpdate(&allowed_types)) {
95         // The update setting is enforced by the device policy.
96 
97         if (!ContainsKey(allowed_types, shill::kTypeCellular)) {
98           LOG(INFO) << "Disabling updates over cellular connection as it's not "
99                        "allowed in the device policy.";
100           return false;
101         }
102 
103         LOG(INFO) << "Allowing updates over cellular per device policy.";
104         return true;
105       } else {
106         // There's no update setting in the device policy, using the local user
107         // setting.
108         PrefsInterface* prefs = system_state_->prefs();
109 
110         if (!prefs || !prefs->Exists(kPrefsUpdateOverCellularPermission)) {
111           LOG(INFO) << "Disabling updates over cellular connection as there's "
112                        "no device policy setting nor user preference present.";
113           return false;
114         }
115 
116         bool stored_value;
117         if (!prefs->GetBoolean(kPrefsUpdateOverCellularPermission,
118                                &stored_value)) {
119           return false;
120         }
121 
122         if (!stored_value) {
123           LOG(INFO) << "Disabling updates over cellular connection per user "
124                        "setting.";
125           return false;
126         }
127         LOG(INFO) << "Allowing updates over cellular per user setting.";
128         return true;
129       }
130     }
131 
132     default:
133       if (tethering == NetworkTethering::kConfirmed) {
134         // Treat this connection as if it is a cellular connection.
135         LOG(INFO) << "Current connection is confirmed tethered, using Cellular "
136                      "setting.";
137         return IsUpdateAllowedOver(NetworkConnectionType::kCellular,
138                                    NetworkTethering::kUnknown);
139       }
140       return true;
141   }
142 }
143 
144 // static
StringForConnectionType(NetworkConnectionType type)145 const char* ConnectionManager::StringForConnectionType(
146     NetworkConnectionType type) {
147   switch (type) {
148     case NetworkConnectionType::kEthernet:
149       return shill::kTypeEthernet;
150     case NetworkConnectionType::kWifi:
151       return shill::kTypeWifi;
152     case NetworkConnectionType::kWimax:
153       return shill::kTypeWimax;
154     case NetworkConnectionType::kBluetooth:
155       return shill::kTypeBluetooth;
156     case NetworkConnectionType::kCellular:
157       return shill::kTypeCellular;
158     case NetworkConnectionType::kUnknown:
159       return "Unknown";
160   }
161   return "Unknown";
162 }
163 
GetConnectionProperties(NetworkConnectionType * out_type,NetworkTethering * out_tethering)164 bool ConnectionManager::GetConnectionProperties(
165     NetworkConnectionType* out_type,
166     NetworkTethering* out_tethering) {
167   dbus::ObjectPath default_service_path;
168   TEST_AND_RETURN_FALSE(GetDefaultServicePath(&default_service_path));
169   if (!default_service_path.IsValid())
170     return false;
171   // Shill uses the "/" service path to indicate that it is not connected.
172   if (default_service_path.value() == "/")
173     return false;
174   TEST_AND_RETURN_FALSE(
175       GetServicePathProperties(default_service_path, out_type, out_tethering));
176   return true;
177 }
178 
GetDefaultServicePath(dbus::ObjectPath * out_path)179 bool ConnectionManager::GetDefaultServicePath(dbus::ObjectPath* out_path) {
180   brillo::VariantDictionary properties;
181   brillo::ErrorPtr error;
182   ManagerProxyInterface* manager_proxy = shill_proxy_->GetManagerProxy();
183   if (!manager_proxy)
184     return false;
185   TEST_AND_RETURN_FALSE(manager_proxy->GetProperties(&properties, &error));
186 
187   const auto& prop_default_service =
188       properties.find(shill::kDefaultServiceProperty);
189   if (prop_default_service == properties.end())
190     return false;
191 
192   *out_path = prop_default_service->second.TryGet<dbus::ObjectPath>();
193   return out_path->IsValid();
194 }
195 
GetServicePathProperties(const dbus::ObjectPath & path,NetworkConnectionType * out_type,NetworkTethering * out_tethering)196 bool ConnectionManager::GetServicePathProperties(
197     const dbus::ObjectPath& path,
198     NetworkConnectionType* out_type,
199     NetworkTethering* out_tethering) {
200   // We create and dispose the ServiceProxyInterface on every request.
201   std::unique_ptr<ServiceProxyInterface> service =
202       shill_proxy_->GetServiceForPath(path);
203 
204   brillo::VariantDictionary properties;
205   brillo::ErrorPtr error;
206   TEST_AND_RETURN_FALSE(service->GetProperties(&properties, &error));
207 
208   // Populate the out_tethering.
209   const auto& prop_tethering = properties.find(shill::kTetheringProperty);
210   if (prop_tethering == properties.end()) {
211     // Set to Unknown if not present.
212     *out_tethering = NetworkTethering::kUnknown;
213   } else {
214     // If the property doesn't contain a string value, the empty string will
215     // become kUnknown.
216     *out_tethering = ParseTethering(prop_tethering->second.TryGet<string>());
217   }
218 
219   // Populate the out_type property.
220   const auto& prop_type = properties.find(shill::kTypeProperty);
221   if (prop_type == properties.end()) {
222     // Set to Unknown if not present.
223     *out_type = NetworkConnectionType::kUnknown;
224     return false;
225   }
226 
227   string type_str = prop_type->second.TryGet<string>();
228   if (type_str == shill::kTypeVPN) {
229     const auto& prop_physical =
230         properties.find(shill::kPhysicalTechnologyProperty);
231     if (prop_physical == properties.end()) {
232       LOG(ERROR) << "No PhysicalTechnology property found for a VPN"
233                     " connection (service: "
234                  << path.value() << "). Returning default kUnknown value.";
235       *out_type = NetworkConnectionType::kUnknown;
236     } else {
237       *out_type = ParseConnectionType(prop_physical->second.TryGet<string>());
238     }
239   } else {
240     *out_type = ParseConnectionType(type_str);
241   }
242   return true;
243 }
244 
245 }  // namespace chromeos_update_engine
246