1 /* 2 * wpadebug - wpa_supplicant and Wi-Fi debugging app for Android 3 * Copyright (c) 2013, Jouni Malinen <j@w1.fi> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 package w1.fi.wpadebug; 10 11 import java.util.ArrayList; 12 import java.util.ListIterator; 13 import java.io.BufferedReader; 14 import java.io.InputStreamReader; 15 import java.io.InputStream; 16 import java.io.IOException; 17 18 import android.app.ListActivity; 19 import android.app.ActionBar; 20 import android.content.Intent; 21 import android.os.Bundle; 22 import android.view.View; 23 import android.view.Menu; 24 import android.view.MenuItem; 25 import android.widget.ListView; 26 import android.widget.ArrayAdapter; 27 import android.widget.Toast; 28 import android.widget.AdapterView.AdapterContextMenuInfo; 29 30 class Credential 31 { 32 int id; 33 String realm; 34 String username; 35 String domain; 36 String imsi; 37 Credential(String entry)38 public Credential(String entry) 39 { 40 String fields[] = entry.split("\t"); 41 id = Integer.parseInt(fields[0]); 42 if (fields.length > 1) 43 realm = fields[1]; 44 else 45 realm = ""; 46 if (fields.length > 2) 47 username = fields[2]; 48 else 49 username = ""; 50 if (fields.length > 3 && fields[3].length() > 0) 51 domain = fields[3]; 52 else 53 domain = null; 54 if (fields.length > 4 && fields[4].length() > 0) 55 imsi = fields[4]; 56 else 57 imsi = null; 58 } 59 Credential(int _id, String _username, String _realm, String _domain, String _imsi)60 public Credential(int _id, String _username, String _realm, String _domain, 61 String _imsi) 62 { 63 id = _id; 64 username = _username; 65 realm = _realm; 66 domain = _domain; 67 imsi = _imsi; 68 } 69 70 71 @Override toString()72 public String toString() 73 { 74 String res = id + " - " + username + "@" + realm; 75 if (domain != null) 76 res += " (domain=" + domain + ")"; 77 if (imsi != null) 78 res += " (imsi=" + imsi + ")"; 79 return res; 80 } 81 } 82 83 public class WpaCredActivity extends ListActivity 84 { 85 private static final String TAG = "wpadebug"; 86 static final int CRED_EDIT_REQ = 0; 87 private ArrayList<Credential> mList; 88 private ArrayAdapter<Credential> mListAdapter; 89 90 @Override onCreate(Bundle savedInstanceState)91 public void onCreate(Bundle savedInstanceState) 92 { 93 super.onCreate(savedInstanceState); 94 95 mList = new ArrayList<Credential>(); 96 97 String res = run("LIST_CREDS"); 98 if (res == null) { 99 Toast.makeText(this, "Could not get credential list", 100 Toast.LENGTH_LONG).show(); 101 finish(); 102 return; 103 } 104 105 String creds[] = res.split("\n"); 106 for (String cred: creds) { 107 if (Character.isDigit(cred.charAt(0))) 108 mList.add(new Credential(cred)); 109 } 110 111 mListAdapter = new ArrayAdapter<Credential>(this, android.R.layout.simple_list_item_1, mList); 112 113 setListAdapter(mListAdapter); 114 registerForContextMenu(getListView()); 115 116 ActionBar abar = getActionBar(); 117 } 118 119 @Override onCreateOptionsMenu(Menu menu)120 public boolean onCreateOptionsMenu(Menu menu) 121 { 122 menu.add(0, 0, 0, "Add credential"); 123 return true; 124 } 125 onActivityResult(int requestCode, int resultCode, Intent data)126 protected void onActivityResult(int requestCode, int resultCode, 127 Intent data) 128 { 129 if (requestCode == CRED_EDIT_REQ) { 130 if (resultCode != RESULT_OK) 131 return; 132 133 String username = data.getStringExtra("username"); 134 135 String realm = data.getStringExtra("realm"); 136 137 String domain = data.getStringExtra("domain"); 138 if (domain != null && domain.length() == 0) 139 domain = null; 140 141 String imsi = data.getStringExtra("imsi"); 142 if (imsi != null && imsi.length() == 0) 143 imsi = null; 144 145 String password = data.getStringExtra("password"); 146 if (password != null && password.length() == 0) 147 password = null; 148 149 String res = run("ADD_CRED"); 150 if (res == null || res.contains("FAIL")) { 151 Toast.makeText(this, "Failed to add credential", 152 Toast.LENGTH_LONG).show(); 153 return; 154 } 155 156 int id = -1; 157 String lines[] = res.split("\n"); 158 for (String line: lines) { 159 if (Character.isDigit(line.charAt(0))) { 160 id = Integer.parseInt(line); 161 break; 162 } 163 } 164 165 if (id < 0) { 166 Toast.makeText(this, "Failed to add credential (invalid id)", 167 Toast.LENGTH_LONG).show(); 168 return; 169 } 170 171 if (!set_cred_quoted(id, "username", username) || 172 !set_cred_quoted(id, "realm", realm) || 173 (password != null && 174 !set_cred_quoted(id, "password", password)) || 175 (domain != null && !set_cred_quoted(id, "domain", domain)) || 176 (imsi != null && !set_cred_quoted(id, "imsi", imsi))) { 177 run("REMOVE_CRED " + id); 178 Toast.makeText(this, "Failed to set credential field", 179 Toast.LENGTH_LONG).show(); 180 return; 181 } 182 183 mListAdapter.add(new Credential(id, username, realm, domain, imsi)); 184 } 185 } 186 187 @Override onOptionsItemSelected(MenuItem item)188 public boolean onOptionsItemSelected(MenuItem item) 189 { 190 if (item.getTitle().equals("Add credential")) { 191 startActivityForResult(new Intent(this, WpaCredEditActivity.class), 192 CRED_EDIT_REQ); 193 return true; 194 } 195 return false; 196 } 197 onCreateContextMenu(android.view.ContextMenu menu, View v, android.view.ContextMenu.ContextMenuInfo menuInfo)198 public void onCreateContextMenu(android.view.ContextMenu menu, View v, 199 android.view.ContextMenu.ContextMenuInfo menuInfo) 200 { 201 menu.add(0, v.getId(), 0, "Delete"); 202 } 203 204 @Override onContextItemSelected(MenuItem item)205 public boolean onContextItemSelected(MenuItem item) 206 { 207 if (item.getTitle().equals("Delete")) { 208 AdapterContextMenuInfo info = 209 (AdapterContextMenuInfo) item.getMenuInfo(); 210 Credential cred = (Credential) getListAdapter().getItem(info.position); 211 String res = run("REMOVE_CRED " + cred.id); 212 if (res == null || !res.contains("OK")) { 213 Toast.makeText(this, "Failed to delete credential", 214 Toast.LENGTH_LONG).show(); 215 } else 216 mListAdapter.remove(cred); 217 return true; 218 } 219 return super.onContextItemSelected(item); 220 } 221 222 @Override onListItemClick(ListView l, View v, int position, long id)223 protected void onListItemClick(ListView l, View v, int position, long id) 224 { 225 Credential item = (Credential) getListAdapter().getItem(position); 226 Toast.makeText(this, "Credential selected: " + item, 227 Toast.LENGTH_SHORT).show(); 228 } 229 run(String cmd)230 private String run(String cmd) 231 { 232 try { 233 Process proc = Runtime.getRuntime().exec(new String[]{"/system/bin/mksh-su", "-c", "wpa_cli " + cmd}); 234 BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream())); 235 StringBuffer output = new StringBuffer(); 236 int read; 237 char[] buffer = new char[1024]; 238 while ((read = reader.read(buffer)) > 0) 239 output.append(buffer, 0, read); 240 reader.close(); 241 proc.waitFor(); 242 return output.toString(); 243 } catch (IOException e) { 244 Toast.makeText(this, "Could not run command", 245 Toast.LENGTH_LONG).show(); 246 return null; 247 } catch (InterruptedException e) { 248 throw new RuntimeException(e); 249 } 250 } 251 set_cred(int id, String field, String value)252 private boolean set_cred(int id, String field, String value) 253 { 254 String res = run("SET_CRED " + id + " " + field + " " + value); 255 return res != null && res.contains("OK"); 256 } 257 set_cred_quoted(int id, String field, String value)258 private boolean set_cred_quoted(int id, String field, String value) 259 { 260 String value2 = "'\"" + value + "\"'"; 261 return set_cred(id, field, value2); 262 } 263 } 264