packages/modules/Wifi/service/java/com/android/server/wifi/WifiConfigManager.java
/**
* Add a network or update a network configuration to our database.
* If the supplied networkId is INVALID_NETWORK_ID, we create a new empty
* network configuration. Otherwise, the networkId should refer to an existing configuration.
*
* @param config provided WifiConfiguration object.
* @param uid UID of the app requesting the network addition/modification.
* @param packageName Package name of the app requesting the network addition/modification.
* @param overrideCreator when this set to true, will overrider the creator to the current
* modifier.
* @return NetworkUpdateResult object representing status of the update.
* WifiConfiguration object representing the existing configuration matching
* the new config, or null if none matches.
*/
private @NonNull Pair<NetworkUpdateResult, WifiConfiguration> addOrUpdateNetworkInternal(
@NonNull WifiConfiguration config, int uid, @Nullable String packageName,
boolean overrideCreator) {
if (mVerboseLoggingEnabled) {
Log.v(TAG, "Adding/Updating network " + config.getPrintableSsid());
}
WifiConfiguration newInternalConfig = null;
long supportedFeatures = mWifiInjector.getActiveModeWarden()
.getPrimaryClientModeManager().getSupportedFeatures();
// First check if we already have a network with the provided network id or configKey.
WifiConfiguration existingInternalConfig = getInternalConfiguredNetwork(config);
// No existing network found. So, potentially a network add.
if (existingInternalConfig == null) {
if (!WifiConfigurationUtil.validate(config, supportedFeatures,
WifiConfigurationUtil.VALIDATE_FOR_ADD)) {
Log.e(TAG, "Cannot add network with invalid config");
return new Pair<>(
new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID,
STATUS_INVALID_CONFIGURATION),
existingInternalConfig);
}
newInternalConfig =
createNewInternalWifiConfigurationFromExternal(config, uid, packageName);
// Since the original config provided may have had an empty
// {@link WifiConfiguration#allowedKeyMgmt} field, check again if we already have a
// network with the the same configkey.
existingInternalConfig =
getInternalConfiguredNetwork(newInternalConfig.getProfileKey());
}
// Existing network found. So, a network update.
if (existingInternalConfig != null) {
if (!WifiConfigurationUtil.validate(
config, supportedFeatures, WifiConfigurationUtil.VALIDATE_FOR_UPDATE)) {
Log.e(TAG, "Cannot update network with invalid config");
return new Pair<>(
new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID,
STATUS_INVALID_CONFIGURATION),
existingInternalConfig);
}
// Check for the app's permission before we let it update this network.
if (!canModifyNetwork(existingInternalConfig, uid, packageName)) {
Log.e(TAG, "UID " + uid + " does not have permission to update configuration "
+ config.getProfileKey());
return new Pair<>(
new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID,
STATUS_NO_PERMISSION_MODIFY_CONFIG),
existingInternalConfig);
}
if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)
&& !config.isPasspoint()) {
logUserActionEvents(existingInternalConfig, config);
}
newInternalConfig =
updateExistingInternalWifiConfigurationFromExternal(
existingInternalConfig, config, uid, packageName, overrideCreator);
}
if (!WifiConfigurationUtil.addUpgradableSecurityTypeIfNecessary(newInternalConfig)) {
return new Pair<>(
new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID),
existingInternalConfig);
}
// Only add networks with proxy settings if the user has permission to
if (WifiConfigurationUtil.hasProxyChanged(existingInternalConfig, newInternalConfig)
&& !canModifyProxySettings(uid, packageName)) {
Log.e(TAG, "UID " + uid + " does not have permission to modify proxy Settings "
+ config.getProfileKey() + ". Must have NETWORK_SETTINGS,"
+ " or be device or profile owner.");
return new Pair<>(
new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID),
existingInternalConfig);
}
// Only allow changes in Repeater Enabled flag if the user has permission to
if (WifiConfigurationUtil.hasRepeaterEnabledChanged(
existingInternalConfig, newInternalConfig)
&& !mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)
&& !mWifiPermissionsUtil.checkConfigOverridePermission(uid)) {
Log.e(TAG, "UID " + uid
+ " does not have permission to modify Repeater Enabled Settings "
+ " , or add a network with Repeater Enabled set to true "
+ config.getProfileKey() + ". Must have NETWORK_SETTINGS.");
return new Pair<>(
new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID),
existingInternalConfig);
}
if (WifiConfigurationUtil.hasMacRandomizationSettingsChanged(existingInternalConfig,
newInternalConfig) && !mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)
&& !mWifiPermissionsUtil.checkNetworkSetupWizardPermission(uid)
&& !mWifiPermissionsUtil.checkConfigOverridePermission(uid)
&& !(newInternalConfig.isPasspoint() && uid == newInternalConfig.creatorUid)
&& !config.fromWifiNetworkSuggestion
&& !mWifiPermissionsUtil.isDeviceInDemoMode(mContext)
&& !(mWifiPermissionsUtil.isAdmin(uid, packageName)
&& uid == newInternalConfig.creatorUid)) {
Log.e(TAG, "UID " + uid + " does not have permission to modify MAC randomization "
+ "Settings " + config.getProfileKey() + ". Must have "
+ "NETWORK_SETTINGS or NETWORK_SETUP_WIZARD or be in Demo Mode "
+ "or be the creator adding or updating a passpoint network "
+ "or be an admin updating their own network.");
return new Pair<>(
new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID),
existingInternalConfig);
}
if (config.isEnterprise()
&& config.enterpriseConfig.isEapMethodServerCertUsed()
&& !config.enterpriseConfig.isMandatoryParameterSetForServerCertValidation()
&& !config.enterpriseConfig.isTrustOnFirstUseEnabled()) {
boolean isSettingsOrSuw = mContext.checkPermission(Manifest.permission.NETWORK_SETTINGS,
-1 /* pid */, uid) == PERMISSION_GRANTED
|| mContext.checkPermission(Manifest.permission.NETWORK_SETUP_WIZARD,
-1 /* pid */, uid) == PERMISSION_GRANTED;
if (!(mWifiInjector.getWifiGlobals().isInsecureEnterpriseConfigurationAllowed()
&& isSettingsOrSuw)) {
Log.e(TAG, "Enterprise network configuration is missing either a Root CA "
+ "or a domain name");
return new Pair<>(
new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID,
STATUS_INVALID_CONFIGURATION_ENTERPRISE),
existingInternalConfig);
}
Log.w(TAG, "Insecure Enterprise network " + config.SSID
+ " configured by Settings/SUW");
// Implicit user approval, when creating an insecure connection which is allowed
// in the configuration of the device
newInternalConfig.enterpriseConfig.setUserApproveNoCaCert(true);
}
// Update the keys for saved enterprise networks. For Passpoint, the certificates
// and keys are installed at the time the provider is installed. For suggestion enterprise
// network the certificates and keys are installed at the time the suggestion is added
if (!config.isPasspoint() && !config.fromWifiNetworkSuggestion && config.isEnterprise()) {
if (!(mWifiKeyStore.updateNetworkKeys(newInternalConfig, existingInternalConfig))) {
return new Pair<>(
new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID),
existingInternalConfig);
}
}
// Validate an Enterprise network with Trust On First Use.
if (config.isEnterprise() && config.enterpriseConfig.isTrustOnFirstUseEnabled()) {
if ((supportedFeatures & WIFI_FEATURE_TRUST_ON_FIRST_USE) == 0) {
Log.e(TAG, "Trust On First Use could not be set "
+ "when Trust On First Use is not supported.");
return new Pair<>(
new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID),
existingInternalConfig);
}
if (!config.enterpriseConfig.isEapMethodServerCertUsed()) {
Log.e(TAG, "Trust On First Use could not be set "
+ "when the server certificate is not used.");
return new Pair<>(
new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID),
existingInternalConfig);
} else if (config.enterpriseConfig.hasCaCertificate()) {
Log.e(TAG, "Trust On First Use could not be set "
+ "when Root CA certificate is set.");
return new Pair<>(
new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID),
existingInternalConfig);
}
}
boolean newNetwork = (existingInternalConfig == null);
// This is needed to inform IpClient about any IP configuration changes.
boolean hasIpChanged =
newNetwork || WifiConfigurationUtil.hasIpChanged(
existingInternalConfig, newInternalConfig);
boolean hasProxyChanged =
newNetwork || WifiConfigurationUtil.hasProxyChanged(
existingInternalConfig, newInternalConfig);
// Reset the |hasEverConnected| flag if the credential parameters changed in this update.
boolean hasCredentialChanged =
newNetwork || WifiConfigurationUtil.hasCredentialChanged(
existingInternalConfig, newInternalConfig);
if (hasCredentialChanged) {
newInternalConfig.getNetworkSelectionStatus().setHasEverConnected(false);
newInternalConfig.setHasPreSharedKeyChanged(true);
Log.i(TAG, "Credential changed for netId=" + newInternalConfig.networkId);
}
// Add it to our internal map. This will replace any existing network configuration for
// updates.
try {
if (null != existingInternalConfig) {
mConfiguredNetworks.remove(existingInternalConfig.networkId);
}
mConfiguredNetworks.put(newInternalConfig);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Failed to add network to config map", e);
return new Pair<>(
new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID),
existingInternalConfig);
}
if (removeExcessNetworks(uid, packageName)) {
if (mConfiguredNetworks.getForAllUsers(newInternalConfig.networkId) == null) {
Log.e(TAG, "Cannot add network because number of configured networks is maxed.");
return new Pair<>(
new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID),
existingInternalConfig);
}
}
// Only re-enable network: 1. add or update user saved network; 2. add or update a user
// saved passpoint network framework consider it is a new network.
if (!newInternalConfig.fromWifiNetworkSuggestion
&& (!newInternalConfig.isPasspoint() || newNetwork)) {
userEnabledNetwork(newInternalConfig.networkId);
}
// Stage the backup of the SettingsProvider package which backs this up.
mBackupManagerProxy.notifyDataChanged();
NetworkUpdateResult result = new NetworkUpdateResult(
newInternalConfig.networkId,
STATUS_SUCCESS,
hasIpChanged,
hasProxyChanged,
hasCredentialChanged,
newNetwork);
localLog("addOrUpdateNetworkInternal: added/updated config."
+ " netId=" + newInternalConfig.networkId
+ " configKey=" + newInternalConfig.getProfileKey()
+ " uid=" + Integer.toString(newInternalConfig.creatorUid)
+ " name=" + newInternalConfig.creatorName);
return new Pair<>(result, existingInternalConfig);
}
packages/modules/Wifi/service/ServiceWifiResources/res/values/config.xml
<!-- Whether to allow Settings or SUW to create insecure Enterprise networks where server
certificate is not validated, by not specifying a Root CA certificate and/or server domain
name. It is STRONGLY RECOMMENDED to be set to false -->
<bool translatable="false" name="config_wifiAllowInsecureEnterpriseConfigurationsForSettingsAndSUW">false</bool>