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