OSDN Git Service

autogrant radio/system as appropriate (prevent crashing on stock roms)
[android-x86/external-koush-Superuser.git] / Superuser / jni / su / su.c
1 /*
2 ** Copyright 2010, Adam Shanks (@ChainsDD)
3 ** Copyright 2008, Zinx Verituse (@zinxv)
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 **     http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <sys/un.h>
21 #include <sys/wait.h>
22 #include <sys/select.h>
23 #include <sys/time.h>
24 #include <unistd.h>
25 #include <limits.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <getopt.h>
30 #include <stdint.h>
31 #include <pwd.h>
32 #include <sys/stat.h>
33 #include <stdarg.h>
34 #include <sys/types.h>
35
36 #include "su.h"
37 #include "utils.h"
38
39 unsigned get_shell_uid() {
40   struct passwd* ppwd = getpwnam("shell");
41   if (NULL == ppwd) {
42     return 2000;
43   }
44   
45   return ppwd->pw_uid;
46 }
47
48 unsigned get_system_uid() {
49   struct passwd* ppwd = getpwnam("system");
50   if (NULL == ppwd) {
51     return 1000;
52   }
53   
54   return ppwd->pw_uid;
55 }
56
57 unsigned get_radio_uid() {
58   struct passwd* ppwd = getpwnam("radio");
59   if (NULL == ppwd) {
60     return 1001;
61   }
62   
63   return ppwd->pw_uid;
64 }
65
66 void exec_log(char *priority, char* logline) {
67   int pid;
68   if ((pid = fork()) == 0) {
69       int zero = open("/dev/zero", O_RDONLY | O_CLOEXEC);
70       dup2(zero, 0);
71       int null = open("/dev/null", O_WRONLY | O_CLOEXEC);
72       dup2(null, 1);
73       dup2(null, 2);
74       execl("/system/bin/log", "/system/bin/log", "-p", priority, "-t", LOG_TAG, logline);
75       _exit(0);
76   }
77 }
78
79 void exec_loge(const char* fmt, ...) {
80     va_list args;
81
82     char logline[PATH_MAX];
83     va_start(args, fmt);
84     vsnprintf(logline, PATH_MAX, fmt, args);
85     va_end(args);
86     exec_log("e", logline);
87 }
88
89 void exec_logw(const char* fmt, ...) {
90     va_list args;
91
92     char logline[PATH_MAX];
93     va_start(args, fmt);
94     vsnprintf(logline, PATH_MAX, fmt, args);
95     va_end(args);
96     exec_log("w", logline);
97 }
98
99 void exec_logd(const char* fmt, ...) {
100     va_list args;
101
102     char logline[PATH_MAX];
103     va_start(args, fmt);
104     vsnprintf(logline, PATH_MAX, fmt, args);
105     va_end(args);
106     exec_log("d", logline);
107 }
108
109 static int from_init(struct su_initiator *from) {
110     char path[PATH_MAX], exe[PATH_MAX];
111     char args[4096], *argv0, *argv_rest;
112     int fd;
113     ssize_t len;
114     int i;
115     int err;
116
117     from->uid = getuid();
118     from->pid = getppid();
119
120     /* Get the command line */
121     snprintf(path, sizeof(path), "/proc/%u/cmdline", from->pid);
122     fd = open(path, O_RDONLY);
123     if (fd < 0) {
124         PLOGE("Opening command line");
125         return -1;
126     }
127     len = read(fd, args, sizeof(args));
128     err = errno;
129     close(fd);
130     if (len < 0 || len == sizeof(args)) {
131         PLOGEV("Reading command line", err);
132         return -1;
133     }
134
135     argv0 = args;
136     argv_rest = NULL;
137     for (i = 0; i < len; i++) {
138         if (args[i] == '\0') {
139             if (!argv_rest) {
140                 argv_rest = &args[i+1];
141             } else {
142                 args[i] = ' ';
143             }
144         }
145     }
146     args[len] = '\0';
147
148     if (argv_rest) {
149         strncpy(from->args, argv_rest, sizeof(from->args));
150         from->args[sizeof(from->args)-1] = '\0';
151     } else {
152         from->args[0] = '\0';
153     }
154
155     /* If this isn't app_process, use the real path instead of argv[0] */
156     snprintf(path, sizeof(path), "/proc/%u/exe", from->pid);
157     len = readlink(path, exe, sizeof(exe));
158     if (len < 0) {
159         PLOGE("Getting exe path");
160         return -1;
161     }
162     exe[len] = '\0';
163     if (strcmp(exe, "/system/bin/app_process")) {
164         argv0 = exe;
165     }
166
167     strncpy(from->bin, argv0, sizeof(from->bin));
168     from->bin[sizeof(from->bin)-1] = '\0';
169
170     struct passwd *pw;
171     pw = getpwuid(from->uid);
172     if (pw && pw->pw_name) {
173         strncpy(from->name, pw->pw_name, sizeof(from->name));
174     }
175
176     return 0;
177 }
178
179 static int get_multiuser_mode() {
180     char *data;
181     char sdk_ver[PROPERTY_VALUE_MAX];
182
183     data = read_file("/system/build.prop");
184     get_property(data, sdk_ver, "ro.build.version.sdk", "0");
185     free(data);
186
187     int sdk = atoi(sdk_ver);
188     if (sdk < 17)
189         return MULTIUSER_MODE_NONE;
190
191     int ret = MULTIUSER_MODE_OWNER_ONLY;
192     char mode[12];
193     FILE *fp;
194     if ((fp = fopen(REQUESTOR_MULTIUSER_MODE, "r"))) {
195         fgets(mode, sizeof(mode), fp);
196         int last = strlen(mode) - 1;
197         if (mode[last] == '\n')
198             mode[last] = '\0';
199         if (strcmp(mode, MULTIUSER_VALUE_USER) == 0) {
200             ret = MULTIUSER_MODE_USER;
201         } else if (strcmp(mode, MULTIUSER_VALUE_OWNER_MANAGED) == 0) {
202             ret = MULTIUSER_MODE_OWNER_MANAGED;
203         }
204         else {
205             ret = MULTIUSER_MODE_OWNER_ONLY;
206         }
207         fclose(fp);
208     }
209     return ret;
210 }
211
212 static void read_options(struct su_context *ctx) {
213     ctx->user.multiuser_mode = get_multiuser_mode();
214 }
215
216 static void user_init(struct su_context *ctx) {
217     if (ctx->from.uid > 99999) {
218         ctx->user.android_user_id = ctx->from.uid / 100000;
219         if (ctx->user.multiuser_mode == MULTIUSER_MODE_USER) {
220             snprintf(ctx->user.database_path, PATH_MAX, "%s/%d/%s", REQUESTOR_USER_PATH, ctx->user.android_user_id, REQUESTOR_DATABASE_PATH);
221             snprintf(ctx->user.base_path, PATH_MAX, "%s/%d/%s", REQUESTOR_USER_PATH, ctx->user.android_user_id, REQUESTOR);
222         }
223     }
224 }
225
226 static void populate_environment(const struct su_context *ctx) {
227     struct passwd *pw;
228
229     if (ctx->to.keepenv)
230         return;
231
232     pw = getpwuid(ctx->to.uid);
233     if (pw) {
234         setenv("HOME", pw->pw_dir, 1);
235         setenv("SHELL", ctx->to.shell, 1);
236         if (ctx->to.login || ctx->to.uid) {
237             setenv("USER", pw->pw_name, 1);
238             setenv("LOGNAME", pw->pw_name, 1);
239         }
240     }
241 }
242
243 void set_identity(unsigned int uid) {
244     /*
245      * Set effective uid back to root, otherwise setres[ug]id will fail
246      * if uid isn't root.
247      */
248     if (seteuid(0)) {
249         PLOGE("seteuid (root)");
250         exit(EXIT_FAILURE);
251     }
252     if (setresgid(uid, uid, uid)) {
253         PLOGE("setresgid (%u)", uid);
254         exit(EXIT_FAILURE);
255     }
256     if (setresuid(uid, uid, uid)) {
257         PLOGE("setresuid (%u)", uid);
258         exit(EXIT_FAILURE);
259     }
260 }
261
262 static void socket_cleanup(struct su_context *ctx) {
263     if (ctx && ctx->sock_path[0]) {
264         if (unlink(ctx->sock_path))
265             PLOGE("unlink (%s)", ctx->sock_path);
266         ctx->sock_path[0] = 0;
267     }
268 }
269
270 /*
271  * For use in signal handlers/atexit-function
272  * NOTE: su_ctx points to main's local variable.
273  *       It's OK due to the program uses exit(3), not return from main()
274  */
275 static struct su_context *su_ctx = NULL;
276
277 static void cleanup(void) {
278     socket_cleanup(su_ctx);
279 }
280
281 static void cleanup_signal(int sig) {
282     socket_cleanup(su_ctx);
283     exit(128 + sig);
284 }
285
286 static int socket_create_temp(char *path, size_t len) {
287     int fd;
288     struct sockaddr_un sun;
289
290     fd = socket(AF_LOCAL, SOCK_STREAM, 0);
291     if (fd < 0) {
292         PLOGE("socket");
293         return -1;
294     }
295     if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
296         PLOGE("fcntl FD_CLOEXEC");
297         goto err;
298     }
299
300     memset(&sun, 0, sizeof(sun));
301     sun.sun_family = AF_LOCAL;
302     snprintf(path, len, "%s/.socket%d", REQUESTOR_CACHE_PATH, getpid());
303     memset(sun.sun_path, 0, sizeof(sun.sun_path));
304     snprintf(sun.sun_path, sizeof(sun.sun_path), "%s", path);
305
306     /*
307      * Delete the socket to protect from situations when
308      * something bad occured previously and the kernel reused pid from that process.
309      * Small probability, isn't it.
310      */
311     unlink(sun.sun_path);
312
313     if (bind(fd, (struct sockaddr*)&sun, sizeof(sun)) < 0) {
314         PLOGE("bind");
315         goto err;
316     }
317
318     if (listen(fd, 1) < 0) {
319         PLOGE("listen");
320         goto err;
321     }
322
323     return fd;
324 err:
325     close(fd);
326     return -1;
327 }
328
329 static int socket_accept(int serv_fd) {
330     struct timeval tv;
331     fd_set fds;
332     int fd, rc;
333
334     /* Wait 20 seconds for a connection, then give up. */
335     tv.tv_sec = 20;
336     tv.tv_usec = 0;
337     FD_ZERO(&fds);
338     FD_SET(serv_fd, &fds);
339     do {
340         rc = select(serv_fd + 1, &fds, NULL, NULL, &tv);
341     } while (rc < 0 && errno == EINTR);
342     if (rc < 1) {
343         PLOGE("select");
344         return -1;
345     }
346
347     fd = accept(serv_fd, NULL, NULL);
348     if (fd < 0) {
349         PLOGE("accept");
350         return -1;
351     }
352
353     return fd;
354 }
355
356 static int socket_send_request(int fd, const struct su_context *ctx) {
357 #define write_data(fd, data, data_len)              \
358 do {                                                \
359     size_t __len = htonl(data_len);                 \
360     __len = write((fd), &__len, sizeof(__len));     \
361     if (__len != sizeof(__len)) {                   \
362         PLOGE("write(" #data ")");                  \
363         return -1;                                  \
364     }                                               \
365     __len = write((fd), data, data_len);            \
366     if (__len != data_len) {                        \
367         PLOGE("write(" #data ")");                  \
368         return -1;                                  \
369     }                                               \
370 } while (0)
371
372 #define write_string(fd, name, data)        \
373 do {                                        \
374     write_data(fd, name, strlen(name));     \
375     write_data(fd, data, strlen(data));     \
376 } while (0)
377
378 // stringify everything.
379 #define write_token(fd, name, data)         \
380 do {                                        \
381     char buf[16];                           \
382     snprintf(buf, sizeof(buf), "%d", data); \
383     write_string(fd, name, buf);            \
384 } while (0)
385
386     write_token(fd, "version", PROTO_VERSION);
387     write_token(fd, "binary.version", VERSION_CODE);
388     write_token(fd, "pid", ctx->from.pid);
389     write_string(fd, "from.name", ctx->from.name);
390     write_string(fd, "to.name", ctx->to.name);
391     write_token(fd, "from.uid", ctx->from.uid);
392     write_token(fd, "to.uid", ctx->to.uid);
393     write_string(fd, "from.bin", ctx->from.bin);
394     write_string(fd, "command", get_command(&ctx->to));
395     write_token(fd, "eof", PROTO_VERSION);
396     return 0;
397 }
398
399 static int socket_receive_result(int fd, char *result, ssize_t result_len) {
400     ssize_t len;
401     
402     LOGD("waiting for user");
403     len = read(fd, result, result_len-1);
404     if (len < 0) {
405         PLOGE("read(result)");
406         return -1;
407     }
408     result[len] = '\0';
409
410     return 0;
411 }
412
413 static void usage(int status) {
414     FILE *stream = (status == EXIT_SUCCESS) ? stdout : stderr;
415
416     fprintf(stream,
417     "Usage: su [options] [--] [-] [LOGIN] [--] [args...]\n\n"
418     "Options:\n"
419     "  -c, --command COMMAND         pass COMMAND to the invoked shell\n"
420     "  -h, --help                    display this help message and exit\n"
421     "  -, -l, --login                pretend the shell to be a login shell\n"
422     "  -m, -p,\n"
423     "  --preserve-environment        do not change environment variables\n"
424     "  -s, --shell SHELL             use SHELL instead of the default " DEFAULT_SHELL "\n"
425     "  -u                            display the multiuser mode and exit\n"
426     "  -v, --version                 display version number and exit\n"
427     "  -V                            display version code and exit,\n"
428     "                                this is used almost exclusively by Superuser.apk\n");
429     exit(status);
430 }
431
432 static __attribute__ ((noreturn)) void deny(struct su_context *ctx) {
433     char *cmd = get_command(&ctx->to);
434
435     // No send to UI denied requests for shell and root users (they are in the log)
436     // if( ctx->from.uid != AID_SHELL && ctx->from.uid != AID_ROOT ) {
437         send_result(ctx, DENY);
438     // }
439     LOGW("request rejected (%u->%u %s)", ctx->from.uid, ctx->to.uid, cmd);
440     fprintf(stderr, "%s\n", strerror(EACCES));
441     exit(EXIT_FAILURE);
442 }
443
444 static __attribute__ ((noreturn)) void allow(struct su_context *ctx) {
445     char *arg0;
446     int argc, err;
447
448     umask(ctx->umask);
449     // No send to UI accepted requests for shell and root users (they are in the log)
450     // if( ctx->from.uid != AID_SHELL && ctx->from.uid != AID_ROOT ) {
451         send_result(ctx, ALLOW);
452     // }
453
454     arg0 = strrchr (ctx->to.shell, '/');
455     arg0 = (arg0) ? arg0 + 1 : ctx->to.shell;
456     if (ctx->to.login) {
457         int s = strlen(arg0) + 2;
458         char *p = malloc(s);
459
460         if (!p)
461             exit(EXIT_FAILURE);
462
463         *p = '-';
464         strcpy(p + 1, arg0);
465         arg0 = p;
466     }
467
468     populate_environment(ctx);
469     set_identity(ctx->to.uid);
470
471 #define PARG(arg)                                    \
472     (ctx->to.optind + (arg) < ctx->to.argc) ? " " : "",                    \
473     (ctx->to.optind + (arg) < ctx->to.argc) ? ctx->to.argv[ctx->to.optind + (arg)] : ""
474
475     LOGD("%u %s executing %u %s using shell %s : %s%s%s%s%s%s%s%s%s%s%s%s%s%s",
476             ctx->from.uid, ctx->from.bin,
477             ctx->to.uid, get_command(&ctx->to), ctx->to.shell,
478             arg0, PARG(0), PARG(1), PARG(2), PARG(3), PARG(4), PARG(5),
479             (ctx->to.optind + 6 < ctx->to.argc) ? " ..." : "");
480
481     argc = ctx->to.optind;
482     if (ctx->to.command) {
483         ctx->to.argv[--argc] = ctx->to.command;
484         ctx->to.argv[--argc] = "-c";
485     }
486     ctx->to.argv[--argc] = arg0;
487     execv(ctx->to.shell, ctx->to.argv + argc);
488     err = errno;
489     PLOGE("exec");
490     fprintf(stderr, "Cannot execute %s: %s\n", ctx->to.shell, strerror(err));
491     exit(EXIT_FAILURE);
492 }
493
494 /*
495  * CyanogenMod-specific behavior
496  *
497  * we can't simply use the property service, since we aren't launched from init
498  * and can't trust the location of the property workspace.
499  * Find the properties ourselves.
500  */
501 int access_disabled(const struct su_initiator *from) {
502     char *data;
503     char build_type[PROPERTY_VALUE_MAX];
504     char debuggable[PROPERTY_VALUE_MAX], enabled[PROPERTY_VALUE_MAX];
505     size_t len;
506
507     data = read_file("/system/build.prop");
508     if (check_property(data, "ro.cm.version")) {
509         get_property(data, build_type, "ro.build.type", "");
510         free(data);
511
512         data = read_file("/default.prop");
513         get_property(data, debuggable, "ro.debuggable", "0");
514         free(data);
515         /* only allow su on debuggable builds */
516         if (strcmp("1", debuggable) != 0) {
517             LOGE("Root access is disabled on non-debug builds");
518             return 1;
519         }
520
521         data = read_file("/data/property/persist.sys.root_access");
522         if (data != NULL) {
523             len = strlen(data);
524             if (len >= PROPERTY_VALUE_MAX)
525                 memcpy(enabled, "1", 2);
526             else
527                 memcpy(enabled, data, len + 1);
528             free(data);
529         } else
530             memcpy(enabled, "1", 2);
531
532         /* enforce persist.sys.root_access on non-eng builds for apps */
533         if (strcmp("eng", build_type) != 0 &&
534                 from->uid != AID_SHELL && from->uid != AID_ROOT &&
535                 (atoi(enabled) & CM_ROOT_ACCESS_APPS_ONLY) != CM_ROOT_ACCESS_APPS_ONLY ) {
536             LOGE("Apps root access is disabled by system setting - "
537                  "enable it under settings -> developer options");
538             return 1;
539         }
540
541         /* disallow su in a shell if appropriate */
542         if (from->uid == AID_SHELL &&
543                 (atoi(enabled) & CM_ROOT_ACCESS_ADB_ONLY) != CM_ROOT_ACCESS_ADB_ONLY ) {
544             LOGE("Shell root access is disabled by a system setting - "
545                  "enable it under settings -> developer options");
546             return 1;
547         }
548         
549     }
550     return 0;
551 }
552
553 int main(int argc, char *argv[]) {
554     // Sanitize all secure environment variables (from linker_environ.c in AOSP linker).
555     /* The same list than GLibc at this point */
556     static const char* const unsec_vars[] = {
557         "GCONV_PATH",
558         "GETCONF_DIR",
559         "HOSTALIASES",
560         "LD_AUDIT",
561         "LD_DEBUG",
562         "LD_DEBUG_OUTPUT",
563         "LD_DYNAMIC_WEAK",
564         "LD_LIBRARY_PATH",
565         "LD_ORIGIN_PATH",
566         "LD_PRELOAD",
567         "LD_PROFILE",
568         "LD_SHOW_AUXV",
569         "LD_USE_LOAD_BIAS",
570         "LOCALDOMAIN",
571         "LOCPATH",
572         "MALLOC_TRACE",
573         "MALLOC_CHECK_",
574         "NIS_PATH",
575         "NLSPATH",
576         "RESOLV_HOST_CONF",
577         "RES_OPTIONS",
578         "TMPDIR",
579         "TZDIR",
580         "LD_AOUT_LIBRARY_PATH",
581         "LD_AOUT_PRELOAD",
582         // not listed in linker, used due to system() call
583         "IFS",
584     };
585     const char* const* cp   = unsec_vars;
586     const char* const* endp = cp + sizeof(unsec_vars)/sizeof(unsec_vars[0]);
587     while (cp < endp) {
588         unsetenv(*cp);
589         cp++;
590     }
591
592     /*
593      * set LD_LIBRARY_PATH if the linker has wiped out it due to we're suid.
594      * This occurs on Android 4.0+
595      */
596     setenv("LD_LIBRARY_PATH", "/vendor/lib:/system/lib", 0);
597
598     LOGD("su invoked.");
599
600     struct su_context ctx = {
601         .from = {
602             .pid = -1,
603             .uid = 0,
604             .bin = "",
605             .args = "",
606             .name = "",
607         },
608         .to = {
609             .uid = AID_ROOT,
610             .login = 0,
611             .keepenv = 0,
612             .shell = DEFAULT_SHELL,
613             .command = NULL,
614             .argv = argv,
615             .argc = argc,
616             .optind = 0,
617             .name = "",
618         },
619         .user = {
620             .android_user_id = 0,
621             .multiuser_mode = MULTIUSER_MODE_OWNER_ONLY,
622             .database_path = REQUESTOR_DATA_PATH REQUESTOR_DATABASE_PATH,
623             .base_path = REQUESTOR_DATA_PATH REQUESTOR
624         },
625     };
626     struct stat st;
627     int c, socket_serv_fd, fd;
628     char buf[64], *result;
629     policy_t dballow;
630     struct option long_opts[] = {
631         { "command",            required_argument,    NULL, 'c' },
632         { "help",            no_argument,        NULL, 'h' },
633         { "login",            no_argument,        NULL, 'l' },
634         { "preserve-environment",    no_argument,        NULL, 'p' },
635         { "shell",            required_argument,    NULL, 's' },
636         { "version",            no_argument,        NULL, 'v' },
637         { NULL, 0, NULL, 0 },
638     };
639
640     while ((c = getopt_long(argc, argv, "+c:hlmps:Vvu", long_opts, NULL)) != -1) {
641         switch(c) {
642         case 'c':
643             ctx.to.command = optarg;
644             break;
645         case 'h':
646             usage(EXIT_SUCCESS);
647             break;
648         case 'l':
649             ctx.to.login = 1;
650             break;
651         case 'm':
652         case 'p':
653             ctx.to.keepenv = 1;
654             break;
655         case 's':
656             ctx.to.shell = optarg;
657             break;
658         case 'V':
659             printf("%d\n", VERSION_CODE);
660             exit(EXIT_SUCCESS);
661         case 'v':
662             printf("%s\n", VERSION);
663             exit(EXIT_SUCCESS);
664         case 'u':
665             switch (get_multiuser_mode()) {
666             case MULTIUSER_MODE_USER:
667                 printf("%s\n", MULTIUSER_VALUE_USER);
668                 break;
669             case MULTIUSER_MODE_OWNER_MANAGED:
670                 printf("%s\n", MULTIUSER_VALUE_OWNER_MANAGED);
671                 break;
672             case MULTIUSER_MODE_OWNER_ONLY:
673                 printf("%s\n", MULTIUSER_VALUE_OWNER_ONLY);
674                 break;
675             case MULTIUSER_MODE_NONE:
676                 printf("%s\n", MULTIUSER_VALUE_NONE);
677                 break;
678             }
679             exit(EXIT_SUCCESS);
680         default:
681             /* Bionic getopt_long doesn't terminate its error output by newline */
682             fprintf(stderr, "\n");
683             usage(2);
684         }
685     }
686     if (optind < argc && !strcmp(argv[optind], "-")) {
687         ctx.to.login = 1;
688         optind++;
689     }
690     /* username or uid */
691     if (optind < argc && strcmp(argv[optind], "--")) {
692         struct passwd *pw;
693         pw = getpwnam(argv[optind]);
694         if (!pw) {
695             char *endptr;
696
697             /* It seems we shouldn't do this at all */
698             errno = 0;
699             ctx.to.uid = strtoul(argv[optind], &endptr, 10);
700             if (errno || *endptr) {
701                 LOGE("Unknown id: %s\n", argv[optind]);
702                 fprintf(stderr, "Unknown id: %s\n", argv[optind]);
703                 exit(EXIT_FAILURE);
704             }
705         } else {
706             ctx.to.uid = pw->pw_uid;
707             if (pw->pw_name)
708                 strncpy(ctx.to.name, pw->pw_name, sizeof(ctx.to.name));
709         }
710         optind++;
711     }
712     if (optind < argc && !strcmp(argv[optind], "--")) {
713         optind++;
714     }
715     ctx.to.optind = optind;
716
717     su_ctx = &ctx;
718     if (from_init(&ctx.from) < 0) {
719         deny(&ctx);
720     }
721         
722     read_options(&ctx);
723     user_init(&ctx);
724
725     // the latter two are necessary for stock ROMs like note 2 which do dumb things with su, or crash otherwise
726     if (ctx.from.uid == AID_ROOT || ctx.from.uid == AID_SYSTEM || ctx.from.uid == AID_RADIO) {
727         LOGD("Allowing root/system/radio.");
728         allow(&ctx);
729     }
730
731     // verify superuser is installed
732     if (stat(ctx.user.base_path, &st) < 0) {
733         // send to market (disabled, because people are and think this is hijacking their su)
734         // if (0 == strcmp(JAVA_PACKAGE_NAME, REQUESTOR))
735         //     silent_run("am start -d http://www.clockworkmod.com/superuser/install.html -a android.intent.action.VIEW");
736         PLOGE("stat %s", ctx.user.base_path);
737         deny(&ctx);
738     }
739
740     // odd perms on superuser data dir
741     if (st.st_gid != st.st_uid) {
742         LOGE("Bad uid/gid %d/%d for Superuser Requestor application",
743                 (int)st.st_uid, (int)st.st_gid);
744         deny(&ctx);
745     }
746
747     // always allow if this is the superuser uid
748     // superuser needs to be able to reenable itself when disabled...
749     if (ctx.from.uid == st.st_uid) {
750         allow(&ctx);
751     }
752
753     // check if superuser is disabled completely
754     if (access_disabled(&ctx.from)) {
755         LOGD("access_disabled");
756         deny(&ctx);
757     }
758
759     // autogrant shell at this point
760     if (ctx.from.uid == AID_SHELL) {
761         LOGD("Allowing shell.");
762         allow(&ctx);
763     }
764
765     // deny if this is a non owner request and owner mode only
766     if (ctx.user.multiuser_mode == MULTIUSER_MODE_OWNER_ONLY && ctx.user.android_user_id != 0) {
767         deny(&ctx);
768     }
769
770     ctx.umask = umask(027);
771
772     int ret = mkdir(REQUESTOR_CACHE_PATH, 0770);
773     if (chown(REQUESTOR_CACHE_PATH, st.st_uid, st.st_gid)) {
774         PLOGE("chown (%s, %ld, %ld)", REQUESTOR_CACHE_PATH, st.st_uid, st.st_gid);
775         deny(&ctx);
776     }
777
778     if (setgroups(0, NULL)) {
779         PLOGE("setgroups");
780         deny(&ctx);
781     }
782     if (setegid(st.st_gid)) {
783         PLOGE("setegid (%lu)", st.st_gid);
784         deny(&ctx);
785     }
786     if (seteuid(st.st_uid)) {
787         PLOGE("seteuid (%lu)", st.st_uid);
788         deny(&ctx);
789     }
790
791     dballow = database_check(&ctx);
792     switch (dballow) {
793         case INTERACTIVE:
794             break;
795         case ALLOW:
796             LOGD("db allowed");
797             allow(&ctx);    /* never returns */
798         case DENY:
799         default:
800             LOGD("db denied");
801             deny(&ctx);        /* never returns too */
802     }
803     
804     socket_serv_fd = socket_create_temp(ctx.sock_path, sizeof(ctx.sock_path));
805     LOGD(ctx.sock_path);
806     if (socket_serv_fd < 0) {
807         deny(&ctx);
808     }
809
810     signal(SIGHUP, cleanup_signal);
811     signal(SIGPIPE, cleanup_signal);
812     signal(SIGTERM, cleanup_signal);
813     signal(SIGQUIT, cleanup_signal);
814     signal(SIGINT, cleanup_signal);
815     signal(SIGABRT, cleanup_signal);
816
817     if (send_request(&ctx) < 0) {
818         deny(&ctx);
819     }
820
821     atexit(cleanup);
822
823     fd = socket_accept(socket_serv_fd);
824     if (fd < 0) {
825         deny(&ctx);
826     }
827     if (socket_send_request(fd, &ctx)) {
828         deny(&ctx);
829     }
830     if (socket_receive_result(fd, buf, sizeof(buf))) {
831         deny(&ctx);
832     }
833
834     close(fd);
835     close(socket_serv_fd);
836     socket_cleanup(&ctx);
837
838     result = buf;
839
840 #define SOCKET_RESPONSE    "socket:"
841     if (strncmp(result, SOCKET_RESPONSE, sizeof(SOCKET_RESPONSE) - 1))
842         LOGW("SECURITY RISK: Requestor still receives credentials in intent");
843     else
844         result += sizeof(SOCKET_RESPONSE) - 1;
845
846     if (!strcmp(result, "DENY")) {
847         deny(&ctx);
848     } else if (!strcmp(result, "ALLOW")) {
849         allow(&ctx);
850     } else {
851         LOGE("unknown response from Superuser Requestor: %s", result);
852         deny(&ctx);
853     }
854 }