Permalink
Browse files

Initial commit with version 2.3.1

  • Loading branch information...
0 parents commit 49fc519553bebd62bd37290e27cec5553f515159 @ChainsDD ChainsDD committed Feb 28, 2011
Showing with 895 additions and 0 deletions.
  1. +13 −0 Android.mk
  2. 0 MODULE_LICENSE_APACHE2
  3. +190 −0 NOTICE
  4. +19 −0 README
  5. +113 −0 activity.cpp
  6. +517 −0 su.c
  7. +43 −0 su.h
13 Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := su
+LOCAL_SRC_FILES := su.c activity.cpp
+
+
+LOCAL_C_INCLUDES += external/sqlite/dist
+LOCAL_SHARED_LIBRARIES := liblog libsqlite libandroid_runtime
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+
+include $(BUILD_EXECUTABLE)
0 MODULE_LICENSE_APACHE2
No changes.
190 NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
19 README
@@ -0,0 +1,19 @@
+This is the su binary for Superuser on Android.
+
+Any app that requires root access must call this binary in order to be given root access.
+
+Branches for this repo support the following Android versions:
+
+ - legacy
+ - cupcake
+ - donut
+
+ - master
+ - eclair
+ - froyo
+ - gingerbread
+ - honeycomb*
+
+Branches marked with '-dev' are in work and should probably not be used. I will push to those channels as I develop new versions so they may be broken from time to time.
+
+* I have yet to personally test superuser on any honeycomb devices, therefore I cannot guarantee it's compatibility
113 activity.cpp
@@ -0,0 +1,113 @@
+#include <unistd.h>
+#include <android_runtime/ActivityManager.h>
+#include <binder/IBinder.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <utils/String8.h>
+#include <assert.h>
+
+extern "C" {
+#include "su.h"
+#include <private/android_filesystem_config.h>
+#include <cutils/properties.h>
+}
+
+using namespace android;
+
+static const int BROADCAST_INTENT_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 13;
+
+static const int NULL_TYPE_ID = 0;
+
+static const int VAL_STRING = 0;
+static const int VAL_INTEGER = 1;
+
+static const int START_SUCCESS = 0;
+
+int send_intent(struct su_initiator *from, struct su_request *to, const char *socket_path, int type)
+{
+ char sdk_version_prop[PROPERTY_VALUE_MAX] = "0";
+ property_get("ro.build.version.sdk", sdk_version_prop, "0");
+
+ int sdk_version = atoi(sdk_version_prop);
+
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> am = sm->checkService(String16("activity"));
+ assert(am != NULL);
+
+ Parcel data, reply;
+ data.writeInterfaceToken(String16("android.app.IActivityManager"));
+
+ data.writeStrongBinder(NULL); /* caller */
+
+ /* intent */
+ if (type == 0) {
+ data.writeString16(String16("com.noshufou.android.su.REQUEST")); /* action */
+ } else {
+ data.writeString16(String16("com.noshufou.android.su.NOTIFICATION")); /* action */
+ }
+ data.writeInt32(NULL_TYPE_ID); /* Uri - data */
+ data.writeString16(NULL, 0); /* type */
+ data.writeInt32(0); /* flags */
+ if (sdk_version >= 4) {
+ // added in donut
+ data.writeString16(NULL, 0); /* package name - DONUT ONLY, NOT IN CUPCAKE. */
+ }
+ data.writeString16(NULL, 0); /* ComponentName - package */
+ data.writeInt32(0); /* Categories - size */
+ if (sdk_version >= 7) {
+ // added in eclair rev 7
+ data.writeInt32(0);
+ }
+ { /* Extras */
+ data.writeInt32(-1); /* dummy, will hold length */
+ int oldPos = data.dataPosition();
+ data.writeInt32(0x4C444E42); // 'B' 'N' 'D' 'L'
+ { /* writeMapInternal */
+ data.writeInt32(4); /* writeMapInternal - size */
+
+ data.writeInt32(VAL_STRING);
+ data.writeString16(String16("caller_uid"));
+ data.writeInt32(VAL_INTEGER);
+ data.writeInt32(from->uid);
+
+ data.writeInt32(VAL_STRING);
+ data.writeString16(String16("desired_uid"));
+ data.writeInt32(VAL_INTEGER);
+ data.writeInt32(to->uid);
+
+ data.writeInt32(VAL_STRING);
+ data.writeString16(String16("desired_cmd"));
+ data.writeInt32(VAL_STRING);
+ data.writeString16(String16(to->command));
+
+ data.writeInt32(VAL_STRING);
+ data.writeString16(String16("socket"));
+ data.writeInt32(VAL_STRING);
+ data.writeString16(String16(socket_path));
+ }
+ int newPos = data.dataPosition();
+ data.setDataPosition(oldPos - 4);
+ data.writeInt32(newPos - oldPos); /* length */
+ data.setDataPosition(newPos);
+ }
+
+ data.writeString16(NULL, 0); /* resolvedType */
+
+ data.writeInt32(-1); /* Not sure what this is for, but it prevents a warning */
+
+ data.writeStrongBinder(NULL); /* resultTo */
+ data.writeInt32(-1); /* resultCode */
+ data.writeString16(NULL, 0); /* resultData */
+
+ data.writeInt32(-1); /* resultExtras */
+
+ data.writeString16(String16("com.noshufou.android.su.RESPOND")); /* perm */
+ data.writeInt32(0); /* serialized */
+ data.writeInt32(0); /* sticky */
+ data.writeInt32(-1);
+
+ status_t ret = am->transact(BROADCAST_INTENT_TRANSACTION, data, &reply);
+ if (ret < START_SUCCESS) return -1;
+
+ return 0;
+}
517 su.c
@@ -0,0 +1,517 @@
+#define LOG_TAG "su"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <endian.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <stdint.h>
+#include <pwd.h>
+
+#include <private/android_filesystem_config.h>
+#include <cutils/log.h>
+
+#include <sqlite3.h>
+
+extern char* _mktemp(char*); /* mktemp doesn't link right. Don't ask me why. */
+
+#include "su.h"
+
+/* Ewwww. I'm way too lazy. */
+static const char socket_path_template[PATH_MAX] = REQUESTOR_CACHE_PATH "/.socketXXXXXX";
+static char socket_path_buf[PATH_MAX];
+static char *socket_path = NULL;
+static int socket_serv_fd = -1;
+static char shell[PATH_MAX];
+static unsigned req_uid = 0;
+
+static sqlite3 *db = NULL;
+
+static struct su_initiator su_from = {
+ .pid = -1,
+ .uid = 0,
+ .bin = "",
+ .args = "",
+};
+
+static struct su_request su_to = {
+ .uid = AID_ROOT,
+ .command = DEFAULT_COMMAND,
+};
+
+static int from_init(struct su_initiator *from)
+{
+ char path[PATH_MAX], exe[PATH_MAX];
+ char args[4096], *argv0, *argv_rest;
+ int fd;
+ ssize_t len;
+ int i;
+
+ from->uid = getuid();
+ from->pid = getppid();
+
+ /* Get the command line */
+ snprintf(path, sizeof(path), "/proc/%u/cmdline", from->pid);
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ PLOGE("Opening command line");
+ return -1;
+ }
+ len = read(fd, args, sizeof(args));
+ close(fd);
+ if (len < 0 || len == sizeof(args)) {
+ PLOGE("Reading command line");
+ return -1;
+ }
+
+ argv0 = args;
+ argv_rest = NULL;
+ for (i = 0; i < len; i++) {
+ if (args[i] == '\0') {
+ if (!argv_rest) {
+ argv_rest = &args[i+1];
+ } else {
+ args[i] = ' ';
+ }
+ }
+ }
+ args[len] = '\0';
+
+ if (argv_rest) {
+ strncpy(from->args, argv_rest, sizeof(from->args));
+ from->args[sizeof(from->args)-1] = '\0';
+ } else {
+ from->args[0] = '\0';
+ }
+
+ /* If this isn't app_process, use the real path instead of argv[0] */
+ snprintf(path, sizeof(path), "/proc/%u/exe", from->pid);
+ len = readlink(path, exe, sizeof(exe));
+ if (len < 0) {
+ PLOGE("Getting exe path");
+ return -1;
+ }
+ exe[len] = '\0';
+ if (strcmp(exe, "/system/bin/app_process")) {
+ argv0 = exe;
+ }
+
+ strncpy(from->bin, argv0, sizeof(from->bin));
+ from->bin[sizeof(from->bin)-1] = '\0';
+
+ return 0;
+}
+
+static void socket_cleanup(void)
+{
+ unlink(socket_path);
+}
+
+static void cleanup(void)
+{
+ socket_cleanup();
+ if (db) sqlite3_close(db);
+}
+
+static void cleanup_signal(int sig)
+{
+ socket_cleanup();
+ exit(sig);
+}
+
+static int socket_create_temp()
+{
+ int fd, err;
+
+ struct sockaddr_un sun;
+
+ fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+ if (fd < 0) {
+ PLOGE("socket");
+ return -1;
+ }
+
+ for (;;) {
+ memset(&sun, 0, sizeof(sun));
+ sun.sun_family = AF_LOCAL;
+ strcpy(socket_path_buf, socket_path_template);
+ socket_path = _mktemp(socket_path_buf);
+ snprintf(sun.sun_path, sizeof(sun.sun_path), "%s", socket_path);
+
+ if (bind(fd, (struct sockaddr*)&sun, sizeof(sun)) < 0) {
+ if (errno != EADDRINUSE) {
+ PLOGE("bind");
+ return -1;
+ }
+ } else {
+ break;
+ }
+ }
+
+ if (chmod(sun.sun_path, 0600) < 0) {
+ PLOGE("chmod(socket)");
+ unlink(sun.sun_path);
+ return -1;
+ }
+
+ if (chown(sun.sun_path, req_uid, req_uid) < 0) {
+ PLOGE("chown(socket)");
+ unlink(sun.sun_path);
+ return -1;
+ }
+
+ if (listen(fd, 1) < 0) {
+ PLOGE("listen");
+ return -1;
+ }
+
+ return fd;
+}
+
+static int socket_accept(int serv_fd)
+{
+ struct timeval tv;
+ fd_set fds;
+ int fd;
+
+ /* Wait 20 seconds for a connection, then give up. */
+ tv.tv_sec = 20;
+ tv.tv_usec = 0;
+ FD_ZERO(&fds);
+ FD_SET(serv_fd, &fds);
+ if (select(serv_fd + 1, &fds, NULL, NULL, &tv) < 1) {
+ PLOGE("select");
+ return -1;
+ }
+
+ fd = accept(serv_fd, NULL, NULL);
+ if (fd < 0) {
+ PLOGE("accept");
+ return -1;
+ }
+
+ return fd;
+}
+
+static int socket_receive_result(int serv_fd, char *result, ssize_t result_len)
+{
+ ssize_t len;
+
+ for (;;) {
+ int fd = socket_accept(serv_fd);
+ if (fd < 0)
+ return -1;
+
+ len = read(fd, result, result_len-1);
+ if (len < 0) {
+ PLOGE("read(result)");
+ return -1;
+ }
+
+ if (len > 0)
+ break;
+ }
+
+ result[len] = '\0';
+
+ return 0;
+}
+
+static sqlite3 *database_init()
+{
+ sqlite3 *db;
+
+ if (mkdir(REQUESTOR_DATABASES_PATH, 0771) >= 0) {
+ chown(REQUESTOR_DATABASES_PATH, req_uid, req_uid);
+ }
+
+ if (sqlite3_open(REQUESTOR_DATABASE_PATH, &db) != SQLITE_OK) {
+ LOGE("Couldn't open database");
+ return NULL;
+ }
+
+ if (sqlite3_exec(db,
+ "PRAGMA journal_mode = delete;",
+ NULL,
+ NULL,
+ NULL
+ ) != SQLITE_OK) {
+ LOGE("Could not set journal mode");
+ sqlite3_close(db);
+ return NULL;
+ }
+
+ chmod(REQUESTOR_DATABASE_PATH, 0660);
+ chown(REQUESTOR_DATABASE_PATH, req_uid, req_uid);
+
+ if (sqlite3_exec(db,
+ "CREATE TABLE IF NOT EXISTS apps (_id INTEGER, uid INTEGER, package TEXT, name TEXT, exec_uid INTEGER, exec_cmd TEXT, allow INTEGER, PRIMARY KEY (_id), UNIQUE (uid,exec_uid,exec_cmd));",
+ NULL,
+ NULL,
+ NULL
+ ) != SQLITE_OK) {
+ LOGE("Couldn't create apps table");
+ sqlite3_close(db);
+ return NULL;
+ }
+
+ if (sqlite3_exec(db,
+ "CREATE TABLE IF NOT EXISTS logs (_id INTEGER, app_id INTEGER, date INTEGER, type INTEGER, PRIMARY KEY (_id));",
+ NULL,
+ NULL,
+ NULL
+ ) != SQLITE_OK) {
+ LOGE("Couldn't create logs table");
+ sqlite3_close(db);
+ return NULL;
+ }
+
+ return db;
+}
+
+enum {
+ DB_INTERACTIVE,
+ DB_DENY,
+ DB_ALLOW
+};
+
+static int database_check(sqlite3 *db, struct su_initiator *from, struct su_request *to)
+{
+ char sql[4096];
+ char *zErrmsg;
+ char **result;
+ int nrow,ncol;
+ int allow;
+ struct timeval tv;
+
+ sqlite3_snprintf(
+ sizeof(sql), sql,
+ "SELECT _id,allow FROM apps WHERE uid=%u AND exec_uid=%u AND exec_cmd='%q';",
+ (unsigned)from->uid, to->uid, to->command
+ );
+
+ if (strlen(sql) >= sizeof(sql)-1)
+ return DB_DENY;
+
+ if (sqlite3_get_table(db, sql, &result, &nrow, &ncol, &zErrmsg) != SQLITE_OK) {
+ LOGE("Database check failed with error message %s", zErrmsg);
+ return DB_DENY;
+ }
+
+ if (nrow == 0 || ncol != 2)
+ return DB_INTERACTIVE;
+
+ if (strcmp(result[0], "_id") == 0 && strcmp(result[1], "allow") == 0) {
+ if (strcmp(result[3], "1") == 0) {
+ allow = DB_ALLOW;
+ } else {
+ allow = DB_DENY;
+ }
+ gettimeofday(&tv, NULL);
+ sqlite3_snprintf(
+ sizeof(sql), sql,
+ "INSERT OR IGNORE INTO logs (app_id,date,type) VALUES (%s,(%ld*1000)+(%ld/1000),%s);",
+ result[2], tv.tv_sec, tv.tv_usec, result[3]
+ );
+ sqlite3_exec(db, sql, NULL, NULL, NULL);
+ return allow;
+ }
+
+ sqlite3_free_table(result);
+
+ return DB_INTERACTIVE;
+}
+
+static int check_notifications(sqlite3 *db)
+{
+ char sql[4096];
+ char *zErrmsg;
+ char **result;
+ int nrow,ncol;
+ int notifications;
+
+ sqlite3_snprintf(
+ sizeof(sql), sql,
+ "SELECT value FROM prefs WHERE key='notifications';"
+ );
+
+ if (sqlite3_get_table(db, sql, &result, &nrow, &ncol, &zErrmsg) != SQLITE_OK) {
+ LOGE("Notifications check failed with error message %s", zErrmsg);
+ return 0;
+ }
+
+ if (nrow == 0 || ncol != 1)
+ return 0;
+
+ if (strcmp(result[0], "value") == 0 && strcmp(result[1], "1") == 0)
+ return 1;
+
+ return 0;
+}
+
+static void deny(void)
+{
+ struct su_initiator *from = &su_from;
+ struct su_request *to = &su_to;
+
+ LOGW("request rejected (%u->%u %s)", from->uid, to->uid, to->command);
+ fprintf(stderr, "%s\n", strerror(EACCES));
+ exit(-1);
+}
+
+static void allow(int notifications)
+{
+ struct su_initiator *from = &su_from;
+ struct su_request *to = &su_to;
+ char *exe = NULL;
+
+ if (notifications)
+ send_intent(&su_from, &su_to, "", 1);
+
+ if (!strcmp(shell, "")) {
+ strcpy(shell , "/system/bin/sh");
+ }
+ exe = strrchr (shell, '/') + 1;
+ setgroups(0, NULL);
+ setresgid(to->uid, to->uid, to->uid);
+ setresuid(to->uid, to->uid, to->uid);
+ LOGD("%u %s executing %u %s using shell %s : %s", from->uid, from->bin, to->uid, to->command, shell, exe);
+ if (strcmp(to->command, DEFAULT_COMMAND)) {
+ execl(shell, exe, "-c", to->command, (char*)NULL);
+ } else {
+ execl(shell, exe, "-", (char*)NULL);
+ }
+ PLOGE("exec");
+ exit(-1);
+}
+
+int main(int argc, char *argv[])
+{
+ struct stat st;
+ char buf[64], *result;
+ int i;
+ int dballow;
+
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "-c")) {
+ if (++i < argc) {
+ su_to.command = argv[i];
+ } else {
+ deny();
+ }
+ } else if (!strcmp(argv[i], "-s")) {
+ if (++i < argc) {
+ strcpy(shell, argv[i]);
+ } else {
+ deny();
+ }
+ } else if (!strcmp(argv[i], "-v")) {
+ printf("%s\n", VERSION);
+ exit(-1);
+ } else if (!strcmp(argv[i], "-")) {
+ ++i;
+ break;
+ } else {
+ break;
+ }
+ }
+ if (i < argc-1) {
+ deny();
+ }
+ if (i == argc-1) {
+ struct passwd *pw;
+ pw = getpwnam(argv[i]);
+ if (!pw) {
+ su_to.uid = atoi(argv[i]);
+ } else {
+ su_to.uid = pw->pw_uid;
+ }
+ }
+
+ from_init(&su_from);
+
+ if (su_from.uid == AID_ROOT)
+ allow(0);
+
+ if (stat(REQUESTOR_DATA_PATH, &st) < 0) {
+ PLOGE("stat");
+ deny();
+ }
+
+ if (st.st_gid != st.st_uid)
+ {
+ LOGE("Bad uid/gid %d/%d for Superuser Requestor application", (int)st.st_uid, (int)st.st_gid);
+ deny();
+ }
+
+ req_uid = st.st_uid;
+
+ if (from_init(&su_from) < 0) {
+ deny();
+ }
+
+ if (mkdir(REQUESTOR_CACHE_PATH, 0771) >= 0) {
+ chown(REQUESTOR_CACHE_PATH, req_uid, req_uid);
+ }
+
+ db = database_init();
+ if (!db) {
+ deny();
+ }
+
+ dballow = database_check(db, &su_from, &su_to);
+ int notifications = check_notifications(db);
+ switch (dballow) {
+ case DB_DENY: deny();
+ case DB_ALLOW: allow(notifications);
+ case DB_INTERACTIVE: break;
+ default: deny();
+ }
+
+ socket_serv_fd = socket_create_temp();
+ if (socket_serv_fd < 0) {
+ deny();
+ }
+
+ signal(SIGHUP, cleanup_signal);
+ signal(SIGPIPE, cleanup_signal);
+ signal(SIGTERM, cleanup_signal);
+ signal(SIGABRT, cleanup_signal);
+ atexit(cleanup);
+
+ if (send_intent(&su_from, &su_to, socket_path, 0) < 0) {
+ deny();
+ }
+
+ if (socket_receive_result(socket_serv_fd, buf, sizeof(buf)) < 0) {
+ deny();
+ }
+
+ close(socket_serv_fd);
+ socket_cleanup();
+
+ result = buf;
+
+ if (!strcmp(result, "DENY")) {
+ deny();
+ } else if (!strcmp(result, "ALLOW")) {
+ allow(notifications);
+ } else {
+ LOGE("unknown response from Superuser Requestor: %s", result);
+ deny();
+ }
+
+ deny();
+ return -1;
+}
43 su.h
@@ -0,0 +1,43 @@
+#ifndef SU_h
+#define SU_h 1
+
+#define REQUESTOR_PACKAGE "com.noshufou.android.su"
+#define REQUESTOR_CLASS "SuRequest"
+
+#define REQUESTOR_DATA_PATH "/data/data/" REQUESTOR_PACKAGE
+#define REQUESTOR_CACHE_PATH REQUESTOR_DATA_PATH "/cache"
+
+#define REQUESTOR_DATABASES_PATH REQUESTOR_DATA_PATH "/databases"
+#define REQUESTOR_DATABASE_PATH REQUESTOR_DATABASES_PATH "/permissions.sqlite"
+
+#define DEFAULT_COMMAND "/system/bin/sh"
+
+#define VERSION "2.3.1-efg"
+
+struct su_initiator {
+ pid_t pid;
+ unsigned uid;
+ char bin[PATH_MAX];
+ char args[4096];
+};
+
+struct su_request {
+ unsigned uid;
+ char *command;
+};
+
+extern int send_intent(struct su_initiator *from, struct su_request *to, const char *socket_path, int type);
+
+#if 0
+#undef LOGE
+#define LOGE(fmt,args...) fprintf(stderr, fmt , ## args )
+#undef LOGD
+#define LOGD(fmt,args...) fprintf(stderr, fmt , ## args )
+#undef LOGW
+#define LOGW(fmt,args...) fprintf(stderr, fmt , ## args )
+#endif
+
+#define PLOGE(fmt,args...) LOGE(fmt " failed with %d: %s" , ## args , errno, strerror(errno))
+#define PLOGEV(fmt,err,args...) LOGE(fmt " failed with %d: %s" , ## args , err, strerror(err))
+
+#endif

0 comments on commit 49fc519

Please sign in to comment.