From f014940abd99c372004e227f2e68f31820162731 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Sun, 24 Dec 2017 01:39:53 +0100 Subject: Implement remote actions --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 4 +- main/build.gradle | 6 +- main/openssl | 2 +- main/src/main/AndroidManifest.xml | 7 + .../src/main/java/de/blinkt/openvpn/LaunchVPN.java | 9 +- .../java/de/blinkt/openvpn/api/ConfirmDialog.java | 191 +++++++++++---------- .../de/blinkt/openvpn/api/ExternalAppDatabase.java | 41 +++++ .../blinkt/openvpn/api/ExternalOpenVPNService.java | 43 ++--- .../java/de/blinkt/openvpn/api/RemoteAction.java | 73 ++++++++ main/src/main/res/values/strings.xml | 1 + 11 files changed, 253 insertions(+), 126 deletions(-) create mode 100644 main/src/main/java/de/blinkt/openvpn/api/RemoteAction.java diff --git a/build.gradle b/build.gradle index c482d85a..14cf5e15 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.1.0-alpha04' + classpath 'com.android.tools.build:gradle:3.1.0-alpha06' } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c188c8b0..d7e494a9 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Nov 24 12:34:12 EST 2017 +#Sun Dec 24 00:32:39 CET 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions-snapshots/gradle-4.4-20171031235950+0000-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-rc-3-all.zip diff --git a/main/build.gradle b/main/build.gradle index 6b49c36d..02384425 100644 --- a/main/build.gradle +++ b/main/build.gradle @@ -20,9 +20,9 @@ repositories { dependencies { implementation 'com.android.support.constraint:constraint-layout:1.0.2' - compile 'com.android.support:support-annotations:27.0.1' - compile 'com.android.support:cardview-v7:27.0.1' - compile 'com.android.support:recyclerview-v7:27.0.1' + compile 'com.android.support:support-annotations:27.0.2' + compile 'com.android.support:cardview-v7:27.0.2' + compile 'com.android.support:recyclerview-v7:27.0.2' // compile 'ch.acra:acra:4.5.0' compile 'com.github.PhilJay:MPAndroidChart:v3.0.2' diff --git a/main/openssl b/main/openssl index e6d693e8..2b0fd261 160000 --- a/main/openssl +++ b/main/openssl @@ -1 +1 @@ -Subproject commit e6d693e846f38eb43a06b1c464d534bf39be80db +Subproject commit 2b0fd26192c4014eabe8cbacbc87e0a2aec2d045 diff --git a/main/src/main/AndroidManifest.xml b/main/src/main/AndroidManifest.xml index e57cf096..efee02f7 100644 --- a/main/src/main/AndroidManifest.xml +++ b/main/src/main/AndroidManifest.xml @@ -224,6 +224,13 @@ android:name="android.support.PARENT_ACTIVITY" android:value="de.blinkt.openvpn.activities.MainActivity" /> + + \ No newline at end of file diff --git a/main/src/main/java/de/blinkt/openvpn/LaunchVPN.java b/main/src/main/java/de/blinkt/openvpn/LaunchVPN.java index 44e355ff..7b5d4e28 100644 --- a/main/src/main/java/de/blinkt/openvpn/LaunchVPN.java +++ b/main/src/main/java/de/blinkt/openvpn/LaunchVPN.java @@ -34,6 +34,7 @@ import android.widget.EditText; import java.io.IOException; import de.blinkt.openvpn.activities.LogWindow; +import de.blinkt.openvpn.api.ExternalAppDatabase; import de.blinkt.openvpn.core.ConnectionStatus; import de.blinkt.openvpn.core.IServiceStatus; import de.blinkt.openvpn.core.OpenVPNStatusService; @@ -139,8 +140,14 @@ public class LaunchVPN extends Activity { mhideLog = intent.getBooleanExtra(EXTRA_HIDELOG, false); VpnProfile profileToConnect = ProfileManager.get(this, shortcutUUID); - if (shortcutName != null && profileToConnect == null) + if (shortcutName != null && profileToConnect == null) { profileToConnect = ProfileManager.getInstance(this).getProfileByName(shortcutName); + if (!(new ExternalAppDatabase(this).checkRemoteActionPermission(this))) { + finish(); + return; + } + } + if (profileToConnect == null) { VpnStatus.logError(R.string.shortcut_profile_notfound); diff --git a/main/src/main/java/de/blinkt/openvpn/api/ConfirmDialog.java b/main/src/main/java/de/blinkt/openvpn/api/ConfirmDialog.java index 4124b7d4..2355f83b 100644 --- a/main/src/main/java/de/blinkt/openvpn/api/ConfirmDialog.java +++ b/main/src/main/java/de/blinkt/openvpn/api/ConfirmDialog.java @@ -21,6 +21,7 @@ import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.content.DialogInterface; import android.content.DialogInterface.OnShowListener; +import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.util.Log; @@ -29,97 +30,113 @@ import android.widget.Button; import android.widget.CompoundButton; import android.widget.ImageView; import android.widget.TextView; + import de.blinkt.openvpn.R; public class ConfirmDialog extends Activity implements -CompoundButton.OnCheckedChangeListener, DialogInterface.OnClickListener { - private static final String TAG = "OpenVPNVpnConfirm"; - - private String mPackage; - - private Button mButton; - - private AlertDialog mAlert; - - @Override - protected void onResume() { - super.onResume(); - try { - mPackage = getCallingPackage(); - if (mPackage==null) { - finish(); - return; - } - - - PackageManager pm = getPackageManager(); - ApplicationInfo app = pm.getApplicationInfo(mPackage, 0); - - View view = View.inflate(this, R.layout.api_confirm, null); - ((ImageView) view.findViewById(R.id.icon)).setImageDrawable(app.loadIcon(pm)); - ((TextView) view.findViewById(R.id.prompt)).setText( - getString(R.string.prompt, app.loadLabel(pm), getString(R.string.app))); - ((CompoundButton) view.findViewById(R.id.check)).setOnCheckedChangeListener(this); - - - Builder builder = new AlertDialog.Builder(this); - - builder.setView(view); - - builder.setIconAttribute(android.R.attr.alertDialogIcon); - builder.setTitle(android.R.string.dialog_alert_title); - builder.setPositiveButton(android.R.string.ok,this); - builder.setNegativeButton(android.R.string.cancel,this); - - mAlert = builder.create(); - mAlert.setCanceledOnTouchOutside(false); - - mAlert.setOnShowListener (new OnShowListener() { - @Override - public void onShow(DialogInterface dialog) { - mButton = mAlert.getButton(DialogInterface.BUTTON_POSITIVE); - mButton.setEnabled(false); - - } - }); - - //setCloseOnTouchOutside(false); - - mAlert.show(); - - } catch (Exception e) { - Log.e(TAG, "onResume", e); - finish(); - } - } - - @Override - public void onBackPressed() { - setResult(RESULT_CANCELED); - finish(); - } - - @Override - public void onCheckedChanged(CompoundButton button, boolean checked) { - mButton.setEnabled(checked); - } - - @Override - public void onClick(DialogInterface dialog, int which) { - - if (which == DialogInterface.BUTTON_POSITIVE) { - ExternalAppDatabase extapps = new ExternalAppDatabase(this); - extapps.addApp(mPackage); - setResult(RESULT_OK); - finish(); - } - - if (which == DialogInterface.BUTTON_NEGATIVE) { - setResult(RESULT_CANCELED); - finish(); - } - } + CompoundButton.OnCheckedChangeListener, DialogInterface.OnClickListener { + private static final String TAG = "OpenVPNVpnConfirm"; + + public static final String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME"; + + public static final String ANONYMOUS_PACKAGE = "de.blinkt.openvpn.ANYPACKAGE"; + + private String mPackage; + + private Button mButton; + + private AlertDialog mAlert; + + @Override + protected void onResume() { + super.onResume(); + + Intent intent = getIntent(); + if (intent.getStringExtra(EXTRA_PACKAGE_NAME) != null) { + mPackage = intent.getStringExtra(EXTRA_PACKAGE_NAME); + } else { + mPackage = getCallingPackage(); + if (mPackage == null) { + finish(); + return; + } + } + + try { + View view = View.inflate(this, R.layout.api_confirm, null); + CharSequence appString; + if (mPackage.equals(ANONYMOUS_PACKAGE)) { + appString = getString(R.string.all_app_prompt, getString(R.string.app)); + } else { + PackageManager pm = getPackageManager(); + ApplicationInfo app = pm.getApplicationInfo(mPackage, 0); + appString = getString(R.string.prompt, app.loadLabel(pm) , getString(R.string.app)); + ((ImageView) view.findViewById(R.id.icon)).setImageDrawable(app.loadIcon(pm)); + } + + + ((TextView) view.findViewById(R.id.prompt)).setText(appString); + ((CompoundButton) view.findViewById(R.id.check)).setOnCheckedChangeListener(this); + + + Builder builder = new AlertDialog.Builder(this); + + builder.setView(view); + + builder.setIconAttribute(android.R.attr.alertDialogIcon); + builder.setTitle(android.R.string.dialog_alert_title); + builder.setPositiveButton(android.R.string.ok, this); + builder.setNegativeButton(android.R.string.cancel, this); + + mAlert = builder.create(); + mAlert.setCanceledOnTouchOutside(false); + + mAlert.setOnShowListener(new OnShowListener() { + @Override + public void onShow(DialogInterface dialog) { + mButton = mAlert.getButton(DialogInterface.BUTTON_POSITIVE); + mButton.setEnabled(false); + + } + }); + + //setCloseOnTouchOutside(false); + + mAlert.show(); + + } catch (Exception e) { + Log.e(TAG, "onResume", e); + finish(); + } + } + + @Override + public void onBackPressed() { + setResult(RESULT_CANCELED); + finish(); + } + + @Override + public void onCheckedChanged(CompoundButton button, boolean checked) { + mButton.setEnabled(checked); + } + + @Override + public void onClick(DialogInterface dialog, int which) { + + if (which == DialogInterface.BUTTON_POSITIVE) { + ExternalAppDatabase extapps = new ExternalAppDatabase(this); + extapps.addApp(mPackage); + setResult(RESULT_OK); + finish(); + } + + if (which == DialogInterface.BUTTON_NEGATIVE) { + setResult(RESULT_CANCELED); + finish(); + } + } } 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 967d7728..e87b4c3a 100644 --- a/main/src/main/java/de/blinkt/openvpn/api/ExternalAppDatabase.java +++ b/main/src/main/java/de/blinkt/openvpn/api/ExternalAppDatabase.java @@ -5,9 +5,14 @@ package de.blinkt.openvpn.api; +import android.app.Activity; import android.content.Context; +import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.Binder; import java.util.HashSet; import java.util.Set; @@ -64,4 +69,40 @@ public class ExternalAppDatabase { saveExtAppList(allowedapps); } + + public String checkOpenVPNPermission(PackageManager pm) throws SecurityRemoteException { + + for (String appPackage : getExtAppList()) { + ApplicationInfo app; + try { + app = pm.getApplicationInfo(appPackage, 0); + if (Binder.getCallingUid() == app.uid) { + return appPackage; + } + } catch (PackageManager.NameNotFoundException e) { + // App not found. Remove it from the list + removeApp(appPackage); + } + + } + throw new SecurityException("Unauthorized OpenVPN API Caller"); + } + + + public boolean checkRemoteActionPermission(Activity a) { + + String callingPackage = a.getCallingPackage(); + + if (callingPackage == null) + callingPackage = ConfirmDialog.ANONYMOUS_PACKAGE; + + if (isAllowed(callingPackage)) { + return true; + } else { + Intent confirmDialog = new Intent(a, ConfirmDialog.class); + confirmDialog.putExtra(ConfirmDialog.EXTRA_PACKAGE_NAME, callingPackage); + a.startActivity(confirmDialog); + return false; + } + } } diff --git a/main/src/main/java/de/blinkt/openvpn/api/ExternalOpenVPNService.java b/main/src/main/java/de/blinkt/openvpn/api/ExternalOpenVPNService.java index 6b549ed1..e5c50a6c 100644 --- a/main/src/main/java/de/blinkt/openvpn/api/ExternalOpenVPNService.java +++ b/main/src/main/java/de/blinkt/openvpn/api/ExternalOpenVPNService.java @@ -111,28 +111,9 @@ public class ExternalOpenVPNService extends Service implements StateListener { private final IOpenVPNAPIService.Stub mBinder = new IOpenVPNAPIService.Stub() { - private String checkOpenVPNPermission() throws SecurityRemoteException { - PackageManager pm = getPackageManager(); - - for (String appPackage : mExtAppDb.getExtAppList()) { - ApplicationInfo app; - try { - app = pm.getApplicationInfo(appPackage, 0); - if (Binder.getCallingUid() == app.uid) { - return appPackage; - } - } catch (NameNotFoundException e) { - // App not found. Remove it from the list - mExtAppDb.removeApp(appPackage); - } - - } - throw new SecurityException("Unauthorized OpenVPN API Caller"); - } - @Override public List getProfiles() throws RemoteException { - checkOpenVPNPermission(); + mExtAppDb.checkOpenVPNPermission(getPackageManager()); ProfileManager pm = ProfileManager.getInstance(getBaseContext()); @@ -170,7 +151,7 @@ public class ExternalOpenVPNService extends Service implements StateListener { @Override public void startProfile(String profileUUID) throws RemoteException { - checkOpenVPNPermission(); + mExtAppDb.checkOpenVPNPermission(getPackageManager()); VpnProfile vp = ProfileManager.get(getBaseContext(), profileUUID); if (vp.checkProfile(getApplicationContext()) != R.string.no_error_found) @@ -180,7 +161,7 @@ public class ExternalOpenVPNService extends Service implements StateListener { } public void startVPN(String inlineConfig) throws RemoteException { - String callingApp = checkOpenVPNPermission(); + String callingApp = mExtAppDb.checkOpenVPNPermission(getPackageManager()); ConfigParser cp = new ConfigParser(); try { @@ -216,7 +197,7 @@ public class ExternalOpenVPNService extends Service implements StateListener { @Override public APIVpnProfile addNewVPNProfile(String name, boolean userEditable, String config) throws RemoteException { - String callingPackage = checkOpenVPNPermission(); + String callingPackage = mExtAppDb.checkOpenVPNPermission(getPackageManager()); ConfigParser cp = new ConfigParser(); try { @@ -241,7 +222,7 @@ public class ExternalOpenVPNService extends Service implements StateListener { @Override public void removeProfile(String profileUUID) throws RemoteException { - checkOpenVPNPermission(); + mExtAppDb.checkOpenVPNPermission(getPackageManager()); ProfileManager pm = ProfileManager.getInstance(getBaseContext()); VpnProfile vp = ProfileManager.get(getBaseContext(), profileUUID); pm.removeProfile(ExternalOpenVPNService.this, vp); @@ -249,7 +230,7 @@ public class ExternalOpenVPNService extends Service implements StateListener { @Override public boolean protectSocket(ParcelFileDescriptor pfd) throws RemoteException { - checkOpenVPNPermission(); + mExtAppDb.checkOpenVPNPermission(getPackageManager()); try { boolean success= mService.protect(pfd.getFd()); pfd.close(); @@ -272,7 +253,7 @@ public class ExternalOpenVPNService extends Service implements StateListener { @Override public Intent prepareVPNService() throws RemoteException { - checkOpenVPNPermission(); + mExtAppDb.checkOpenVPNPermission(getPackageManager()); if (VpnService.prepare(ExternalOpenVPNService.this) == null) return null; @@ -284,7 +265,7 @@ public class ExternalOpenVPNService extends Service implements StateListener { @Override public void registerStatusCallback(IOpenVPNStatusCallback cb) throws RemoteException { - checkOpenVPNPermission(); + mExtAppDb.checkOpenVPNPermission(getPackageManager()); if (cb != null) { cb.newStatus(mMostRecentState.vpnUUID, mMostRecentState.state, @@ -298,7 +279,7 @@ public class ExternalOpenVPNService extends Service implements StateListener { @Override public void unregisterStatusCallback(IOpenVPNStatusCallback cb) throws RemoteException { - checkOpenVPNPermission(); + mExtAppDb.checkOpenVPNPermission(getPackageManager()); if (cb != null) mCallbacks.unregister(cb); @@ -306,21 +287,21 @@ public class ExternalOpenVPNService extends Service implements StateListener { @Override public void disconnect() throws RemoteException { - checkOpenVPNPermission(); + mExtAppDb.checkOpenVPNPermission(getPackageManager()); if (mService != null) mService.stopVPN(false); } @Override public void pause() throws RemoteException { - checkOpenVPNPermission(); + mExtAppDb.checkOpenVPNPermission(getPackageManager()); if (mService != null) mService.userPause(true); } @Override public void resume() throws RemoteException { - checkOpenVPNPermission(); + mExtAppDb.checkOpenVPNPermission(getPackageManager()); if (mService != null) mService.userPause(false); diff --git a/main/src/main/java/de/blinkt/openvpn/api/RemoteAction.java b/main/src/main/java/de/blinkt/openvpn/api/RemoteAction.java new file mode 100644 index 00000000..cac8efcb --- /dev/null +++ b/main/src/main/java/de/blinkt/openvpn/api/RemoteAction.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2012-2017 Arne Schwabe + * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + */ + +package de.blinkt.openvpn.api; + +import android.app.Activity; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; + +import de.blinkt.openvpn.core.IOpenVPNServiceInternal; +import de.blinkt.openvpn.core.OpenVPNService; + +public class RemoteAction extends Activity { + + private ExternalAppDatabase mExtAppDb; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mExtAppDb = new ExternalAppDatabase(this); + } + + private ServiceConnection mConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName className, + IBinder service) { + + IOpenVPNServiceInternal myservice = IOpenVPNServiceInternal.Stub.asInterface(service); + try { + myservice.stopVPN(false); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + + @Override + public void onServiceDisconnected(ComponentName arg0) { + //mService = null; + } + + }; + + + @Override + protected void onResume() { + super.onResume(); + if (mExtAppDb.checkRemoteActionPermission(this)) + performAction(); + + finish(); + + } + + private void performAction() { + Intent intent = new Intent(this, OpenVPNService.class); + intent.setAction(OpenVPNService.START_SERVICE); + + ComponentName component = getIntent().getComponent(); + if (component.getShortClassName().equals(".api.DisconnectVPN")) { + boolean mDoDisconnect = true; + } + getApplicationContext().bindService(intent, mConnection, Context.BIND_AUTO_CREATE); + + + } +} diff --git a/main/src/main/res/values/strings.xml b/main/src/main/res/values/strings.xml index 67248dae..c814afc6 100755 --- a/main/src/main/res/values/strings.xml +++ b/main/src/main/res/values/strings.xml @@ -454,5 +454,6 @@ OpenSSL returned an error Running test… Test selected algorithms + An external app tries to control %s. The app cannot be determined allowing now grants ALL apps access. -- cgit v1.2.3