diff options
author | Arne Schwabe <arne@rfc2549.org> | 2012-04-30 02:53:12 +0200 |
---|---|---|
committer | Arne Schwabe <arne@rfc2549.org> | 2012-04-30 02:53:12 +0200 |
commit | 44fa929579f9d801de9b62269f80310f3405ba4a (patch) | |
tree | 2ec9d7e96aea032153e51aa1ec9df4ce23d9ad10 | |
parent | 59ec3d3da5b3a7dca678df9adde663a57ccd1632 (diff) |
version 0.4.2
--HG--
rename : src/de/blinkt/openvpn/BasicSettings.java => src/de/blinkt/openvpn/Settings_Basic.java
-rw-r--r-- | AndroidManifest.xml | 4 | ||||
-rw-r--r-- | res/layout/basic_settings.xml | 4 | ||||
-rw-r--r-- | res/menu/logmenu.xml | 9 | ||||
-rw-r--r-- | res/xml/vpn_headers.xml | 2 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/LogWindow.java | 13 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/OpenVPN.java | 4 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/OpenVPNThread.java | 61 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/OpenVpnManagementThread.java | 140 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/OpenVpnService.java | 354 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/Settings_Authentication.java | 6 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/Settings_Basic.java (renamed from src/de/blinkt/openvpn/BasicSettings.java) | 3 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/VPNPreferences.java | 5 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/VPNProfileList.java | 71 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/VpnProfile.java | 109 |
14 files changed, 513 insertions, 272 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 1aa0fca7..d7f7e082 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -17,8 +17,8 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="de.blinkt.openvpn" - android:versionCode="10" - android:versionName="0.0.4a" > + android:versionCode="11" + android:versionName="0.4.3" > <uses-permission android:name="android.permission.INTERNET" /> diff --git a/res/layout/basic_settings.xml b/res/layout/basic_settings.xml index 37d2c733..e19ec148 100644 --- a/res/layout/basic_settings.xml +++ b/res/layout/basic_settings.xml @@ -167,6 +167,8 @@ style="@style/item" android:layout_marginLeft="8dip" android:layout_marginRight="8dip" + android:hint="@string/pw_query_hint" + android:inputType="textPassword" /> </LinearLayout> @@ -203,8 +205,8 @@ style="@style/item" android:layout_marginLeft="8dip" android:layout_marginRight="8dip" + android:hint="@string/pw_query_hint" android:inputType="textPassword" /> - <!-- android:hint="@string/pw_query_hint" --> </LinearLayout> <LinearLayout diff --git a/res/menu/logmenu.xml b/res/menu/logmenu.xml new file mode 100644 index 00000000..f97418a1 --- /dev/null +++ b/res/menu/logmenu.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+<item android:id="@+id/clearlog"
+ android:icon="@android:drawable/ic_delete"
+ android:title="clear log"
+ android:showAsAction="ifRoom"
+ />
+
+</menu>
\ No newline at end of file diff --git a/res/xml/vpn_headers.xml b/res/xml/vpn_headers.xml index faaa6cdd..dd942832 100644 --- a/res/xml/vpn_headers.xml +++ b/res/xml/vpn_headers.xml @@ -3,7 +3,7 @@ <header android:tag="BasicSettings" - android:fragment="de.blinkt.openvpn.BasicSettings" + android:fragment="de.blinkt.openvpn.Settings_Basic" android:summary="Server, port and authentication method. Normally you should only settings specified here." android:title="Basic Settings" android:id="@+id/basicsettingsid"/> diff --git a/src/de/blinkt/openvpn/LogWindow.java b/src/de/blinkt/openvpn/LogWindow.java index 6c3e1ff7..b5e7008f 100644 --- a/src/de/blinkt/openvpn/LogWindow.java +++ b/src/de/blinkt/openvpn/LogWindow.java @@ -8,11 +8,12 @@ import android.os.Bundle; import android.os.Handler; import android.os.Handler.Callback; import android.os.Message; +import android.view.Menu; +import android.view.MenuInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ListAdapter; import android.widget.ListView; -import android.widget.SimpleAdapter; import android.widget.TextView; import de.blinkt.openvpn.OpenVPN.LogListener; @@ -45,7 +46,7 @@ public class LogWindow extends ListActivity { observers.add(observer); } - + @Override public void unregisterDataSetObserver(DataSetObserver observer) { observers.remove(observer); @@ -133,6 +134,14 @@ public class LogWindow extends ListActivity { } + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.logmenu, menu); + return true; + } + + @Override public void onCreate(Bundle savedInstanceState) { diff --git a/src/de/blinkt/openvpn/OpenVPN.java b/src/de/blinkt/openvpn/OpenVPN.java index c3d92a4c..ea6c4926 100644 --- a/src/de/blinkt/openvpn/OpenVPN.java +++ b/src/de/blinkt/openvpn/OpenVPN.java @@ -53,6 +53,10 @@ public class OpenVPN { } + synchronized static void clearLog() { + logbuffer.clear(); + } + synchronized static void addLogListener(LogListener ll){ logListener.add(ll); } diff --git a/src/de/blinkt/openvpn/OpenVPNThread.java b/src/de/blinkt/openvpn/OpenVPNThread.java new file mode 100644 index 00000000..124179e5 --- /dev/null +++ b/src/de/blinkt/openvpn/OpenVPNThread.java @@ -0,0 +1,61 @@ +package de.blinkt.openvpn;
+
+import java.util.Arrays;
+
+import android.util.Log;
+
+public class OpenVPNThread implements Runnable {
+ private static final String TAG = "OpenVPN";
+ private OpenVpnService mService;
+ private String[] mArgv;
+
+ public OpenVPNThread(OpenVpnService service,String[] argv)
+ {
+ mService = service;
+ mArgv = argv;
+ }
+
+ @Override
+ public void run() {
+ try {
+ Log.i(TAG, "Starting o");
+
+
+ OpenVPN.setCallback(mService);
+
+
+ // We try to create the tunnel for several times. The better way
+ // is to work with ConnectivityManager, such as trying only when
+ // the network is avaiable. Here we just use a counter to keep
+ // things simple.
+ //for (int attempt = 0; attempt < 10; ++attempt) {
+ mService.getHandler().sendEmptyMessage(R.string.connecting);
+
+ // Log argv
+
+ OpenVPN.logMessage(0, "argv:" , Arrays.toString(mArgv));
+
+ OpenVPN.startOpenVPNThreadArgs(mArgv);
+
+
+
+ // Sleep for a while. This also checks if we got interrupted.
+ Thread.sleep(3000);
+ //}
+ Log.i(TAG, "Giving up");
+ } catch (Exception e) {
+ Log.e(TAG, "Got " + e.toString());
+ } finally {
+ try {
+ /// mInterface.close();
+ } catch (Exception e) {
+ // ignore
+ }
+ //mInterface = null;
+
+
+ mService.getHandler().sendEmptyMessage(R.string.disconnected);
+ Log.i(TAG, "Exiting");
+ }
+ }
+}
diff --git a/src/de/blinkt/openvpn/OpenVpnManagementThread.java b/src/de/blinkt/openvpn/OpenVpnManagementThread.java new file mode 100644 index 00000000..00d8fe9b --- /dev/null +++ b/src/de/blinkt/openvpn/OpenVpnManagementThread.java @@ -0,0 +1,140 @@ +package de.blinkt.openvpn;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import android.net.LocalSocket;
+import android.util.Log;
+
+public class OpenVpnManagementThread implements Runnable {
+
+ private static final String TAG = "openvpn";
+ private LocalSocket mSocket;
+ private VpnProfile mProfile;
+
+ public OpenVpnManagementThread(VpnProfile profile, LocalSocket mgmtsocket) {
+ mProfile = profile;
+ mSocket = mgmtsocket;
+ }
+
+
+ private String managmentEscape(String unescape) {
+ String escapedString = unescape.replace("\\", "\\\\");
+ escapedString = escapedString.replace("\"","\\\"");
+ escapedString = escapedString.replace("\n","\\n");
+ return '"' + escapedString + '"';
+ }
+
+
+ public void managmentCommand(String cmd) {
+ try {
+ mSocket.getOutputStream().write(cmd.getBytes());
+ mSocket.getOutputStream().flush();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ @Override
+ public void run() {
+ Log.i(TAG, "Managment Socket Thread started");
+ byte [] buffer =new byte[2048];
+ // mSocket.setSoTimeout(5); // Setting a timeout cannot be that bad
+ InputStream instream = null;
+ try {
+ instream = mSocket.getInputStream();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ String pendingInput="";
+
+ try {
+
+ while(true) {
+ int numbytesread = instream.read(buffer);
+ if(numbytesread==-1)
+ return;
+
+ String input = new String(buffer,0,numbytesread,"UTF-8");
+
+ pendingInput += input;
+
+ pendingInput=processInput(pendingInput);
+
+
+
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ private String processInput(String pendingInput) {
+ while(pendingInput.contains("\n")) {
+ String[] tokens = pendingInput.split("\\r?\\n", 2);
+ processCommand(tokens[0]);
+ if(tokens.length == 1)
+ // No second part, newline was at the end
+ pendingInput="";
+ else
+ pendingInput=tokens[1];
+ }
+ return pendingInput;
+ }
+
+
+ private void processCommand(String command) {
+ if (command.startsWith(">") && command.contains(":")) {
+ String[] parts = command.split(":",2);
+ String cmd = parts[0].substring(1);
+ String argument = parts[1];
+
+
+ if(cmd.equals("INFO"))
+ logStatusMessage(command);
+ else if (cmd.equals("PASSWORD")) {
+ processPWCommand(argument);
+ } else if (cmd.equals("HOLD")) {
+ managmentCommand("hold release\n");
+ }
+ }
+ Log.i(TAG, "Got unrecognized command" + command);
+
+ }
+
+
+ private void processPWCommand(String argument) {
+ //argument has the form Need 'Private Key' password
+ int p1 =argument.indexOf('\'');
+ int p2 = argument.indexOf('\'',p1+1);
+ //String needed = argument.replace("Need '", "").replace("' password", "");
+ String needed = argument.substring(p1+1, p2);
+
+ String pw=null;
+
+ if(needed.equals("Private Key")) {
+ pw = mProfile.getPasswordPrivateKey();
+ } else if (needed.equals("Auth")) {
+ String usercmd = String.format("username '%s' %s\n",
+ needed, managmentEscape(mProfile.mUsername));
+ managmentCommand(usercmd);
+ pw = mProfile.getPasswordAuth();
+ }
+ if(pw!=null) {
+ String cmd = String.format("password '%s' %s\n", needed, managmentEscape(pw));
+ managmentCommand(cmd);
+ }
+
+ }
+
+
+
+
+ private void logStatusMessage(String command) {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/src/de/blinkt/openvpn/OpenVpnService.java b/src/de/blinkt/openvpn/OpenVpnService.java index 39d73adb..031f2a14 100644 --- a/src/de/blinkt/openvpn/OpenVpnService.java +++ b/src/de/blinkt/openvpn/OpenVpnService.java @@ -17,13 +17,11 @@ package de.blinkt.openvpn; import java.io.IOException; -import java.net.UnknownHostException; -import java.util.Arrays; import java.util.Vector; -import de.blinkt.openvpn.OpenVpnService.CIDRIP; - +import android.app.NotificationManager; import android.app.PendingIntent; +import android.content.Context; import android.content.Intent; import android.net.LocalSocket; import android.net.LocalSocketAddress; @@ -31,19 +29,15 @@ import android.net.VpnService; import android.os.Handler; import android.os.Message; import android.os.ParcelFileDescriptor; -import android.util.Log; import android.widget.Toast; -public class OpenVpnService extends VpnService implements Handler.Callback, Runnable { - private static final String TAG = "OpenVpnService"; - - private String[] mArgv; +public class OpenVpnService extends VpnService implements Handler.Callback { + private static final String TAG = "OpenVpnService"; - private Handler mHandler; - // Only one VPN, make this thread shared between all instances - private static Thread mThread; + Handler mHandler; + private Thread mServiceThread; - private ParcelFileDescriptor mInterface; + private ParcelFileDescriptor mInterface; private Vector<String> mDnslist=new Vector<String>(); @@ -55,7 +49,14 @@ public class OpenVpnService extends VpnService implements Handler.Callback, Runn private CIDRIP mLocalIP; - + private OpenVpnManagementThread mSocketManager; + + private Thread mSocketManagerThread; + + private NotificationManager mNotificationManager; + + + class CIDRIP{ String mIp; int len; @@ -63,12 +64,12 @@ public class OpenVpnService extends VpnService implements Handler.Callback, Runn mIp=ip; String[] ipt = mask.split("\\."); long netmask=0; - + netmask += Integer.parseInt(ipt[0]); netmask += Integer.parseInt(ipt[1])<< 8; netmask += Integer.parseInt(ipt[2])<< 16; netmask += Integer.parseInt(ipt[3])<< 24; - + len =0; while((netmask & 0x1) == 1) { len++; @@ -80,209 +81,147 @@ public class OpenVpnService extends VpnService implements Handler.Callback, Runn return String.format("%s/%d",mIp,len); } } - - @Override - public void onRevoke() { - managmentCommand("signal SIGINT\n"); - mThread=null; - stopSelf(); - }; - - - public void managmentCommand(String cmd) { - LocalSocket mgmtsocket; - try { - byte[] buffer = new byte[400]; - mgmtsocket = new LocalSocket(); - - mgmtsocket.connect(new LocalSocketAddress(getCacheDir().getAbsolutePath() + "/" + "mgmtsocket", - LocalSocketAddress.Namespace.FILESYSTEM)); - //mgmtsocket = new Dat("127.0.0.1",OpenVPNClient.MANAGMENTPORT)); - - //OutputStreamWriter outw = new OutputStreamWriter(mgmtsocket.getOutputStream()); - mgmtsocket.getInputStream().read(buffer); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - } - //outw.write(cmd); - mgmtsocket.getOutputStream().write(cmd.getBytes()); - //outw.flush(); - try { - Thread.sleep(400); - } catch (InterruptedException e) { - } - mgmtsocket.close(); - } catch (UnknownHostException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); + @Override + public void onRevoke() { + mSocketManager.managmentCommand("signal SIGINT\n"); + mServiceThread=null; + stopSelf(); + }; + + + + + + + private LocalSocket openManagmentInterface() { + // Could take a while to open connection + String socketname = (getCacheDir().getAbsolutePath() + "/" + "mgmtsocket"); + LocalSocket sock = new LocalSocket(); + int tries = 8; + + while(tries > 0 && !sock.isConnected()) { + try { + sock.connect(new LocalSocketAddress(socketname, + LocalSocketAddress.Namespace.FILESYSTEM)); + } catch (IOException e) { + // wait 300 ms before retrying + try { Thread.sleep(300); + } catch (InterruptedException e1) {} + + } + tries--; } + return sock; + } - - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - // The handler is only used to show messages. - if (mHandler == null) { - mHandler = new Handler(this); - } - - // Stop the previous session by interrupting the thread. - if (mThread != null) { - managmentCommand("signal SIGINT\n"); - mThread.interrupt(); - } - - // Thread already running, reuse existing, - - // Extract information from the intent. - String prefix = getPackageName(); - mArgv = intent.getStringArrayExtra(prefix + ".ARGV"); - - - // Start a new session by creating a new thread. - mThread = new Thread(this, "OpenVPNThread"); - mThread.start(); - - String profileUUID = intent.getStringExtra(prefix + ".profileUUID"); - mProfile = ProfileManager.get(profileUUID); - - if(intent.hasExtra(prefix +".PKCS12PASS")) - { - try { - String pkcs12password = intent.getStringExtra(prefix +".PKCS12PASS"); - Thread.sleep(3000); - - managmentCommand("password 'Private Key' " + pkcs12password + "\n"); - } catch (InterruptedException e) { - } - - } - if(intent.hasExtra(prefix +".USERNAME")) - { - try { - String user = managmentEscape(intent.getStringExtra(prefix +".USERNAME")); - String pw = managmentEscape(intent.getStringExtra(prefix +".PASSWORD")); - Thread.sleep(3000); - - - managmentCommand("username 'Auth' " + user+ "\n" + - "password 'Auth' " + pw + "\n"); - } catch (InterruptedException e) { - } - - } - - - return START_STICKY; - } - - private String managmentEscape(String unescape) { - String escapedString = unescape.replace("\\", "\\\\"); - escapedString = escapedString.replace("\"","\\\""); - escapedString = escapedString.replace("\n","\\n"); - return '"' + escapedString + '"'; + + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + // The handler is only used to show messages. + if (mHandler == null) { + mHandler = new Handler(this); + } + + mNotificationManager=(NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE); + + + // Stop the previous session by interrupting the thread. + if (mSocketManager != null) { + mSocketManager.managmentCommand("signal SIGINT\n"); + } + + if (mServiceThread!=null) { + mServiceThread.interrupt(); + } + + + // Extract information from the intent. + String prefix = getPackageName(); + String[] argv = intent.getStringArrayExtra(prefix + ".ARGV"); + + String profileUUID = intent.getStringExtra(prefix + ".profileUUID"); + mProfile = ProfileManager.get(profileUUID); + + // Start a new session by creating a new thread. + + OpenVPNThread serviceThread = new OpenVPNThread(this, argv); + + mServiceThread = new Thread(serviceThread, "OpenVPNServiceThread"); + mServiceThread.start(); + + + // Open the Management Interface + LocalSocket mgmtsocket = openManagmentInterface(); + + if(mgmtsocket!=null) { + // start a Thread that handles incoming messages of the managment socket + mSocketManager = new OpenVpnManagementThread(mProfile,mgmtsocket); + mSocketManagerThread = new Thread(mSocketManager,"OpenVPNMgmtThread"); + mSocketManagerThread.start(); + } + + return START_STICKY; } + + + @Override - public void onDestroy() { - if (mThread != null) { - managmentCommand("signal SIGINT\n"); - - mThread.interrupt(); - } - } - - @Override - public boolean handleMessage(Message message) { - if (message != null) { - Toast.makeText(this, message.what, Toast.LENGTH_SHORT).show(); - } - return true; - } - - @Override - public synchronized void run() { - try { - Log.i(TAG, "Starting o"); - - - OpenVPN.setCallback(this); - - - // We try to create the tunnel for several times. The better way - // is to work with ConnectivityManager, such as trying only when - // the network is avaiable. Here we just use a counter to keep - // things simple. - //for (int attempt = 0; attempt < 10; ++attempt) { - mHandler.sendEmptyMessage(R.string.connecting); - - // Log argv - - OpenVPN.logMessage(0, "argv:" , Arrays.toString(mArgv)); - - OpenVPN.startOpenVPNThreadArgs(mArgv); - - - - // Sleep for a while. This also checks if we got interrupted. - Thread.sleep(3000); - //} - Log.i(TAG, "Giving up"); - } catch (Exception e) { - Log.e(TAG, "Got " + e.toString()); - } finally { - try { - mInterface.close(); - } catch (Exception e) { - // ignore - } - mInterface = null; - - - mHandler.sendEmptyMessage(R.string.disconnected); - Log.i(TAG, "Exiting"); - } - } + public void onDestroy() { + if (mServiceThread != null) { + mSocketManager.managmentCommand("signal SIGINT\n"); + + mServiceThread.interrupt(); + } + } + + @Override + public boolean handleMessage(Message message) { + if (message != null) { + Toast.makeText(this, message.what, Toast.LENGTH_SHORT).show(); + } + return true; + } + + public ParcelFileDescriptor openTun() { - Builder builder = new Builder(); - - builder.addAddress(mLocalIP.mIp, mLocalIP.len); - - for (String dns : mDnslist ) { - builder.addDnsServer(dns); + Builder builder = new Builder(); + + builder.addAddress(mLocalIP.mIp, mLocalIP.len); + + for (String dns : mDnslist ) { + builder.addDnsServer(dns); } - - - for (CIDRIP route:mRoutes) { - builder.addRoute(route.mIp, route.len); - } - - if(mDomain!=null) - builder.addSearchDomain(mDomain); - - - mDnslist.clear(); - mRoutes.clear(); - - - builder.setSession(mProfile.mName + " - " + mLocalIP); - - // Let the configure Button show the Log - Intent intent = new Intent(getBaseContext(),LogWindow.class); - PendingIntent startLW = PendingIntent.getActivity(getApplicationContext(), 0, intent, 0); - builder.setConfigureIntent(startLW); - mInterface = builder.establish(); - return mInterface; - } + + for (CIDRIP route:mRoutes) { + builder.addRoute(route.mIp, route.len); + } + + if(mDomain!=null) + builder.addSearchDomain(mDomain); + mDnslist.clear(); + mRoutes.clear(); + + + builder.setSession(mProfile.mName + " - " + mLocalIP); + + // Let the configure Button show the Log + Intent intent = new Intent(getBaseContext(),LogWindow.class); + PendingIntent startLW = PendingIntent.getActivity(getApplicationContext(), 0, intent, 0); + builder.setConfigureIntent(startLW); + mInterface = builder.establish(); + return mInterface; + + } + public void addDNS(String dns) { mDnslist.add(dns); } @@ -303,4 +242,9 @@ public class OpenVpnService extends VpnService implements Handler.Callback, Runn public void setLocalIP(String local, String netmask) { mLocalIP = new CIDRIP(local, netmask); } + + + public Handler getHandler() { + return mHandler; + } } diff --git a/src/de/blinkt/openvpn/Settings_Authentication.java b/src/de/blinkt/openvpn/Settings_Authentication.java index 4c70344d..57d99417 100644 --- a/src/de/blinkt/openvpn/Settings_Authentication.java +++ b/src/de/blinkt/openvpn/Settings_Authentication.java @@ -1,8 +1,5 @@ package de.blinkt.openvpn; -import com.lamerman.FileDialog; -import com.lamerman.SelectionMode; - import android.app.Activity; import android.content.Intent; import android.os.Bundle; @@ -15,6 +12,9 @@ import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceFragment; import android.preference.SwitchPreference; +import com.lamerman.FileDialog; +import com.lamerman.SelectionMode; + public class Settings_Authentication extends PreferenceFragment implements OnPreferenceChangeListener, OnPreferenceClickListener { private static final int SELECT_TLS_FILE = 23223232; private CheckBoxPreference mExpectTLSCert; diff --git a/src/de/blinkt/openvpn/BasicSettings.java b/src/de/blinkt/openvpn/Settings_Basic.java index 51a4c2bc..35e86792 100644 --- a/src/de/blinkt/openvpn/BasicSettings.java +++ b/src/de/blinkt/openvpn/Settings_Basic.java @@ -41,7 +41,7 @@ import com.lamerman.FileDialog; import de.blinkt.openvpn.R.id; -public class BasicSettings extends Fragment implements View.OnClickListener, OnItemSelectedListener, Callback { +public class Settings_Basic extends Fragment implements View.OnClickListener, OnItemSelectedListener, Callback { private static final int CHOOSE_FILE_OFFSET = 1000; private static final int UPDATE_ALIAS = 20; @@ -90,7 +90,6 @@ public class BasicSettings extends Fragment implements View.OnClickListener, OnI public void onCreate(Bundle savedInstanceState) { - Bundle foo = getArguments(); String profileuuid =getArguments().getString(getActivity().getPackageName() + ".profileUUID"); mProfile=ProfileManager.get(profileuuid); super.onCreate(savedInstanceState); diff --git a/src/de/blinkt/openvpn/VPNPreferences.java b/src/de/blinkt/openvpn/VPNPreferences.java index 771cd902..38de9d3e 100644 --- a/src/de/blinkt/openvpn/VPNPreferences.java +++ b/src/de/blinkt/openvpn/VPNPreferences.java @@ -4,14 +4,13 @@ import java.util.List; import android.os.Bundle; import android.preference.PreferenceActivity; -import android.widget.Button; public class VPNPreferences extends PreferenceActivity { private String mProfileUUID; - private BasicSettings mBS; - public void setmBS(BasicSettings mBS) { + private Settings_Basic mBS; + public void setmBS(Settings_Basic mBS) { this.mBS = mBS; } diff --git a/src/de/blinkt/openvpn/VPNProfileList.java b/src/de/blinkt/openvpn/VPNProfileList.java index 8f4304dc..bc61dddb 100644 --- a/src/de/blinkt/openvpn/VPNProfileList.java +++ b/src/de/blinkt/openvpn/VPNProfileList.java @@ -13,6 +13,7 @@ import android.preference.PreferenceScreen; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; +import android.view.inputmethod.EditorInfo; import android.widget.EditText; import android.widget.Toast; import de.blinkt.openvpn.VPNConfigPreference.VpnPreferencesClickListener; @@ -58,6 +59,39 @@ public class VPNProfileList extends PreferenceFragment implements VpnPreference } } + private void askForPW(String type) { + + final EditText entry = new EditText(getActivity()); + entry.setSingleLine(); + entry.setInputType(EditorInfo.TYPE_TEXT_VARIATION_PASSWORD); + + AlertDialog.Builder dialog = new AlertDialog.Builder(getActivity()); + dialog.setTitle("Need " + type); + dialog.setMessage("Enter the password for profile " + mSelectedVPN.mName); + dialog.setView(entry); + + dialog.setPositiveButton(android.R.string.ok, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + String pw = entry.getText().toString(); + mSelectedVPN.mTransientPW = pw; + onActivityResult(START_VPN_PROFILE, Activity.RESULT_OK, null); + + } + + }); + dialog.setNegativeButton(android.R.string.cancel, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + } + }); + + dialog.create().show(); + + } + private void onAddProfileClicked() { Context context = getActivity(); if (context != null) { @@ -97,7 +131,7 @@ public class VPNProfileList extends PreferenceFragment implements VpnPreference } - + private void addProfile(VpnProfile profile) { getPM().addProfile(profile); getPM().saveProfileList(getActivity()); @@ -107,7 +141,7 @@ public class VPNProfileList extends PreferenceFragment implements VpnPreference - + public void refreshList() { PreferenceScreen plist = getPreferenceScreen(); @@ -159,7 +193,12 @@ public class VPNProfileList extends PreferenceFragment implements VpnPreference public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if(requestCode==START_VPN_PROFILE && resultCode == Activity.RESULT_OK) { - new startOpenVpnThread().start(); + + if(mSelectedVPN.needUserPWInput()!=null) { + askForPW(mSelectedVPN.needUserPWInput()); + } else { + new startOpenVpnThread().start(); + } } else if (requestCode == START_VPN_CONFIG && resultCode == Activity.RESULT_OK) { String configuredVPN = data.getStringExtra(getActivity().getPackageName() + ".profileUUID"); @@ -183,44 +222,44 @@ public class VPNProfileList extends PreferenceFragment implements VpnPreference Intent startLW = new Intent(getActivity().getBaseContext(),LogWindow.class); startActivity(startLW); - + OpenVPN.logMessage(0, "", "Building configration..."); - + Intent startVPN = mSelectedVPN.prepareIntent(getActivity()); - + getActivity().startService(startVPN); getActivity().finish(); - + } } void showConfigErrorDialog(int vpnok) { - + AlertDialog.Builder d = new AlertDialog.Builder(getActivity()); d.setTitle(R.string.config_error_found); - + d.setMessage(vpnok); - - + + d.setPositiveButton("Ok", null); - + d.show(); } - + @Override public void onStartVPNClick(VPNConfigPreference preference) { getPM(); // Query the System for permission mSelectedVPN = ProfileManager.get(preference.getKey()); - + int vpnok = mSelectedVPN.checkProfile(); if(vpnok!= R.string.no_error_found) { showConfigErrorDialog(vpnok); return; } - - + + getPM().saveProfile(getActivity(), mSelectedVPN); Intent intent = VpnService.prepare(getActivity()); diff --git a/src/de/blinkt/openvpn/VpnProfile.java b/src/de/blinkt/openvpn/VpnProfile.java index 2db89395..4028f3d0 100644 --- a/src/de/blinkt/openvpn/VpnProfile.java +++ b/src/de/blinkt/openvpn/VpnProfile.java @@ -38,6 +38,7 @@ public class VpnProfile implements Serializable{ public static final int TYPE_STATICKEYS = 4; private static final String OVPNCONFIGFILE = "android.conf"; + // Keep in order of parceling // Public attributes, since I got mad with getter/setter @@ -74,6 +75,10 @@ public class VpnProfile implements Serializable{ public String mUsername=""; public boolean mRoutenopull=false; + + protected transient String mTransientPW=null; + private static transient String mTempPKCS12Password; + public int describeContents() { return 0; @@ -153,10 +158,17 @@ public class VpnProfile implements Serializable{ String cfg=""; + // Enable managment interface + cfg += "management "; - // TODO "--remote-cert-eku", "TLS Web Server Authentication" - - + cfg +=cacheDir.getAbsolutePath() + "/" + "mgmtsocket"; + cfg += " unix\n"; + cfg += "management-hold\n\n"; + + cfg+="# tmp does not exist on Android\n"; + cfg+="tmp-dir "; + cfg+=cacheDir.getAbsolutePath(); + cfg+="\n\n"; boolean useTLSClient = (mAuthenticationType != TYPE_STATICKEYS); @@ -171,10 +183,7 @@ public class VpnProfile implements Serializable{ cfg+="verb 2\n"; - // /tmp does not exist on Android - cfg+="tmp-dir "; - cfg+=cacheDir.getAbsolutePath(); - cfg+="\n"; + // quit after 5 tries cfg+="connect-retry-max 5\n"; @@ -339,14 +348,6 @@ public class VpnProfile implements Serializable{ // Add fixed paramenters args.add("openvpn"); - // Enable managment interface to - // stop openvpn - args.add("--management"); - - args.add(cacheDir.getAbsolutePath() + "/" + "mgmtsocket"); - args.add("unix"); - //args.add("--management-hold"); - args.add("--config"); args.add(cacheDir.getAbsolutePath() + "/" + OVPNCONFIGFILE); @@ -358,24 +359,12 @@ public class VpnProfile implements Serializable{ String prefix = activity.getPackageName(); Intent intent = new Intent(activity,OpenVpnService.class); + + if(mAuthenticationType == VpnProfile.TYPE_KEYSTORE) { + savePKCS12(activity); + } intent.putExtra(prefix + ".ARGV" , buildOpenvpnArgv(activity.getCacheDir())); - - if(mAuthenticationType == TYPE_PKCS12){ - intent.putExtra(prefix + ".PKCS12PASS", - mPKCS12Password); - } - - if(mAuthenticationType == VpnProfile.TYPE_KEYSTORE) { - String pkcs12pw = savePKCS12(activity); - intent.putExtra(prefix + ".PKCS12PASS", pkcs12pw); - } - - if(mAuthenticationType == VpnProfile.TYPE_USERPASS) { - intent.putExtra(prefix + ".USERNAME", mUsername); - intent.putExtra(prefix + ".PASSWORD", mPassword); - } - intent.putExtra(prefix + ".profileUUID", mUuid.toString()); try { @@ -390,7 +379,10 @@ public class VpnProfile implements Serializable{ return intent; } - private String getRandomPW() { + public String getTemporaryPKCS12Password() { + if(mTempPKCS12Password!=null) + return mTempPKCS12Password; + String pw= ""; // Put enough digits togher to make a password :) Random r = new Random(); @@ -398,11 +390,12 @@ public class VpnProfile implements Serializable{ pw += new Integer(r.nextInt(1000)).toString(); } - return pw; + mTempPKCS12Password=pw; + return mTempPKCS12Password; } - private String savePKCS12(Context context) { + private void savePKCS12(Context context) { PrivateKey privateKey = null; X509Certificate[] cachain=null; try { @@ -412,11 +405,11 @@ public class VpnProfile implements Serializable{ KeyStore ks = KeyStore.getInstance("PKCS12"); ks.load(null, null); ks.setKeyEntry("usercert", privateKey, null, cachain); - String mypw = getRandomPW(); + String mypw = getTemporaryPKCS12Password(); FileOutputStream fout = new FileOutputStream(context.getCacheDir().getAbsolutePath() + "/" + VpnProfile.OVPNCONFIGPKCS12); ks.store(fout,mypw.toCharArray()); fout.flush(); fout.close(); - return mypw; + return; } catch (KeyChainException e) { e.printStackTrace(); } catch (InterruptedException e) { @@ -432,7 +425,6 @@ public class VpnProfile implements Serializable{ } catch (IOException e) { e.printStackTrace(); } - return "ERROR"; } //! Return an error if somethign is wrong @@ -453,6 +445,49 @@ public class VpnProfile implements Serializable{ } + //! Openvpn asks for a "Private Key", this can be pkcs12 pw or private key pw + // + public String getPasswordPrivateKey() { + if(mTransientPW!=null) { + return mTransientPW; + } + switch (mAuthenticationType) { + case TYPE_KEYSTORE: + return getTemporaryPKCS12Password(); + + case TYPE_PKCS12: + return mPKCS12Password; + + case TYPE_USERPASS: + case TYPE_STATICKEYS: + case TYPE_CERTIFICATES: + default: + return null; + } + } + + public String needUserPWInput() { + if(mTransientPW!=null) + return null; + if(mAuthenticationType == TYPE_PKCS12 && + (mPKCS12Password.equals("") || mPKCS12Password == null)) { + return "PKCS12 File Password"; + } + if(mAuthenticationType == TYPE_USERPASS && + (mPassword.equals("") || mPassword == null)) { + return "Password"; + } + return null; + } + + public String getPasswordAuth() { + if(mTransientPW!=null) + return mTransientPW; + else + return mPassword; + } + + } |