From 2bb04a1f0cad2570845a96db4d1e30c441b16d09 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Mon, 8 May 2023 22:45:38 +0200 Subject: Allow setting remote control apps via managed configuration Closes ##1610 Signed-off-by: Arne Schwabe --- .../de/blinkt/openvpn/api/AppRestrictions.java | 67 ++++++++++++++++++---- .../de/blinkt/openvpn/api/ExternalAppDatabase.java | 48 ++++++++++++++-- .../de/blinkt/openvpn/core/OpenVPNService.java | 6 +- main/src/main/res/values/untranslatable.xml | 5 ++ main/src/main/res/xml/app_restrictions.xml | 66 ++++++++++++--------- .../de/blinkt/openvpn/fragments/GeneralSettings.kt | 4 ++ 6 files changed, 152 insertions(+), 44 deletions(-) (limited to 'main') diff --git a/main/src/main/java/de/blinkt/openvpn/api/AppRestrictions.java b/main/src/main/java/de/blinkt/openvpn/api/AppRestrictions.java index bdab3be3..8a5d1c71 100644 --- a/main/src/main/java/de/blinkt/openvpn/api/AppRestrictions.java +++ b/main/src/main/java/de/blinkt/openvpn/api/AppRestrictions.java @@ -14,6 +14,7 @@ import android.text.TextUtils; import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.core.ConfigParser; +import de.blinkt.openvpn.core.OpenVPNService; import de.blinkt.openvpn.core.Preferences; import de.blinkt.openvpn.core.ProfileManager; import de.blinkt.openvpn.core.VpnStatus; @@ -93,12 +94,61 @@ public class AppRestrictions { VpnStatus.logError(String.format(Locale.US, "App restriction version %s does not match expected version %d", configVersion, CONFIG_VERSION)); return; } - Parcelable[] profileList = restrictions.getParcelableArray(("vpn_configuration_list")); + Parcelable[] profileList = restrictions.getParcelableArray("vpn_configuration_list"); if (profileList == null) { VpnStatus.logError("App restriction does not contain a profile list (vpn_configuration_list)"); return; } + importVPNProfiles(c, restrictions, profileList); + setAllowedRemoteControl(c, restrictions); + + setMiscSettings(c, restrictions); + } + + private void setAllowedRemoteControl(Context c, Bundle restrictions) { + Parcelable[] allowedApps = restrictions.getParcelableArray("allowed_remote_access"); + ExternalAppDatabase extapps = new ExternalAppDatabase(c); + + if (allowedApps == null) + { + extapps.setFlagManagedConfiguration(false); + return; + } + + HashSet restrictionApps = new HashSet<>(); + + for (Parcelable allowedApp: allowedApps) { + if (!(allowedApp instanceof Bundle)) { + VpnStatus.logError("App restriction allowed app has wrong type"); + continue; + } + String package_name = ((Bundle) allowedApp).getString("package_name"); + restrictionApps.add(package_name); + } + + extapps.setFlagManagedConfiguration(true); + extapps.clearAllApiApps(); + + if(!extapps.getExtAppList().equals(restrictionApps)) + { + extapps.setAllowedApps(restrictionApps); + } + } + + private static void setMiscSettings(Context c, Bundle restrictions) { + SharedPreferences defaultPrefs = Preferences.getDefaultSharedPreferences(c); + + if(restrictions.containsKey("screenoffpausevpn")) + { + boolean pauseVPN = restrictions.getBoolean("screenoffpausevpn"); + SharedPreferences.Editor editor = defaultPrefs.edit(); + editor.putBoolean("screenoff", pauseVPN); + editor.apply(); + } + } + + private void importVPNProfiles(Context c, Bundle restrictions, Parcelable[] profileList) { Set provisionedUuids = new HashSet<>(); String defaultprofile = restrictions.getString("defaultprofile", null); @@ -117,7 +167,7 @@ public class AppRestrictions { String name = p.getString("name"); String certAlias = p.getString("certificate_alias"); - if (uuid == null || ovpn == null || name == null) { + if (TextUtils.isEmpty(uuid) || TextUtils.isEmpty(ovpn) || TextUtils.isEmpty(name)) { VpnStatus.logError("App restriction profile misses uuid, ovpn or name key"); continue; } @@ -125,6 +175,8 @@ public class AppRestrictions { /* we always use lower case uuid since Android UUID class will use present * them that way */ uuid = uuid.toLowerCase(Locale.US); + if (defaultprofile != null) + defaultprofile = defaultprofile.toLowerCase(Locale.US); if (uuid.equals(defaultprofile)) defaultprofileProvisioned = true; @@ -178,14 +230,6 @@ public class AppRestrictions { } } } - - if(restrictions.containsKey("screenoffpausevpn")) - { - boolean pauseVPN = restrictions.getBoolean("screenoffpausevpn"); - SharedPreferences.Editor editor = defaultPrefs.edit(); - editor.putBoolean("screenoff", pauseVPN); - editor.apply(); - } } /** @@ -196,6 +240,9 @@ public class AppRestrictions { if (vpnProfile == null) return; + if (certAlias == null) + certAlias = ""; + int oldType = vpnProfile.mAuthenticationType; String oldAlias = vpnProfile.mAlias; diff --git a/main/src/main/java/de/blinkt/openvpn/api/ExternalAppDatabase.java b/main/src/main/java/de/blinkt/openvpn/api/ExternalAppDatabase.java index 57e82778..fe0afdb6 100644 --- a/main/src/main/java/de/blinkt/openvpn/api/ExternalAppDatabase.java +++ b/main/src/main/java/de/blinkt/openvpn/api/ExternalAppDatabase.java @@ -13,11 +13,13 @@ import android.content.SharedPreferences.Editor; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.Binder; +import android.widget.Toast; import java.util.HashSet; import java.util.Set; import de.blinkt.openvpn.core.Preferences; +import de.blinkt.openvpn.core.VpnStatus; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; @@ -30,12 +32,34 @@ public class ExternalAppDatabase { } private final static String PREFERENCES_KEY = "allowed_apps"; + private final static String PREFERENCES_KEY_MANAGED_CONFIG = "allowed_apps_managed"; + + public void setFlagManagedConfiguration(boolean managed) + { + SharedPreferences prefs = Preferences.getDefaultSharedPreferences(mContext); + Editor prefedit = prefs.edit(); + + prefedit.putBoolean(PREFERENCES_KEY_MANAGED_CONFIG, managed); + increaseWorkaroundCounter(prefs, prefedit); + prefedit.apply(); + } + + public boolean isManagedConfiguration() + { + SharedPreferences prefs = Preferences.getDefaultSharedPreferences(mContext); + return prefs.getBoolean(PREFERENCES_KEY_MANAGED_CONFIG, false); + } + + private static void increaseWorkaroundCounter(SharedPreferences prefs, Editor prefedit) { + // Workaround for bug + int counter = prefs.getInt("counter", 0); + prefedit.putInt("counter", counter + 1); + } boolean isAllowed(String packagename) { Set allowedapps = getExtAppList(); - return allowedapps.contains(packagename); - + return allowedapps.contains(packagename); } public Set getExtAppList() { @@ -50,14 +74,22 @@ public class ExternalAppDatabase { saveExtAppList(allowedapps); } + public boolean checkAllowingModifyingRemoteControl(Context c) { + if (isManagedConfiguration()) { + Toast.makeText(c, "Remote control apps are manged by managed configuration, cannot change", Toast.LENGTH_LONG).show(); + VpnStatus.logError("Remote control apps are manged by managed configuration, cannot change"); + return false; + } + return true; + } + private void saveExtAppList( Set allowedapps) { SharedPreferences prefs = Preferences.getDefaultSharedPreferences(mContext); Editor prefedit = prefs.edit(); // Workaround for bug prefedit.putStringSet(PREFERENCES_KEY, allowedapps); - int counter = prefs.getInt("counter", 0); - prefedit.putInt("counter", counter + 1); + increaseWorkaroundCounter(prefs, prefedit); prefedit.apply(); } @@ -83,9 +115,9 @@ public class ExternalAppDatabase { } } catch (PackageManager.NameNotFoundException e) { // App not found. Remove it from the list - removeApp(appPackage); + if (!isManagedConfiguration()) + removeApp(appPackage); } - } throw new SecurityException("Unauthorized OpenVPN API Caller"); } @@ -105,4 +137,8 @@ public class ExternalAppDatabase { return false; } } + + public void setAllowedApps(Set restrictionApps) { + saveExtAppList(restrictionApps); + } } diff --git a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java index 88c253ec..115d6319 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java +++ b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java @@ -180,10 +180,14 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } } + + @Override public void addAllowedExternalApp(String packagename) throws RemoteException { ExternalAppDatabase extapps = new ExternalAppDatabase(OpenVPNService.this); - extapps.addApp(packagename); + if(extapps.checkAllowingModifyingRemoteControl(this)) { + extapps.addApp(packagename); + } } @Override diff --git a/main/src/main/res/values/untranslatable.xml b/main/src/main/res/values/untranslatable.xml index 651af1d3..9da7f522 100644 --- a/main/src/main/res/values/untranslatable.xml +++ b/main/src/main/res/values/untranslatable.xml @@ -85,6 +85,11 @@ Failed to negotiate cipher with server URL Pause VPN when screen is off and less than 64 kB transferred data in 60s + List of apps that are allowed to use the remote AIDL. If this list is in the restrictions, the app will not allowe any changes to the list by the user. + Package name of the allow app (e.g. de.blinkt.openvpn.remoteapp) + Package + Allowed remote access app + Remote API access insecure diff --git a/main/src/main/res/xml/app_restrictions.xml b/main/src/main/res/xml/app_restrictions.xml index 0451fd25..55bc6888 100644 --- a/main/src/main/res/xml/app_restrictions.xml +++ b/main/src/main/res/xml/app_restrictions.xml @@ -1,5 +1,4 @@ - - @@ -7,49 +6,47 @@ + android:title="@string/apprest_ver" /> + android:restrictionType="bundle_array" + android:title="@string/apprest_vpnlist"> + android:restrictionType="bundle" + android:title="@string/apprest_vpnconf"> + android:title="@string/apprest_uuid" /> + /> + android:key="ovpn" + android:restrictionType="string" + android:title="@string/apprest_ovpn" /> + android:key="certificate_alias" + android:restrictionType="string" + android:title="@string/apprest_certalias" />