[[project @ 2] koushd**20090106022154 Ignore-this: 74934f2b69b243a765b06e0f24275853 Initial commit. ] adddir ./Superuser addfile ./Superuser/.classpath addfile ./Superuser/.project addfile ./Superuser/AndroidManifest.xml adddir ./Superuser/assets adddir ./Superuser/res adddir ./Superuser/res/drawable addfile ./Superuser/res/drawable/icon.png adddir ./Superuser/res/layout addfile ./Superuser/res/layout/main.xml addfile ./Superuser/res/layout/superuserrequest.xml addfile ./Superuser/res/layout/whitelistitem.xml adddir ./Superuser/res/raw addfile ./Superuser/res/raw/su adddir ./Superuser/res/values addfile ./Superuser/res/values/strings.xml adddir ./Superuser/src adddir ./Superuser/src/koushikdutta adddir ./Superuser/src/koushikdutta/superuser addfile ./Superuser/src/koushikdutta/superuser/R.java addfile ./Superuser/src/koushikdutta/superuser/SuperuserActivity.java addfile ./Superuser/src/koushikdutta/superuser/SuperuserRequestActivity.java adddir ./su addfile ./su/Android.mk addfile ./su/MODULE_LICENSE_APACHE2 addfile ./su/su.c hunk ./Superuser/.classpath 1 + + + + + + hunk ./Superuser/.project 1 + + + Superuser + + + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + hunk ./Superuser/AndroidManifest.xml 1 - + + + + + + + + + + + + + + + + + binary ./Superuser/res/drawable/icon.png oldhex * newhex *89504e470d0a1a0a0000000d49484452000000300000003008060000005702f987000000046741 *4d410000b18f0bfc61050000001874455874536f667477617265005061696e742e4e4554207633 *2e3336a9e7e225000001c4494441546843ed5ac10dc2300c2ccbc0002cc02ef063033e88372bc0 *0a5d8229e832604b45042be462a781425da94228b6e3d817e71c9835159ef9be3991d945607add *1d9aeedd54243fa7b173307e25f94d05d7f24c92431dbdb7fe7debf8c31ac9ed0279d6dbe5cd54 *418a265f0a672e681a92bf089d25d2a9361e89e6114da6cd18b257341e89e62a65d092b1220791 *b2369a8e7f1451cd3845732b36e3cfe1bf150b981cfe61c6348850c9f2693a40fd4f664ce59056 *d8f14fa7b1366859f214d9555fab99afa4de17fe43b247202f373cd38994fd6d96c3522872d03c *48daa73f6d19f2053c697569c6cc19e0d395f1997a43e7782fa0fd22f1cf3a680e6e92867f2c6c *9274e40246c5ff6137a565acc3873db0a8eda62c2776ed0568fb5fc95861c6aa2dc0f14fb717d5 *a29b63585b4dfe11ff3fc7ff551d5b0e0acc3211fe0fabc9d8eabfea34fd28fefbcd89b889e4ff *88ff9c44cb89f84f5b028fd0b9521669d5b797588155ab03a57ad35e00c2b316ff72c3f3773407 *ac6aa63d62e43f7eff6f8a764c29c2ff2777ff5907db392972fc8f80ffcb6ae2f8cf81ee20328e *7fc77f2190b4dd54e456fbabf59f7fff0a1b1c78d14af2dcc0843afc8f147f6404eebc93fef738 *45f7430000000049454e44ae426082 hunk ./Superuser/res/layout/main.xml 1 + + + + + + + + hunk ./Superuser/res/layout/superuserrequest.xml 1 - + + + + + + + + + + + + + + + hunk ./Superuser/res/layout/whitelistitem.xml 1 + + + + + + + + + + + binary ./Superuser/res/raw/su oldhex * newhex *7f454c460101010000000000000000000200280001000000008700003400000020120000020000 *0434002000060028001500140001000070c00b0000c08b0000c08b000020000000200000000400 *00000400000006000000340000003480000034800000c0000000c0000000050000000400000003 *000000f4000000f4800000f4800000130000001300000004000000010000000100000000000000 *0080000000800000e00b0000e00b00000500000000100000010000000010000000900000009000 *006401000068010000060000000010000002000000201000002090000020900000e8000000e800 *000006000000040000002f73797374656d2f62696e2f6c696e6b6572000011000000220000000a *0000001a0000001d00000019000000080000001800000015000000000000000600000021000000 *17000000140000000d0000001c0000001f0000000c000000200000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000000000000000000900 *00000100000003000000000000000000000007000000040000000000000000000000120000000f *0000000b0000001000000000000000050000000e0000001b000000110000000200000016000000 *130000001e00000000000000000000000000000000000000b10000002486000020000000120000 *005c0000003086000074010000120000001f010000e08b0000000000001000f1ff7b0000000000 *00000400000011000000c7000000000000001800000012000000a90000003c8600000c00000012 *0000005a01000068910000000000001000f1ff0c010000488600005000000012000000eb000000 *54860000cc00000012000000f20000006086000038000000120000004b01000064910000000000 *001000f1ff11010000c08b0000000000001000f1ff6a0000006c860000b8000000120000002b00 *0000788600001c00000012000000ba000000848600001c00000012000000590100006891000000 *0000001000f1fff8000000908600000000000012000000c200000000000000fc00000011000000 *060100009c86000024000000120000003f01000064910000000000001000f1ffde000000a88600 *0000000000120000006501000068910000000000001000f1ff47000000b48600004c0000001200 *000037000000c08600000c00000012000000e6000000cc86000000000000120000003801000064 *910000000000001000f1ff2601000068910000000000001000f1ffa4000000d886000010000000 *120000008d0000000000000018000000120000006d01000000000800000000001000f1ff2b0100 *0064910000000000001000f1ffff000000e486000000000000120000004f000000f08600000c02 *000012000000006c696273716c6974652e736f006c6962632e736f006c6962737464632b2b2e73 *6f006c69626d2e736f005f5f6c6962635f696e69740073716c697465335f6f70656e5f76320073 *7072696e74660073716c697465335f657865630073716c697465335f636c6f7365005f5f737461 *636b5f63686b5f6661696c005f5f737461636b5f63686b5f6775617264005f5f61656162695f75 *6e77696e645f6370705f7072310061746f69005f5f6572726e6f007374726572726f7200667072 *696e7466005f5f7346005f5f61656162695f756e77696e645f6370705f70723000676574707069 *6400737461740073797374656d00736c6565700073657467696400736574756964006578656376 *0070757473005f5f65786964785f7374617274005f5f65786964785f656e64005f5f646174615f *7374617274005f6564617461005f5f6273735f7374617274005f5f6273735f73746172745f5f00 *5f5f6273735f656e645f5f005f5f656e645f5f005f737461636b005c9100001504000060910000 *15120000149100001601000018910000160200001c910000160600002091000016080000249100 *001609000028910000160a00002c910000160d000030910000160e000034910000160f00003891 *0000161100003c910000161300004091000016150000449100001617000048910000161800004c *9100001619000050910000161c00005491000016200000589100001621000004e02de504e09fe5 *0ee08fe008f0bee5e80a000000c68fe200ca8ce2e8fabce500c68fe200ca8ce2e0fabce500c68f *e200ca8ce2d8fabce500c68fe200ca8ce2d0fabce500c68fe200ca8ce2c8fabce500c68fe200ca *8ce2c0fabce500c68fe200ca8ce2b8fabce500c68fe200ca8ce2b0fabce500c68fe200ca8ce2a8 *fabce500c68fe200ca8ce2a0fabce500c68fe200ca8ce298fabce500c68fe200ca8ce290fabce5 *00c68fe200ca8ce288fabce500c68fe200ca8ce280fabce500c68fe200ca8ce278fabce500c68f *e200ca8ce270fabce500c68fe200ca8ce268fabce500c68fe200ca8ce260fabce5000000000d00 *a0e10010a0e304208fe204308fe2d8ffffeab20000ea0090000008900000109000001890000000 *00a0e10000a0e170b5214d214c2249ad44224d224869447d442a592818136802220b6006a90023 *fff7b6ef061c00281cd11c4b1c4807ace9182a58201cfff7a6ef1a49069804966a1803ab05ae21 *1c03900096fff7b8ef069b002801d0181c05e0181cfff750ef049803e00698fff74cef0020074e *ac59074d6d442a6823689a4201d0fff75eef8421c9008d4470bde0fbffff540000001c040000c4 *090000e8f8ffff28f9ffff5c000000d1f6ffff70b51c4e141c1c4d1c4a7e44ad44051cb0581b49 *036869440b60a068fff770ef6860021c2368012808dc164c16491a1c6c447118201cfff752ef05 *e0134803ac3118201cfff74aef28680c4d0023211c00220093fff760ef094a745900206a441668 *23689e4201d0fff714ef812109018d4470bd22090000f0f7ffff540000000c0800000c04000058 *f9ffff80f9ffff30b581b0051cfff7e6ee0068fff7d6ee084c0949094a7c44031c6058a418211c *2a1ca830fff7faeefff7d4ee006801b0404230bd8608000058000000b0f9fffff0b5414d414c42 *4ead44424d00af78607d4428596a4639600368f351ba60fff7f0ee3d4a3d49f860bc186918fa68 *201cfff7ecee391c201c1031fff7f4ee3848bb6a2e183360fff71fff00281dd135493c1c7c3469 *183268201cfb68fff7d6ee201cfff7a4ee002801d02f4834e000240120fff7a2eefff707ff0028 *05dc00282ed101340a2c2bd0f2e70020fff7acee002825d1fff7d2ee002821d17c686946a30012 *33de08f200204e891aa300aa1958500a603c688d460a1c0434012002e040cc013016607b680432 *9842f8db18482818fff790ee15482818fff771ff04e0144c2819fff75cee0120084eb968aa598d *460749cd5913689d4201d0fff762ee0d4cbd46a544f0bd7cfaffff540000007c0500004c080000 *7c040000c4f9ffff5c000000d0f9ffff68faffff90faffff84faffff6cfaffff8405000000c09f *e51cff2fe1a98800002f646174612f646174612f6b6f757368696b64757474612e737570657275 *7365722f6461746162617365732f7375706572757365722e73716c6974650000000073656c6563 *74202a2066726f6d2077686974656c697374207768657265205f69643d2564206c696d69742031 *3b00000064656c6574652066726f6d2077686974656c697374207768657265205f69643d272573 *273b0000007570646174652077686974656c6973742073657420636f756e743d25642077686572 *65205f69643d272573273b00000073753a2025732e204572726f723a25730a0000002f70726f63 *2f256400000000616d207374617274202d6120616e64726f69642e696e74656e742e616374696f *6e2e4d41494e202d6e206b6f757368696b64757474612e7375706572757365722f6b6f75736869 *6b64757474612e7375706572757365722e53757065727573657252657175657374416374697669 *7479202d2d656920756964202564202d2d656920706964202564203e202f6465762f6e756c6c00 *000000616d2e0073753a207065726d697373696f6e2064656e6965640000002f73797374656d2f *62696e2f7368000087b20181b0b0aa010000000083b20181b0b0aa0300000000b2970181b0ab01 *e00000000070fbff7fd8ffff7f10fcff7fdcffff7f98fcff7fb0a90080d0fcff7fd8ffff7f0000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *00ffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000010000000100 *0000010000000e0000000100000016000000010000002300000020000000009000002100000008 *00000019000000089000001b000000080000001a000000109000001c0000000800000004000000 *0881000005000000fc83000006000000dc8100000a000000740100000b00000010000000150000 *000000000003000000089100000200000090000000140000001100000017000000808500001100 *000070850000120000001000000013000000080000000000000000000000000000000000000000 *000000000000000000000000000000000000000000000000000000000000002090000000000000 *000000001086000010860000108600001086000010860000108600001086000010860000108600 *001086000010860000108600001086000010860000108600001086000010860000108600000000 *000000000000410f0000006165616269000105000000002e726f64617461002e73687374727461 *62002e41524d2e6578746162002e64796e616d6963002e68617368002e64796e73796d002e696e *74657270002e64796e737472002e41524d2e61747472696275746573002e63746f7273002e6273 *73002e72656c2e706c74002e72656c2e676f74002e74657874002e41524d2e6578696478002e66 *696e695f6172726179002e696e69745f6172726179002e707265696e69745f6172726179000000 *000000000000000000000000000000000000000000000000000000000000000000000000000000 *350000000100000002000000f4800000f400000013000000000000000000000001000000000000 *002700000005000000020000000881000008010000d40000000300000000000000040000000400 *00002d0000000b00000002000000dc810000dc0100002002000004000000000000000400000010 *0000003d0000000300000002000000fc830000fc03000074010000000000000000000001000000 *000000006a00000009000000020000007085000070050000100000000300000011000000040000 *000800000061000000090000000200000080850000800500009000000003000000070000000400 *0000080000006500000001000000060000001086000010060000ec000000000000000000000004 *000000040000007300000001000000060000000087000000070000f00200000000000000000000 *1000000000000000010000000100000032000000f0890000f0090000ac01000000000000000000 *0004000000010000001300000001000000020000009c8b00009c0b000024000000000000000000 *00000400000000000000790000000100007082000000c08b0000c00b0000200000000800000000 *00000004000000000000009c000000100000000300000000900000001000000800000000000000 *000000000100000000000000900000000e00000003000000089000000810000008000000000000 *00000000000100000000000000840000000f000000030000001090000010100000080000000000 *000000000000010000000000000055000000010000000300000018900000181000000800000000 *0000000000000001000000000000001e00000006000000030000002090000020100000e8000000 *040000000000000004000000080000006e000000010000000300000008910000081100005c0000 *00000000000000000004000000040000005c000000080000000300000064910000641100000400 *000000000000000000000400000000000000450000000300007000000000000000006411000010 *000000000000000000000001000000000000000900000003000000000000000000000074110000 *ab00000000000000000000000100000000000000 hunk ./Superuser/res/values/strings.xml 1 + + + + Superuser +Superuser permissions grants the application full (root) access to all the phone's capabilties. +Superuser Permissions + hunk ./Superuser/src/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 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/koushikdutta/superuser/SuperuserActivity.java 1 - +package 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"); + } + + private static void remountFileSystem(String suCommand) throws Exception + { + // this function remounts the file system for permission changes with either su or superuser, depending on whether + // superuser is set up already or not + String command = String.format("echo \"mount -oremount,rw /dev/block/mtdblock3 /system\" | %s\nexit\n", suCommand); + Process p = Runtime.getRuntime().exec("sh"); + OutputStream writer = p.getOutputStream(); + writer.write(command.getBytes("ASCII")); + Thread.sleep(500); + } + + 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/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/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/koushikdutta/superuser/SuperuserRequestActivity.java 1 +package 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(); + } + }); + } +} hunk ./su/Android.mk 1 +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= su.c + +LOCAL_MODULE:= su + +LOCAL_STATIC_LIBRARIES := libc + +LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) +LOCAL_MODULE_TAGS := debug tests + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/../../../external/sqlite/dist \ + $(LOCAL_PATH)/../../../external/sqlite/android + +LOCAL_SHARED_LIBRARIES := \ + libsqlite + +include $(BUILD_EXECUTABLE) hunk ./su/su.c 1 +/* +** +** Copyright 2008, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#define DBPATH "/data/data/koushikdutta.superuser/databases/superuser.sqlite" + +static int g_puid; + +static void printRow(int argc, char** argv, char** azColName) +{ + int i; + for (i = 0; i < argc; i++) + { + printf("%s: %s\n", azColName[i], argv[i]); + } +} + +typedef struct whitelistCallInfo whitelistCallInfo; +struct whitelistCallInfo +{ + sqlite3* db; + int count; +}; + +static int whitelistCallback(void *data, int argc, char **argv, char **azColName) +{ + whitelistCallInfo* callInfo = (whitelistCallInfo*)data; + // note the count + int count = atoi(argv[2]); + callInfo->count = count; + // remove whitelist entries that are expired + if (count - 1 <= 0) + { + char remove[1024]; + sprintf(remove, "delete from whitelist where _id='%s';", argv[0]); + sqlite3_exec(callInfo->db, remove, NULL, NULL, NULL); + return 0; + } + + char update[1024]; + sprintf(update, "update whitelist set count=%d where _id='%s';", count, argv[0]); + sqlite3_exec(callInfo->db, update, NULL, NULL, NULL); + return 0; +} + +static int checkWhitelist() +{ + sqlite3 *db; + int rc = sqlite3_open_v2(DBPATH, &db, SQLITE_OPEN_READWRITE, NULL); + if (!rc) + { + char *errorMessage; + char query[1024]; + sprintf(query, "select * from whitelist where _id=%d limit 1;", g_puid); + struct whitelistCallInfo callInfo; + callInfo.count = 0; + callInfo.db = db; + rc = sqlite3_exec(db, query, whitelistCallback, &callInfo, &errorMessage); + if (rc != SQLITE_OK) + { + sqlite3_close(db); + return 0; + } + sqlite3_close(db); + return callInfo.count; + } + sqlite3_close(db); + return 0; +} + +static int executionFailure(char *context) +{ + fprintf(stderr, "su: %s. Error:%s\n", context, strerror(errno)); + return -errno; +} + +static int permissionDenied() +{ + // the superuser activity couldn't be started + printf("su: permission denied\n"); + return 1; +} + +int main(int argc, char **argv) +{ + struct stat stats; + struct passwd *pw; + int uid = 0; + int gid = 0; + + int ppid = getppid(); + char szppid[256]; + sprintf(szppid, "/proc/%d", ppid); + stat(szppid, &stats); + g_puid = stats.st_uid; + + // lets make sure the caller is allowed to execute this + if (!checkWhitelist()) + { + char sysCmd[1024]; + sprintf(sysCmd, "am start -a android.intent.action.MAIN -n koushikdutta.superuser/koushikdutta.superuser.SuperuserRequestActivity --ei uid %d --ei pid %d > /dev/null", g_puid, ppid); + if (system(sysCmd)) + return executionFailure("am."); + + int found = 0; + int i; + for (i = 0; i < 10; i++) + { + sleep(1); + // 0 means waiting for user input + // > 0 means yes/always + // < 0 means no + int checkResult = checkWhitelist(); + if (checkResult > 0) + { + found = 1; + break; + } + else if (checkResult < 0) + { + // user hit no + return permissionDenied(); + } + } + + if (!found) + return permissionDenied(); + } + + if(setgid(gid) || setuid(uid)) + return permissionDenied(); + + char *exec_args[argc + 1]; + exec_args[argc] = NULL; + exec_args[0] = "sh"; + int i; + for (i = 1; i < argc; i++) + { + exec_args[i] = argv[i]; + } + execv("/system/bin/sh", exec_args); + return executionFailure("sh"); +} +