wpadebug: Add credential manager
Signed-hostap: Jouni Malinen <j@w1.fi>
This commit is contained in:
parent
d7232a8da6
commit
728b04314c
6 changed files with 461 additions and 0 deletions
|
@ -36,5 +36,13 @@
|
||||||
android:label="WPA command list"
|
android:label="WPA command list"
|
||||||
android:parentActivityName="w1.fi.wpadebug.MainActivity">
|
android:parentActivityName="w1.fi.wpadebug.MainActivity">
|
||||||
</activity>
|
</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>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
117
wpadebug/res/layout/cred_edit.xml
Normal file
117
wpadebug/res/layout/cred_edit.xml
Normal file
|
@ -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>
|
|
@ -50,6 +50,18 @@
|
||||||
android:onClick="runWpaCommands"
|
android:onClick="runWpaCommands"
|
||||||
/>
|
/>
|
||||||
</LinearLayout>
|
</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"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|
|
@ -53,6 +53,12 @@ public class MainActivity extends Activity
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void runWpaCredentials(View view)
|
||||||
|
{
|
||||||
|
Intent intent = new Intent(this, WpaCredActivity.class);
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
|
||||||
public void runWpaCliCmd(View view)
|
public void runWpaCliCmd(View view)
|
||||||
{
|
{
|
||||||
Intent intent = new Intent(this, DisplayMessageActivity.class);
|
Intent intent = new Intent(this, DisplayMessageActivity.class);
|
||||||
|
|
263
wpadebug/src/w1/fi/wpadebug/WpaCredActivity.java
Normal file
263
wpadebug/src/w1/fi/wpadebug/WpaCredActivity.java
Normal file
|
@ -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
wpadebug/src/w1/fi/wpadebug/WpaCredEditActivity.java
Normal file
55
wpadebug/src/w1/fi/wpadebug/WpaCredEditActivity.java
Normal file
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue