OSDN Git Service

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