Browse Source

wpadebug: Add credential manager

Signed-hostap: Jouni Malinen <j@w1.fi>
Jouni Malinen 12 years ago
parent
commit
728b04314c

+ 8 - 0
wpadebug/AndroidManifest.xml

@@ -36,5 +36,13 @@
 		  android:label="WPA command list"
 		  android:parentActivityName="w1.fi.wpadebug.MainActivity">
 	</activity>
+	<activity android:name="w1.fi.wpadebug.WpaCredActivity"
+		  android:label="Credentials"
+		  android:parentActivityName="w1.fi.wpadebug.MainActivity">
+	</activity>
+	<activity android:name="w1.fi.wpadebug.WpaCredEditActivity"
+		  android:label="Credential"
+		  android:parentActivityName="w1.fi.wpadebug.WpaCredActivity">
+	</activity>
     </application>
 </manifest>

+ 117 - 0
wpadebug/res/layout/cred_edit.xml

@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    >
+	<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+		      android:layout_width="match_parent"
+		      android:layout_height="wrap_content"
+		      android:orientation="horizontal"
+		      >
+		<TextView
+		    android:layout_width="wrap_content"
+		    android:layout_height="wrap_content"
+		    android:text="Username"
+		    />
+		<EditText android:id="@+id/cred_edit_username"
+			  android:layout_weight="1"
+			  android:layout_width="0dp"
+			  android:layout_height="wrap_content"
+			  android:singleLine="true"
+			  android:lines="1"
+			  />
+	</LinearLayout>
+	<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+		      android:layout_width="match_parent"
+		      android:layout_height="wrap_content"
+		      android:orientation="horizontal"
+		      >
+		<TextView
+		    android:layout_width="wrap_content"
+		    android:layout_height="wrap_content"
+		    android:text="Realm"
+		    />
+		<EditText android:id="@+id/cred_edit_realm"
+			  android:layout_weight="1"
+			  android:layout_width="0dp"
+			  android:layout_height="wrap_content"
+			  android:singleLine="true"
+			  android:lines="1"
+			  />
+	</LinearLayout>
+	<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+		      android:layout_width="match_parent"
+		      android:layout_height="wrap_content"
+		      android:orientation="horizontal"
+		      >
+		<TextView
+		    android:layout_width="wrap_content"
+		    android:layout_height="wrap_content"
+		    android:text="Password"
+		    />
+		<EditText android:id="@+id/cred_edit_password"
+			  android:layout_weight="1"
+			  android:layout_width="0dp"
+			  android:layout_height="wrap_content"
+			  android:singleLine="true"
+			  android:lines="1"
+			  android:inputType="textPassword"
+			  />
+	</LinearLayout>
+	<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+		      android:layout_width="match_parent"
+		      android:layout_height="wrap_content"
+		      android:orientation="horizontal"
+		      >
+		<TextView
+		    android:layout_width="wrap_content"
+		    android:layout_height="wrap_content"
+		    android:text="Domain"
+		    />
+		<EditText android:id="@+id/cred_edit_domain"
+			  android:layout_weight="1"
+			  android:layout_width="0dp"
+			  android:layout_height="wrap_content"
+			  android:singleLine="true"
+			  android:lines="1"
+			  />
+	</LinearLayout>
+	<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+		      android:layout_width="match_parent"
+		      android:layout_height="wrap_content"
+		      android:orientation="horizontal"
+		      >
+		<TextView
+		    android:layout_width="wrap_content"
+		    android:layout_height="wrap_content"
+		    android:text="IMSI"
+		    />
+		<EditText android:id="@+id/cred_edit_imsi"
+			  android:layout_weight="1"
+			  android:layout_width="0dp"
+			  android:layout_height="wrap_content"
+			  android:singleLine="true"
+			  android:lines="1"
+			  android:hint="Used only with SIM/USIM testing"
+			  />
+	</LinearLayout>
+	<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+		      android:layout_width="match_parent"
+		      android:layout_height="wrap_content"
+		      android:orientation="horizontal"
+		      >
+		<Button
+		    android:layout_width="wrap_content"
+		    android:layout_height="wrap_content"
+		    android:text="Save"
+		    android:onClick="credSave"
+		    />
+		<Button
+		    android:layout_width="wrap_content"
+		    android:layout_height="wrap_content"
+		    android:text="Cancel"
+		    android:onClick="credCancel"
+		    />
+	</LinearLayout>
+</LinearLayout>

+ 12 - 0
wpadebug/res/layout/main.xml

@@ -50,6 +50,18 @@
 		    android:onClick="runWpaCommands"
 		    />
 	</LinearLayout>
+	<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+		      android:layout_width="match_parent"
+		      android:layout_height="wrap_content"
+		      android:orientation="horizontal"
+		      >
+		<Button
+		    android:layout_width="wrap_content"
+		    android:layout_height="wrap_content"
+		    android:text="Credentials"
+		    android:onClick="runWpaCredentials"
+		    />
+	</LinearLayout>
 	<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 		      android:layout_width="match_parent"
 		      android:layout_height="wrap_content"

+ 6 - 0
wpadebug/src/w1/fi/wpadebug/MainActivity.java

@@ -53,6 +53,12 @@ public class MainActivity extends Activity
 	startActivity(intent);
     }
 
+    public void runWpaCredentials(View view)
+    {
+	Intent intent = new Intent(this, WpaCredActivity.class);
+	startActivity(intent);
+    }
+
     public void runWpaCliCmd(View view)
     {
 	Intent intent = new Intent(this, DisplayMessageActivity.class);

+ 263 - 0
wpadebug/src/w1/fi/wpadebug/WpaCredActivity.java

@@ -0,0 +1,263 @@
+/*
+ * wpadebug - wpa_supplicant and Wi-Fi debugging app for Android
+ * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+package w1.fi.wpadebug;
+
+import java.util.ArrayList;
+import java.util.ListIterator;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.InputStream;
+import java.io.IOException;
+
+import android.app.ListActivity;
+import android.app.ActionBar;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.ListView;
+import android.widget.ArrayAdapter;
+import android.widget.Toast;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+
+class Credential
+{
+    int id;
+    String realm;
+    String username;
+    String domain;
+    String imsi;
+
+    public Credential(String entry)
+    {
+	String fields[] = entry.split("\t");
+	id = Integer.parseInt(fields[0]);
+	if (fields.length > 1)
+	    realm = fields[1];
+	else
+	    realm = "";
+	if (fields.length > 2)
+	    username = fields[2];
+	else
+	    username = "";
+	if (fields.length > 3 && fields[3].length() > 0)
+	    domain = fields[3];
+	else
+	    domain = null;
+	if (fields.length > 4 && fields[4].length() > 0)
+	    imsi = fields[4];
+	else
+	    imsi = null;
+    }
+
+    public Credential(int _id, String _username, String _realm, String _domain,
+		      String _imsi)
+    {
+	id = _id;
+	username = _username;
+	realm = _realm;
+	domain = _domain;
+	imsi = _imsi;
+    }
+
+
+    @Override
+    public String toString()
+    {
+	String res = id + " - " + username + "@" + realm;
+	if (domain != null)
+	    res += " (domain=" + domain + ")";
+	if (imsi != null)
+	    res += " (imsi=" + imsi + ")";
+	return res;
+    }
+}
+
+public class WpaCredActivity extends ListActivity
+{
+    private static final String TAG = "wpadebug";
+    static final int CRED_EDIT_REQ = 0;
+    private ArrayList<Credential> mList;
+    private ArrayAdapter<Credential> mListAdapter;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState)
+    {
+        super.onCreate(savedInstanceState);
+
+	mList = new ArrayList<Credential>();
+
+	String res = run("LIST_CREDS");
+	if (res == null) {
+	    Toast.makeText(this, "Could not get credential list",
+			   Toast.LENGTH_LONG).show();
+	    finish();
+	    return;
+	}
+
+	String creds[] = res.split("\n");
+	for (String cred: creds) {
+	    if (Character.isDigit(cred.charAt(0)))
+		mList.add(new Credential(cred));
+	}
+
+	mListAdapter = new ArrayAdapter<Credential>(this, android.R.layout.simple_list_item_1, mList);
+
+	setListAdapter(mListAdapter);
+	registerForContextMenu(getListView());
+
+	ActionBar abar = getActionBar();
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu)
+    {
+	menu.add(0, 0, 0, "Add credential");
+	return true;
+    }
+
+    protected void onActivityResult(int requestCode, int resultCode,
+				    Intent data)
+    {
+	if (requestCode == CRED_EDIT_REQ) {
+	    if (resultCode != RESULT_OK)
+		return;
+
+	    String username = data.getStringExtra("username");
+
+	    String realm = data.getStringExtra("realm");
+
+	    String domain = data.getStringExtra("domain");
+	    if (domain != null && domain.length() == 0)
+		domain = null;
+
+	    String imsi = data.getStringExtra("imsi");
+	    if (imsi != null && imsi.length() == 0)
+		imsi = null;
+
+	    String password = data.getStringExtra("password");
+	    if (password != null && password.length() == 0)
+		password = null;
+
+	    String res = run("ADD_CRED");
+	    if (res == null || res.contains("FAIL")) {
+		Toast.makeText(this, "Failed to add credential",
+			       Toast.LENGTH_LONG).show();
+		return;
+	    }
+
+	    int id = -1;
+	    String lines[] = res.split("\n");
+	    for (String line: lines) {
+		if (Character.isDigit(line.charAt(0))) {
+		    id = Integer.parseInt(line);
+		    break;
+		}
+	    }
+
+	    if (id < 0) {
+		Toast.makeText(this, "Failed to add credential (invalid id)",
+			       Toast.LENGTH_LONG).show();
+		return;
+	    }
+
+	    if (!set_cred_quoted(id, "username", username) ||
+		!set_cred_quoted(id, "realm", realm) ||
+		(password != null &&
+		 !set_cred_quoted(id, "password", password)) ||
+		(domain != null && !set_cred_quoted(id, "domain", domain)) ||
+		(imsi != null && !set_cred_quoted(id, "imsi", imsi))) {
+		run("REMOVE_CRED " + id);
+		Toast.makeText(this, "Failed to set credential field",
+			       Toast.LENGTH_LONG).show();
+		return;
+	    }
+
+	    mListAdapter.add(new Credential(id, username, realm, domain, imsi));
+	}
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item)
+    {
+	if (item.getTitle().equals("Add credential")) {
+	    startActivityForResult(new Intent(this, WpaCredEditActivity.class),
+				   CRED_EDIT_REQ);
+	    return true;
+	}
+	return false;
+    }
+
+    public void onCreateContextMenu(android.view.ContextMenu menu, View v,
+				    android.view.ContextMenu.ContextMenuInfo menuInfo)
+    {
+	menu.add(0, v.getId(), 0, "Delete");
+    }
+
+    @Override
+    public boolean onContextItemSelected(MenuItem item)
+    {
+	if (item.getTitle().equals("Delete")) {
+	    AdapterContextMenuInfo info =
+		(AdapterContextMenuInfo) item.getMenuInfo();
+	    Credential cred = (Credential) getListAdapter().getItem(info.position);
+	    String res = run("REMOVE_CRED " + cred.id);
+	    if (res == null || !res.contains("OK")) {
+		Toast.makeText(this, "Failed to delete credential",
+			       Toast.LENGTH_LONG).show();
+	    } else
+		mListAdapter.remove(cred);
+	    return true;
+	}
+	return super.onContextItemSelected(item);
+    }
+
+    @Override
+    protected void onListItemClick(ListView l, View v, int position, long id)
+    {
+	Credential item = (Credential) getListAdapter().getItem(position);
+	Toast.makeText(this, "Credential selected: " + item,
+		       Toast.LENGTH_SHORT).show();
+    }
+
+    private String run(String cmd)
+    {
+	try {
+	    Process proc = Runtime.getRuntime().exec(new String[]{"/system/bin/mksh-su", "-c", "wpa_cli " + cmd});
+	    BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
+	    StringBuffer output = new StringBuffer();
+	    int read;
+	    char[] buffer = new char[1024];
+	    while ((read = reader.read(buffer)) > 0)
+		output.append(buffer, 0, read);
+	    reader.close();
+	    proc.waitFor();
+	    return output.toString();
+	} catch (IOException e) {
+	    Toast.makeText(this, "Could not run command",
+			   Toast.LENGTH_LONG).show();
+	    return null;
+	} catch (InterruptedException e) {
+	    throw new RuntimeException(e);
+	}
+    }
+
+    private boolean set_cred(int id, String field, String value)
+    {
+	String res = run("SET_CRED " + id + " " + field + " " + value);
+	return res != null && res.contains("OK");
+    }
+
+    private boolean set_cred_quoted(int id, String field, String value)
+    {
+	String value2 = "'\"" + value + "\"'";
+	return set_cred(id, field, value2);
+    }
+}

+ 55 - 0
wpadebug/src/w1/fi/wpadebug/WpaCredEditActivity.java

@@ -0,0 +1,55 @@
+/*
+ * wpadebug - wpa_supplicant and Wi-Fi debugging app for Android
+ * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+package w1.fi.wpadebug;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.EditText;
+
+public class WpaCredEditActivity extends Activity
+{
+    @Override
+    public void onCreate(Bundle savedInstanceState)
+    {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.cred_edit);
+    }
+
+    public void credSave(View view)
+    {
+	Intent data = new Intent();
+	EditText edit;
+
+	edit = (EditText) findViewById(R.id.cred_edit_username);
+	data.putExtra("username", edit.getText().toString());
+
+	edit = (EditText) findViewById(R.id.cred_edit_realm);
+	data.putExtra("realm", edit.getText().toString());
+
+	edit = (EditText) findViewById(R.id.cred_edit_password);
+	data.putExtra("password", edit.getText().toString());
+
+	edit = (EditText) findViewById(R.id.cred_edit_domain);
+	data.putExtra("domain", edit.getText().toString());
+
+	edit = (EditText) findViewById(R.id.cred_edit_imsi);
+	data.putExtra("imsi", edit.getText().toString());
+
+	setResult(Activity.RESULT_OK, data);
+	finish();
+    }
+
+    public void credCancel(View view)
+    {
+	setResult(Activity.RESULT_CANCELED);
+	finish();
+    }
+}