static void allow(char *shell, mode_t mask) { struct su_initiator *from = &su_from; struct su_request *to = &su_to; char *exe = NULL; umask(mask); send_intent(&su_from, &su_to, "", 1, 1); if (!strcmp(shell, "")) { strcpy(shell , "/system/bin/sh"); } exe = strrchr (shell, '/') + 1; 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(EXIT_SUCCESS); }
static __attribute__ ((noreturn)) void deny(const struct su_context *ctx) { char *cmd = get_command(&ctx->to); send_intent(ctx, "", 0, ACTION_RESULT); LOGW("request rejected (%u->%u %s)", ctx->from.uid, ctx->to.uid, cmd); fprintf(stderr, "%s\n", strerror(EACCES)); exit(EXIT_FAILURE); }
static void deny(void) { struct su_initiator *from = &su_from; struct su_request *to = &su_to; send_intent(&su_from, &su_to, "", 0, 1); LOGW("request rejected (%u->%u %s)", from->uid, to->uid, to->command); fprintf(stderr, "%s\n", strerror(EACCES)); exit(EXIT_FAILURE); }
int main (int argc, char *argv[]) { printf("Welcome to pinentry-android\n"); printf("starting java activity...\n"); send_intent(); sleep(3); pid_t child_pid; int child_status; // pinentry_init ("pinentry-android"); /* Consumes all arguments. */ // if (pinentry_parse_opts (argc, argv)) // { // printf ("pinentry-android (pinentry) " VERSION "\n"); // exit (EXIT_SUCCESS); // } struct sockaddr_un addr; int fd; if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { perror("socket error"); exit(-1); } memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; addr.sun_path[0] = '\0'; strncpy( &addr.sun_path[1], SOCKET_NAME, sizeof(addr.sun_path)-1 ); /* calculate the length of our addrlen, for some reason this isn't simply * sizeof(addr), TODO: learn why, i suspect it has something to do with sun_path * being a char[108] */ int len = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&addr.sun_path[1]); printf("connecting to Java socket server...\n"); if (connect(fd, (struct sockaddr*)&addr, len) < 0) { perror("connect error"); exit(-1); } printf("connection succeeded\n"); /* remember Java doesn't understand \0 terminated strings*/ int bytes_written = write(fd, "hello!", 6); printf("wrote %d bytes \n", bytes_written); close(fd); child_pid = fork(); if( child_pid < 0 ) { /* unsuccessful fork */ perror("fork:"); exit(-1); } if( child_pid == 0 ) { /* child process */ printf("child! bye\n"); /* TODO: we actually don't want to pass the socket here..*/ // if (pinentry_loop2 (fd, fd)) // exit(1); exit(0); } else { /* parent process */ wait(&child_status); exit(0); } return 0; }
static __attribute__ ((noreturn)) void allow(const struct su_context *ctx) { char *arg0; int argc, err; umask(ctx->umask); send_intent(ctx, "", 1, ACTION_RESULT); arg0 = strrchr (ctx->to.shell, '/'); arg0 = (arg0) ? arg0 + 1 : ctx->to.shell; if (ctx->to.login) { int s = strlen(arg0) + 2; char *p = malloc(s); if (!p) exit(EXIT_FAILURE); *p = '-'; strcpy(p + 1, arg0); arg0 = p; } /* * Set effective uid back to root, otherwise setres[ug]id will fail * if ctx->to.uid isn't root. */ if (seteuid(0)) { PLOGE("seteuid (root)"); exit(EXIT_FAILURE); } populate_environment(ctx); if (setresgid(ctx->to.uid, ctx->to.uid, ctx->to.uid)) { PLOGE("setresgid (%u)", ctx->to.uid); exit(EXIT_FAILURE); } if (setresuid(ctx->to.uid, ctx->to.uid, ctx->to.uid)) { PLOGE("setresuid (%u)", ctx->to.uid); exit(EXIT_FAILURE); } #define PARG(arg) \ (ctx->to.optind + (arg) < ctx->to.argc) ? " " : "", \ (ctx->to.optind + (arg) < ctx->to.argc) ? ctx->to.argv[ctx->to.optind + (arg)] : "" LOGD("%u %s executing %u %s using shell %s : %s%s%s%s%s%s%s%s%s%s%s%s%s%s", ctx->from.uid, ctx->from.bin, ctx->to.uid, get_command(&ctx->to), ctx->to.shell, arg0, PARG(0), PARG(1), PARG(2), PARG(3), PARG(4), PARG(5), (ctx->to.optind + 6 < ctx->to.argc) ? " ..." : ""); argc = ctx->to.optind; if (ctx->to.command) { ctx->to.argv[--argc] = ctx->to.command; ctx->to.argv[--argc] = "-c"; } ctx->to.argv[--argc] = arg0; execv(ctx->to.shell, ctx->to.argv + argc); err = errno; PLOGE("exec"); fprintf(stderr, "Cannot execute %s: %s\n", ctx->to.shell, strerror(err)); exit(EXIT_FAILURE); }
int main(int argc, char *argv[]) { struct stat st; static int socket_serv_fd = -1; char buf[64], shell[PATH_MAX], *result, debuggable[PROPERTY_VALUE_MAX]; char enabled[PROPERTY_VALUE_MAX], build_type[PROPERTY_VALUE_MAX]; char root_settings[PROPERTY_VALUE_MAX]; int i, dballow; mode_t orig_umask; for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-c") || !strcmp(argv[i], "--command")) { if (++i < argc) { su_to.command = argv[i]; } else { usage(); } } else if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "--shell")) { if (++i < argc) { strncpy(shell, argv[i], sizeof(shell)); shell[sizeof(shell) - 1] = 0; } else { usage(); } } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) { printf("%s\n", VERSION); exit(EXIT_SUCCESS); } else if (!strcmp(argv[i], "-V")) { printf("%d\n", VERSION_CODE); exit(EXIT_SUCCESS); } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { usage(); } else if (!strcmp(argv[i], "-") || !strcmp(argv[i], "-l") || !strcmp(argv[i], "--login")) { ++i; break; } else { break; } } if (i < argc-1) { usage(); } 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; } } if (from_init(&su_from) < 0) { deny(); } property_get("ro.debuggable", debuggable, "0"); property_get(ROOT_ACCESS_PROPERTY, enabled, ROOT_ACCESS_DEFAULT); property_get("ro.build.type", build_type, ""); property_get(ROOT_SETTINGS_PROPERTY, root_settings, ""); orig_umask = umask(027); // Root Settings-specific behavior if (strcmp("1", root_settings) == 0) { // only allow su on debuggable builds if (strcmp("1", debuggable) != 0) { LOGE("Root access is disabled on non-debug builds"); deny(); } // enforce persist.sys.root_access on non-eng builds if (strcmp("eng", build_type) != 0 && (atoi(enabled) & 1) != 1 ) { LOGE("Root access is disabled by system setting - enable it under settings -> developer options"); deny(); } // disallow su in a shell if appropriate if (su_from.uid == AID_SHELL && (atoi(enabled) == 1)) { LOGE("Root access is disabled by a system setting - enable it under settings -> developer options"); deny(); } } if (su_from.uid == AID_ROOT || su_from.uid == AID_SHELL) allow(shell, orig_umask); 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(); } if (mkdir(REQUESTOR_CACHE_PATH, 0770) >= 0) { chown(REQUESTOR_CACHE_PATH, st.st_uid, st.st_gid); } setgroups(0, NULL); setegid(st.st_gid); seteuid(st.st_uid); LOGE("sudb - Opening database"); db = database_init(); if (!db) { LOGE("sudb - Could not open database, prompt user"); // if the database could not be opened, we can assume we need to // prompt the user dballow = DB_INTERACTIVE; } else { LOGE("sudb - Database opened"); dballow = database_check(db, &su_from, &su_to); // Close the database, we're done with it. If it stays open, // it will cause problems sqlite3_close(db); db = NULL; LOGE("sudb - Database closed"); } switch (dballow) { case DB_DENY: deny(); case DB_ALLOW: allow(shell, orig_umask); 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, -1, 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(shell, orig_umask); } else { LOGE("unknown response from Superuser Requestor: %s", result); deny(); } deny(); return -1; }