1 /* 2 * Copyright (C) 2017 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 package com.android.server.wifi; 18 19 import static com.android.server.wifi.WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION; 20 21 import android.annotation.Nullable; 22 import android.content.Context; 23 import android.net.IpConfiguration; 24 import android.net.wifi.WifiConfiguration; 25 import android.net.wifi.WifiConfiguration.NetworkSelectionStatus; 26 import android.net.wifi.WifiEnterpriseConfig; 27 import android.os.Process; 28 import android.util.Log; 29 import android.util.Pair; 30 31 import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; 32 import com.android.server.wifi.util.XmlUtil; 33 import com.android.server.wifi.util.XmlUtil.IpConfigurationXmlUtil; 34 import com.android.server.wifi.util.XmlUtil.NetworkSelectionStatusXmlUtil; 35 import com.android.server.wifi.util.XmlUtil.WifiConfigurationXmlUtil; 36 import com.android.server.wifi.util.XmlUtil.WifiEnterpriseConfigXmlUtil; 37 38 import org.xmlpull.v1.XmlPullParser; 39 import org.xmlpull.v1.XmlPullParserException; 40 import org.xmlpull.v1.XmlSerializer; 41 42 import java.io.IOException; 43 import java.util.ArrayList; 44 import java.util.List; 45 46 /** 47 * This class performs serialization and parsing of XML data block that contain the list of WiFi 48 * network configurations (XML block data inside <NetworkList> tag). 49 */ 50 public abstract class NetworkListStoreData implements WifiConfigStore.StoreData { 51 private static final String TAG = "NetworkListStoreData"; 52 53 private static final String XML_TAG_SECTION_HEADER_NETWORK_LIST = "NetworkList"; 54 private static final String XML_TAG_SECTION_HEADER_NETWORK = "Network"; 55 private static final String XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION = "WifiConfiguration"; 56 private static final String XML_TAG_SECTION_HEADER_NETWORK_STATUS = "NetworkStatus"; 57 private static final String XML_TAG_SECTION_HEADER_IP_CONFIGURATION = "IpConfiguration"; 58 private static final String XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION = 59 "WifiEnterpriseConfiguration"; 60 61 private final Context mContext; 62 63 /** 64 * List of saved shared networks visible to all the users to be stored in the store file. 65 */ 66 private List<WifiConfiguration> mConfigurations; 67 NetworkListStoreData(Context context)68 NetworkListStoreData(Context context) { 69 mContext = context; 70 } 71 72 @Override serializeData(XmlSerializer out, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)73 public void serializeData(XmlSerializer out, 74 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 75 throws XmlPullParserException, IOException { 76 serializeNetworkList(out, mConfigurations, encryptionUtil); 77 } 78 79 @Override deserializeData(XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)80 public void deserializeData(XmlPullParser in, int outerTagDepth, 81 @WifiConfigStore.Version int version, 82 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 83 throws XmlPullParserException, IOException { 84 // Ignore empty reads. 85 if (in == null) { 86 return; 87 } 88 mConfigurations = parseNetworkList(in, outerTagDepth, version, encryptionUtil); 89 } 90 91 @Override resetData()92 public void resetData() { 93 mConfigurations = null; 94 } 95 96 @Override hasNewDataToSerialize()97 public boolean hasNewDataToSerialize() { 98 // always persist. 99 return true; 100 } 101 102 @Override getName()103 public String getName() { 104 return XML_TAG_SECTION_HEADER_NETWORK_LIST; 105 } 106 setConfigurations(List<WifiConfiguration> configs)107 public void setConfigurations(List<WifiConfiguration> configs) { 108 mConfigurations = configs; 109 } 110 111 /** 112 * An empty list will be returned if no shared configurations. 113 * 114 * @return List of {@link WifiConfiguration} 115 */ getConfigurations()116 public List<WifiConfiguration> getConfigurations() { 117 if (mConfigurations == null) { 118 return new ArrayList<WifiConfiguration>(); 119 } 120 return mConfigurations; 121 } 122 123 /** 124 * Serialize the list of {@link WifiConfiguration} to an output stream in XML format. 125 * 126 * @param out The output stream to serialize the data to 127 * @param networkList The network list to serialize 128 * @param encryptionUtil Instance of {@link WifiConfigStoreEncryptionUtil} 129 * @throws XmlPullParserException 130 * @throws IOException 131 */ serializeNetworkList(XmlSerializer out, List<WifiConfiguration> networkList, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)132 private void serializeNetworkList(XmlSerializer out, List<WifiConfiguration> networkList, 133 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 134 throws XmlPullParserException, IOException { 135 if (networkList == null) { 136 return; 137 } 138 for (WifiConfiguration network : networkList) { 139 serializeNetwork(out, network, encryptionUtil); 140 } 141 } 142 143 /** 144 * Serialize a {@link WifiConfiguration} to an output stream in XML format. 145 * 146 * @param out The output stream to serialize the data to 147 * @param config The network config to serialize 148 * @param encryptionUtil Instance of {@link WifiConfigStoreEncryptionUtil} 149 * @throws XmlPullParserException 150 * @throws IOException 151 */ serializeNetwork(XmlSerializer out, WifiConfiguration config, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)152 private void serializeNetwork(XmlSerializer out, WifiConfiguration config, 153 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 154 throws XmlPullParserException, IOException { 155 XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_NETWORK); 156 157 // Serialize WifiConfiguration. 158 XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION); 159 WifiConfigurationXmlUtil.writeToXmlForConfigStore(out, config, encryptionUtil); 160 XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION); 161 162 // Serialize network selection status. 163 XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_NETWORK_STATUS); 164 NetworkSelectionStatusXmlUtil.writeToXml(out, config.getNetworkSelectionStatus()); 165 XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_NETWORK_STATUS); 166 167 // Serialize IP configuration. 168 XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_IP_CONFIGURATION); 169 IpConfigurationXmlUtil.writeToXml(out, config.getIpConfiguration()); 170 XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_IP_CONFIGURATION); 171 172 // Serialize enterprise configuration for enterprise networks. 173 if (config.enterpriseConfig != null 174 && config.enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE) { 175 XmlUtil.writeNextSectionStart( 176 out, XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION); 177 WifiEnterpriseConfigXmlUtil.writeToXml(out, config.enterpriseConfig, encryptionUtil); 178 XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION); 179 } 180 181 XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_NETWORK); 182 } 183 184 /** 185 * Parse a list of {@link WifiConfiguration} from an input stream in XML format. 186 * 187 * @param in The input stream to read from 188 * @param outerTagDepth The XML tag depth of the outer XML block 189 * @param version Version of config store file. 190 * @param encryptionUtil Instance of {@link WifiConfigStoreEncryptionUtil} 191 * @return List of {@link WifiConfiguration} 192 * @throws XmlPullParserException 193 * @throws IOException 194 */ parseNetworkList(XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)195 private List<WifiConfiguration> parseNetworkList(XmlPullParser in, int outerTagDepth, 196 @WifiConfigStore.Version int version, 197 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 198 throws XmlPullParserException, IOException { 199 List<WifiConfiguration> networkList = new ArrayList<>(); 200 while (XmlUtil.gotoNextSectionWithNameOrEnd(in, XML_TAG_SECTION_HEADER_NETWORK, 201 outerTagDepth)) { 202 // Try/catch only runtime exceptions (like illegal args), any XML/IO exceptions are 203 // fatal and should abort the entire loading process. 204 try { 205 WifiConfiguration config = 206 parseNetwork(in, outerTagDepth + 1, version, encryptionUtil); 207 networkList.add(config); 208 } catch (RuntimeException e) { 209 // Failed to parse this network, skip it. 210 Log.e(TAG, "Failed to parse network config. Skipping...", e); 211 } 212 } 213 return networkList; 214 } 215 216 /** 217 * Parse a {@link WifiConfiguration} from an input stream in XML format. 218 * 219 * @param in The input stream to read from 220 * @param outerTagDepth The XML tag depth of the outer XML block 221 * @param version Version of config store file. 222 * @param encryptionUtil Instance of {@link WifiConfigStoreEncryptionUtil} 223 * @return {@link WifiConfiguration} 224 * @throws XmlPullParserException 225 * @throws IOException 226 */ parseNetwork(XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)227 private WifiConfiguration parseNetwork(XmlPullParser in, int outerTagDepth, 228 @WifiConfigStore.Version int version, 229 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 230 throws XmlPullParserException, IOException { 231 Pair<String, WifiConfiguration> parsedConfig = null; 232 NetworkSelectionStatus status = null; 233 IpConfiguration ipConfiguration = null; 234 WifiEnterpriseConfig enterpriseConfig = null; 235 236 String[] headerName = new String[1]; 237 while (XmlUtil.gotoNextSectionOrEnd(in, headerName, outerTagDepth)) { 238 switch (headerName[0]) { 239 case XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION: 240 if (parsedConfig != null) { 241 throw new XmlPullParserException("Detected duplicate tag for: " 242 + XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION); 243 } 244 parsedConfig = WifiConfigurationXmlUtil.parseFromXml(in, outerTagDepth + 1, 245 version >= ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION, 246 encryptionUtil); 247 break; 248 case XML_TAG_SECTION_HEADER_NETWORK_STATUS: 249 if (status != null) { 250 throw new XmlPullParserException("Detected duplicate tag for: " 251 + XML_TAG_SECTION_HEADER_NETWORK_STATUS); 252 } 253 status = NetworkSelectionStatusXmlUtil.parseFromXml(in, outerTagDepth + 1); 254 break; 255 case XML_TAG_SECTION_HEADER_IP_CONFIGURATION: 256 if (ipConfiguration != null) { 257 throw new XmlPullParserException("Detected duplicate tag for: " 258 + XML_TAG_SECTION_HEADER_IP_CONFIGURATION); 259 } 260 ipConfiguration = IpConfigurationXmlUtil.parseFromXml(in, outerTagDepth + 1); 261 break; 262 case XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION: 263 if (enterpriseConfig != null) { 264 throw new XmlPullParserException("Detected duplicate tag for: " 265 + XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION); 266 } 267 enterpriseConfig = 268 WifiEnterpriseConfigXmlUtil.parseFromXml(in, outerTagDepth + 1, 269 version >= ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION, 270 encryptionUtil); 271 break; 272 default: 273 throw new XmlPullParserException("Unknown tag under " 274 + XML_TAG_SECTION_HEADER_NETWORK + ": " + headerName[0]); 275 } 276 } 277 if (parsedConfig == null || parsedConfig.first == null || parsedConfig.second == null) { 278 throw new XmlPullParserException("XML parsing of wifi configuration failed"); 279 } 280 String configKeyParsed = parsedConfig.first; 281 WifiConfiguration configuration = parsedConfig.second; 282 String configKeyCalculated = configuration.configKey(); 283 if (!configKeyParsed.equals(configKeyCalculated)) { 284 throw new XmlPullParserException( 285 "Configuration key does not match. Retrieved: " + configKeyParsed 286 + ", Calculated: " + configKeyCalculated); 287 } 288 // Set creatorUid/creatorName for networks which don't have it set to valid value. 289 String creatorName = mContext.getPackageManager().getNameForUid(configuration.creatorUid); 290 if (creatorName == null) { 291 Log.e(TAG, "Invalid creatorUid for saved network " + configuration.configKey() 292 + ", creatorUid=" + configuration.creatorUid); 293 configuration.creatorUid = Process.SYSTEM_UID; 294 configuration.creatorName = 295 mContext.getPackageManager().getNameForUid(Process.SYSTEM_UID); 296 } else if (!creatorName.equals(configuration.creatorName)) { 297 Log.w(TAG, "Invalid creatorName for saved network " + configuration.configKey() 298 + ", creatorUid=" + configuration.creatorUid 299 + ", creatorName=" + configuration.creatorName); 300 configuration.creatorName = creatorName; 301 } 302 303 configuration.setNetworkSelectionStatus(status); 304 configuration.setIpConfiguration(ipConfiguration); 305 if (enterpriseConfig != null) { 306 configuration.enterpriseConfig = enterpriseConfig; 307 } 308 return configuration; 309 } 310 } 311 312