diff options
Diffstat (limited to 'src')
| -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 | 
10 files changed, 498 insertions, 268 deletions
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; +	} + +	  }  | 
