summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArne Schwabe <arne@rfc2549.org>2012-04-30 02:53:12 +0200
committerArne Schwabe <arne@rfc2549.org>2012-04-30 02:53:12 +0200
commit44fa929579f9d801de9b62269f80310f3405ba4a (patch)
tree2ec9d7e96aea032153e51aa1ec9df4ce23d9ad10
parent59ec3d3da5b3a7dca678df9adde663a57ccd1632 (diff)
version 0.4.2
--HG-- rename : src/de/blinkt/openvpn/BasicSettings.java => src/de/blinkt/openvpn/Settings_Basic.java
-rw-r--r--AndroidManifest.xml4
-rw-r--r--res/layout/basic_settings.xml4
-rw-r--r--res/menu/logmenu.xml9
-rw-r--r--res/xml/vpn_headers.xml2
-rw-r--r--src/de/blinkt/openvpn/LogWindow.java13
-rw-r--r--src/de/blinkt/openvpn/OpenVPN.java4
-rw-r--r--src/de/blinkt/openvpn/OpenVPNThread.java61
-rw-r--r--src/de/blinkt/openvpn/OpenVpnManagementThread.java140
-rw-r--r--src/de/blinkt/openvpn/OpenVpnService.java354
-rw-r--r--src/de/blinkt/openvpn/Settings_Authentication.java6
-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.java5
-rw-r--r--src/de/blinkt/openvpn/VPNProfileList.java71
-rw-r--r--src/de/blinkt/openvpn/VpnProfile.java109
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;
+ }
+
+
}