[[project @ 6] koushd**20090106024755 Ignore-this: f034285ba39890e1ab4fbc77a9c25f92 subversion sucks on package renames. ] adddir ./Superuser/src/com/koushikdutta/superuser addfile ./Superuser/src/com/koushikdutta/superuser/R.java addfile ./Superuser/src/com/koushikdutta/superuser/SuperuserActivity.java addfile ./Superuser/src/com/koushikdutta/superuser/SuperuserRequestActivity.java hunk ./Superuser/src/com/koushikdutta/superuser/R.java 1 +/* AUTO-GENERATED FILE. DO NOT MODIFY. + * + * This class was automatically generated by the + * aapt tool from the resource data it found. It + * should not be modified by hand. + */ + +package com.koushikdutta.superuser; + +public final class R { + public static final class attr { + } + public static final class drawable { + public static final int icon=0x7f020000; + } + public static final class id { + public static final int AlwaysButton=0x7f060007; + public static final int EmptyWhitelistText=0x7f060001; + public static final int LinearLayout01=0x7f060000; + public static final int LinearLayout02=0x7f060008; + public static final int NoButton=0x7f060006; + public static final int ScrollView01=0x7f060002; + public static final int WhitelistItemText=0x7f060009; + public static final int WhitelistPackageText=0x7f06000a; + public static final int YesButton=0x7f060005; + public static final int requestorprocesses=0x7f060004; + public static final int requestoruid=0x7f060003; + } + public static final class layout { + public static final int main=0x7f030000; + public static final int superuserrequest=0x7f030001; + public static final int whitelistitem=0x7f030002; + } + public static final class raw { + public static final int su=0x7f040000; + } + public static final class string { + public static final int app_name=0x7f050000; + public static final int superuser_permissions_description=0x7f050001; + public static final int superuser_permissions_name=0x7f050002; + } +} hunk ./Superuser/src/com/koushikdutta/superuser/SuperuserActivity.java 1 - +package com.koushikdutta.superuser; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import android.app.ListActivity; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.CursorAdapter; +import android.widget.ListView; +import android.widget.TextView; +import android.widget.Toast; +import android.widget.AdapterView.OnItemLongClickListener; + +public class SuperuserActivity extends ListActivity +{ + LayoutInflater mInflater; + ListView mListView; + WhitelistAdapter mAdapter; + TextView mEmptyText; + SQLiteDatabase mDatabase; + Cursor mCursor; + + protected static class DatabaseHelper extends SQLiteOpenHelper + { + public DatabaseHelper(Context context) + { + super(context, "superuser.sqlite", null, 1); + } + + @Override + public void onCreate(SQLiteDatabase db) + { + String ddlWhitelist = "create table whitelist (_id integer primary key, name text, count integer);"; + db.execSQL(ddlWhitelist); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) + { + } + } + + public class WhitelistAdapter extends CursorAdapter + { + public WhitelistAdapter(Context context, Cursor c) + { + super(context, c); + } + + @Override + public void bindView(View view, Context context, Cursor cursor) + { + TextView whitelistPackageText = (TextView) view.findViewById(R.id.WhitelistPackageText); + int uid = cursor.getInt(0); + String packageName = cursor.getString(1); + whitelistPackageText.setText(packageName); + TextView whitelistItemText = (TextView) view.findViewById(R.id.WhitelistItemText); + whitelistItemText.setText("User ID: " + new Integer(uid).toString()); + } + + @Override + public View newView(Context context, Cursor cursor, ViewGroup parent) + { + View view = mInflater.inflate(R.layout.whitelistitem, null); + bindView(view, context, cursor); + return view; + } + } + + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + + prepareSu(); + + mEmptyText = (TextView) findViewById(R.id.EmptyWhitelistText); + mListView = (ListView) findViewById(android.R.id.list); + mInflater = getLayoutInflater(); + + DatabaseHelper hlp = new DatabaseHelper(this); + mDatabase = hlp.getWritableDatabase(); + + refreshCursor(); + + Toast toast = Toast.makeText(this, "Click and hold an application to to remove it from the whitelist", Toast.LENGTH_LONG); + toast.show(); + + mListView.setOnItemLongClickListener(new OnItemLongClickListener() + { + @Override + public boolean onItemLongClick(AdapterView parent, View view, int position, long id) + { + mCursor.moveToPosition(position); + int uid = mCursor.getInt(0); + String command = "delete from whitelist where _id=" + uid + ";"; + mDatabase.execSQL(command); + refreshCursor(); + return true; + } + }); + + updateEmptyText(); + } + + private void refreshCursor() + { + mCursor = mDatabase.query(false, "whitelist", new String[] { "_id", "name" }, null, null, null, null, null, null); + mAdapter = new WhitelistAdapter(this, mCursor); + setListAdapter(mAdapter); + updateEmptyText(); + } + + private void updateEmptyText() + { + mEmptyText.setVisibility(mCursor.getCount() != 0 ? View.GONE : View.VISIBLE); + } + + public static int getUidForPackage(String packageName) throws Exception + { + // parse the uid given a package name (which should be visible in ps) + Process p = Runtime.getRuntime().exec("ps"); + InputStream reader = p.getInputStream(); + Thread.sleep(200); + byte[] buff = new byte[10000]; + int read = reader.read(buff, 0, buff.length); + String str = new String(buff); + String pattern = String.format("app_(\\d+).*?%s", packageName); + Pattern regex = Pattern.compile(pattern); + Matcher match = regex.matcher(str); + if (match.find()) + return Integer.parseInt(match.group(1)) + 10000; + + throw new Exception("Unable to determine uid for package"); + } + + // Superuser upgrade path + private void prepareSu() + { + try + { + File su = new File("/system/bin/su"); + if (!su.exists()) + { + Toast toast = Toast.makeText(this, "Unable to find /system/bin/su.", Toast.LENGTH_LONG); + toast.show(); + return; + } + + InputStream suStream = getResources().openRawResource(R.raw.su); + + if (su.length() == suStream.available()) + { + suStream.close(); + return; + } + + File superuser = new File("/system/bin/superuser"); + + if (superuser.exists()) + { + // return device to original state + Process process = Runtime.getRuntime().exec("superuser"); + DataOutputStream os = new DataOutputStream(process.getOutputStream()); + + os.writeBytes("mount -oremount,rw /dev/block/mtdblock3 /system\n"); + os.writeBytes("busybox cp /system/bin/superuser /system/bin/su\n"); + os.writeBytes("busybox chown 0:0 /system/bin/su\n"); + os.writeBytes("chmod 4755 /system/bin/su\n"); + os.writeBytes("rm /system/bin/superuser\n"); + os.writeBytes("exit\n"); + os.flush(); + } + + byte[] bytes = new byte[suStream.available()]; + DataInputStream dis = new DataInputStream(suStream); + dis.readFully(bytes); + FileOutputStream suOutStream = new FileOutputStream("/data/data/com.koushikdutta.superuser/su"); + suOutStream.write(bytes); + suOutStream.close(); + + Process process = Runtime.getRuntime().exec("su"); + DataOutputStream os = new DataOutputStream(process.getOutputStream()); + os.writeBytes("mount -oremount,rw /dev/block/mtdblock3 /system\n"); + os.writeBytes("busybox cp /data/data/com.koushikdutta.superuser/su /system/bin/su\n"); + os.writeBytes("busybox chown 0:0 /system/bin/su\n"); + os.writeBytes("chmod 4755 /system/bin/su\n"); + os.writeBytes("exit\n"); + os.flush(); + } + catch (Exception e) + { + Toast toast = Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG); + toast.show(); + } + } +} hunk ./Superuser/src/com/koushikdutta/superuser/SuperuserRequestActivity.java 1 +package com.koushikdutta.superuser; + +import java.io.InputStream; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import android.app.Activity; +import android.content.Intent; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.os.Bundle; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; + +public class SuperuserRequestActivity extends Activity +{ + Button mYesButton; + Button mNoButton; + Button mAlwaysButton; + Intent mIntent; + SQLiteDatabase mDatabase; + int mUid; + int mPid; + String mName; + + @Override + protected void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setContentView(R.layout.superuserrequest); + + Button yesButton = (Button) findViewById(R.id.YesButton); + Button noButton = (Button) findViewById(R.id.NoButton); + Button alwaysButton = (Button) findViewById(R.id.AlwaysButton); + mIntent = getIntent(); + + mUid = mIntent.getIntExtra("uid", -1); + mPid = mIntent.getIntExtra("pid", -1); + + if (mUid == -1 || mPid == -1) + { + Toast toast = Toast.makeText(this, "This intent requires two int parameters: uid pid", Toast.LENGTH_LONG); + toast.show(); + mIntent.putExtra("superuserresult", false); + setResult(RESULT_CANCELED, mIntent); + finish(); + return; + } + + try + { + if (mUid >= 10000) + { + Process p = Runtime.getRuntime().exec("ps"); + InputStream reader = p.getInputStream(); + Thread.sleep(200); + byte[] buff = new byte[10000]; + int read = reader.read(buff, 0, buff.length); + String str = new String(buff); + int id = mUid - 10000; + String pattern = String.format("app_%d+(.*?)\n", id); + Pattern regex = Pattern.compile(pattern); + Matcher match = regex.matcher(str); + mName = ""; + while (match.find()) + { + String[] strings = match.group(1).split(" "); + mName += strings[strings.length -1] + "\n"; + } + + TextView nameText = (TextView) findViewById(R.id.requestorprocesses); + mName = mName.replace("'",""); + nameText.setText(mName); + } + } + catch (Exception e) + { + Toast toast = Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG); + toast.show(); + finish(); + return; + } + + TextView packageText = (TextView) findViewById(R.id.requestoruid); + packageText.setText("User ID: " + mUid); + + // check whitelist + mDatabase = new SuperuserActivity.DatabaseHelper(this).getWritableDatabase(); + Cursor c = mDatabase.query("whitelist", new String[] { "_id", "name" }, "_id = " + mUid, null, null, null, null); + + yesButton.setOnClickListener(new OnClickListener() + { + @Override + public void onClick(View v) + { + String delete = String.format("delete from whitelist where _id=%d;", mUid); + mDatabase.execSQL(delete); + String whitelistCommand = String.format("insert into whitelist values (%d, '%s', %d);", mUid, mName, 1); + mDatabase.execSQL(whitelistCommand); + finish(); + } + }); + + noButton.setOnClickListener(new OnClickListener() + { + @Override + public void onClick(View v) + { + String delete = String.format("delete from whitelist where _id=%d;", mUid); + mDatabase.execSQL(delete); + String whitelistCommand = String.format("insert into whitelist values (%d, '%s', %d);", mUid, mName, -1); + mDatabase.execSQL(whitelistCommand); + finish(); + } + }); + + alwaysButton.setOnClickListener(new OnClickListener() + { + @Override + public void onClick(View v) + { + String delete = String.format("delete from whitelist where _id=%d;", mUid); + mDatabase.execSQL(delete); + String whitelistCommand = String.format("insert into whitelist values (%d, '%s', %d);", mUid, mName, 10000); + mDatabase.execSQL(whitelistCommand); + finish(); + } + }); + } +}