OSDN Git Service

Improve logging code.
[android-x86/external-koush-Superuser.git] / Superuser / jni / su / daemon.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 #define _GNU_SOURCE /* for unshare() */
19
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <sys/un.h>
23 #include <sys/wait.h>
24 #include <sys/select.h>
25 #include <sys/time.h>
26 #include <unistd.h>
27 #include <limits.h>
28 #include <fcntl.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <getopt.h>
32 #include <stdint.h>
33 #include <pwd.h>
34 #include <sys/mount.h>
35 #include <sys/stat.h>
36 #include <stdarg.h>
37 #include <sys/types.h>
38 #include <pthread.h>
39 #include <sched.h>
40 #include <termios.h>
41
42 #ifdef SUPERUSER_EMBEDDED
43 #include <cutils/multiuser.h>
44 #endif
45
46 #include "su.h"
47 #include "utils.h"
48
49 int is_daemon = 0;
50 int daemon_from_uid = 0;
51 int daemon_from_pid = 0;
52
53 static int read_int(int fd) {
54     int val;
55     int len = read(fd, &val, sizeof(int));
56     if (len != sizeof(int)) {
57         LOGE("unable to read int");
58         exit(-1);
59     }
60     return val;
61 }
62
63 static void write_int(int fd, int val) {
64     int written = write(fd, &val, sizeof(int));
65     if (written != sizeof(int)) {
66         PLOGE("unable to write int");
67         exit(-1);
68     }
69 }
70
71 static char* read_string(int fd) {
72     int len = read_int(fd);
73     if (len > PATH_MAX || len < 0) {
74         LOGE("invalid string length %d", len);
75         exit(-1);
76     }
77     char* val = malloc(sizeof(char) * (len + 1));
78     if (val == NULL) {
79         LOGE("unable to malloc string");
80         exit(-1);
81     }
82     val[len] = '\0';
83     int amount = read(fd, val, len);
84     if (amount != len) {
85         LOGE("unable to read string");
86         exit(-1);
87     }
88     return val;
89 }
90
91 static void write_string(int fd, char* val) {
92     int len = strlen(val);
93     write_int(fd, len);
94     int written = write(fd, val, len);
95     if (written != len) {
96         PLOGE("unable to write string");
97         exit(-1);
98     }
99 }
100
101 #ifdef SUPERUSER_EMBEDDED
102 static void mount_emulated_storage(int user_id) {
103     const char *emulated_source = getenv("EMULATED_STORAGE_SOURCE");
104     const char *emulated_target = getenv("EMULATED_STORAGE_TARGET");
105     const char* legacy = getenv("EXTERNAL_STORAGE");
106
107     if (!emulated_source || !emulated_target) {
108         // No emulated storage is present
109         return;
110     }
111
112     // Create a second private mount namespace for our process
113     if (unshare(CLONE_NEWNS) < 0) {
114         PLOGE("unshare");
115         return;
116     }
117
118     if (mount("rootfs", "/", NULL, MS_SLAVE | MS_REC, NULL) < 0) {
119         PLOGE("mount rootfs as slave");
120         return;
121     }
122
123     // /mnt/shell/emulated -> /storage/emulated
124     if (mount(emulated_source, emulated_target, NULL, MS_BIND, NULL) < 0) {
125         PLOGE("mount emulated storage");
126     }
127
128     char target_user[PATH_MAX];
129     snprintf(target_user, PATH_MAX, "%s/%d", emulated_target, user_id);
130
131     // /mnt/shell/emulated/<user> -> /storage/emulated/legacy
132     if (mount(target_user, legacy, NULL, MS_BIND | MS_REC, NULL) < 0) {
133         PLOGE("mount legacy path");
134     }
135 }
136 #endif
137
138 static int run_daemon_child(int infd, int outfd, int errfd, int argc, char** argv) {
139     if (-1 == dup2(outfd, STDOUT_FILENO)) {
140         PLOGE("dup2 child outfd");
141         exit(-1);
142     }
143
144     if (-1 == dup2(errfd, STDERR_FILENO)) {
145         PLOGE("dup2 child errfd");
146         exit(-1);
147     }
148
149     if (-1 == dup2(infd, STDIN_FILENO)) {
150         PLOGE("dup2 child infd");
151         exit(-1);
152     }
153
154     close(infd);
155     close(outfd);
156     close(errfd);
157
158     return su_main(argc, argv, 0);
159 }
160
161 static void pump(int input, int output) {
162     char buf[4096];
163     int len;
164     while ((len = read(input, buf, 4096)) > 0) {
165         write(output, buf, len);
166     }
167     close(input);
168     close(output);
169 }
170
171 static void* pump_thread(void* data) {
172     int* files = (int*)data;
173     int input = files[0];
174     int output = files[1];
175     pump(input, output);
176     free(data);
177     return NULL;
178 }
179
180 static void pump_async(int input, int output) {
181     pthread_t writer;
182     int* files = (int*)malloc(sizeof(int) * 2);
183     if (files == NULL) {
184         LOGE("unable to pump_async");
185         exit(-1);
186     }
187     files[0] = input;
188     files[1] = output;
189     pthread_create(&writer, NULL, pump_thread, files);
190 }
191
192 static int daemon_accept(int fd) {
193     is_daemon = 1;
194     int pid = read_int(fd);
195     LOGV("remote pid: %d", pid);
196     int atty = read_int(fd);
197     LOGV("remote atty: %d", atty);
198     daemon_from_uid = read_int(fd);
199     LOGV("remote uid: %d", daemon_from_uid);
200     daemon_from_pid = read_int(fd);
201     LOGV("remote req pid: %d", daemon_from_pid);
202
203     struct ucred credentials;
204     int ucred_length = sizeof(struct ucred);
205     /* fill in the user data structure */
206     if(getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &credentials, &ucred_length)) {
207         LOGE("could obtain credentials from unix domain socket");
208         exit(-1);
209     }
210     // if the credentials on the other side of the wire are NOT root,
211     // we can't trust anything being sent.
212     if (credentials.uid != 0) {
213         daemon_from_uid = credentials.uid;
214         pid = credentials.pid;
215         daemon_from_pid = credentials.pid;
216     }
217
218     int mount_storage = read_int(fd);
219     int argc = read_int(fd);
220     if (argc < 0 || argc > 512) {
221         LOGE("unable to allocate args: %d", argc);
222         exit(-1);
223     }
224     LOGV("remote args: %d", argc);
225     char** argv = (char**)malloc(sizeof(char*) * (argc + 1));
226     argv[argc] = NULL;
227     int i;
228     for (i = 0; i < argc; i++) {
229         argv[i] = read_string(fd);
230     }
231
232     char errfile[PATH_MAX];
233     char outfile[PATH_MAX];
234     char infile[PATH_MAX];
235     sprintf(outfile, "%s/%d.stdout", REQUESTOR_DAEMON_PATH, pid);
236     sprintf(errfile, "%s/%d.stderr", REQUESTOR_DAEMON_PATH, pid);
237     sprintf(infile, "%s/%d.stdin", REQUESTOR_DAEMON_PATH, pid);
238
239     if (mkfifo(outfile, 0660) != 0) {
240         PLOGE("mkfifo %s", outfile);
241         exit(-1);
242     }
243     if (mkfifo(errfile, 0660) != 0) {
244         PLOGE("mkfifo %s", errfile);
245         exit(-1);
246     }
247     if (mkfifo(infile, 0660) != 0) {
248         PLOGE("mkfifo %s", infile);
249         exit(-1);
250     }
251
252     chown(outfile, daemon_from_uid, 0);
253     chown(infile, daemon_from_uid, 0);
254     chown(errfile, daemon_from_uid, 0);
255     chmod(outfile, 0660);
256     chmod(infile, 0660);
257     chmod(errfile, 0660);
258
259     // ack
260     write_int(fd, 1);
261
262     int ptm = -1;
263     char* devname = NULL;
264     if (atty) {
265         ptm = open("/dev/ptmx", O_RDWR);
266         if (ptm <= 0) {
267             PLOGE("ptm");
268             exit(-1);
269         }
270         if(grantpt(ptm) || unlockpt(ptm) || ((devname = (char*) ptsname(ptm)) == 0)) {
271             PLOGE("ptm setup");
272             close(ptm);
273             exit(-1);
274         }
275         LOGV("devname: %s", devname);
276     }
277
278     int outfd = open(outfile, O_WRONLY);
279     if (outfd <= 0) {
280         PLOGE("outfd daemon %s", outfile);
281         goto done;
282     }
283     int errfd = open(errfile, O_WRONLY);
284     if (errfd <= 0) {
285         PLOGE("errfd daemon %s", errfile);
286         goto done;
287     }
288     int infd = open(infile, O_RDONLY);
289     if (infd <= 0) {
290         PLOGE("infd daemon %s", infile);
291         goto done;
292     }
293
294     int code;
295     // now fork and run main, watch for the child pid exit, and send that
296     // across the control channel as the response.
297     int child = fork();
298     if (child < 0) {
299         code = child;
300         goto done;
301     }
302
303     // if this is the child, open the fifo streams
304     // and dup2 them with stdin/stdout, and run main, which execs
305     // the target.
306     if (child == 0) {
307         close(fd);
308
309         if (devname != NULL) {
310             int pts = open(devname, O_RDWR);
311             if(pts < 0) {
312                 PLOGE("pts");
313                 exit(-1);
314             }
315
316             struct termios slave_orig_term_settings; // Saved terminal settings 
317             tcgetattr(pts, &slave_orig_term_settings);
318
319             struct termios new_term_settings;
320             new_term_settings = slave_orig_term_settings; 
321             cfmakeraw(&new_term_settings);
322             // WHY DOESN'T THIS WORK, FUUUUU
323             new_term_settings.c_lflag &= ~(ECHO);
324             tcsetattr(pts, TCSANOW, &new_term_settings);
325
326             setsid();
327             ioctl(pts, TIOCSCTTY, 1);
328
329             close(infd);
330             close(outfd);
331             close(errfd);
332             close(ptm);
333
334             errfd = pts;
335             infd = pts;
336             outfd = pts;
337         }
338
339 #ifdef SUPERUSER_EMBEDDED
340         if (mount_storage) {
341             mount_emulated_storage(multiuser_get_user_id(daemon_from_uid));
342         }
343 #endif
344
345         return run_daemon_child(infd, outfd, errfd, argc, argv);
346     }
347
348     if (devname != NULL) {
349         // pump ptm across the socket
350         pump_async(infd, ptm);
351         pump(ptm, outfd);
352     }
353     else {
354         close(infd);
355         close(outfd);
356         close(errfd);
357     }
358
359     // wait for the child to exit, and send the exit code
360     // across the wire.
361     int status;
362     LOGV("waiting for child exit");
363     if (waitpid(child, &status, 0) > 0) {
364         code = WEXITSTATUS(status);
365     }
366     else {
367         code = -1;
368     }
369
370 done:
371     write(fd, &code, sizeof(int));
372     close(fd);
373     LOGV("child exited");
374     return code;
375 }
376
377 int run_daemon() {
378     if (getuid() != 0 || getgid() != 0) {
379         PLOGE("daemon requires root. uid/gid not root");
380         return -1;
381     }
382
383     int fd;
384     struct sockaddr_un sun;
385
386     fd = socket(AF_LOCAL, SOCK_STREAM, 0);
387     if (fd < 0) {
388         PLOGE("socket");
389         return -1;
390     }
391     if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
392         PLOGE("fcntl FD_CLOEXEC");
393         goto err;
394     }
395
396     memset(&sun, 0, sizeof(sun));
397     sun.sun_family = AF_LOCAL;
398     sprintf(sun.sun_path, "%s/server", REQUESTOR_DAEMON_PATH);
399
400     /*
401      * Delete the socket to protect from situations when
402      * something bad occured previously and the kernel reused pid from that process.
403      * Small probability, isn't it.
404      */
405     unlink(sun.sun_path);
406     unlink(REQUESTOR_DAEMON_PATH);
407
408     int previous_umask = umask(027);
409     mkdir(REQUESTOR_DAEMON_PATH, 0777);
410
411     if (bind(fd, (struct sockaddr*)&sun, sizeof(sun)) < 0) {
412         PLOGE("daemon bind");
413         goto err;
414     }
415
416     chmod(REQUESTOR_DAEMON_PATH, 0755);
417     chmod(sun.sun_path, 0777);
418
419     umask(previous_umask);
420
421     if (listen(fd, 10) < 0) {
422         PLOGE("daemon listen");
423         goto err;
424     }
425
426     int client;
427     while ((client = accept(fd, NULL, NULL)) > 0) {
428         if (fork_zero_fucks() == 0) {
429             close(fd);
430             return daemon_accept(client);
431         }
432         else {
433             close(client);
434         }
435     }
436
437     LOGE("daemon exiting");
438 err:
439     close(fd);
440     return -1;
441 }
442
443 int connect_daemon(int argc, char *argv[]) {
444     char errfile[PATH_MAX];
445     char outfile[PATH_MAX];
446     char infile[PATH_MAX];
447     int uid = getuid();
448     sprintf(outfile, "%s/%d.stdout", REQUESTOR_DAEMON_PATH, getpid());
449     sprintf(errfile, "%s/%d.stderr", REQUESTOR_DAEMON_PATH, getpid());
450     sprintf(infile, "%s/%d.stdin", REQUESTOR_DAEMON_PATH, getpid());
451     unlink(errfile);
452     unlink(infile);
453     unlink(outfile);
454
455     struct sockaddr_un sun;
456
457     int socketfd = socket(AF_LOCAL, SOCK_STREAM, 0);
458     if (socketfd < 0) {
459         PLOGE("socket");
460         exit(-1);
461     }
462     if (fcntl(socketfd, F_SETFD, FD_CLOEXEC)) {
463         PLOGE("fcntl FD_CLOEXEC");
464         exit(-1);
465     }
466
467     memset(&sun, 0, sizeof(sun));
468     sun.sun_family = AF_LOCAL;
469     sprintf(sun.sun_path, "%s/server", REQUESTOR_DAEMON_PATH);
470
471     if (0 != connect(socketfd, (struct sockaddr*)&sun, sizeof(sun))) {
472         PLOGE("connect");
473         exit(-1);
474     }
475
476     LOGV("connecting client %d", getpid());
477
478     int mount_storage = getenv("MOUNT_EMULATED_STORAGE") != NULL;
479
480     write_int(socketfd, getpid());
481     write_int(socketfd, isatty(STDIN_FILENO));
482     write_int(socketfd, uid);
483     write_int(socketfd, getppid());
484     write_int(socketfd, mount_storage);
485     write_int(socketfd, mount_storage ? argc - 1 : argc);
486
487     int i;
488     for (i = 0; i < argc; i++) {
489         if (i == 1 && mount_storage) {
490             continue;
491         }
492         write_string(socketfd, argv[i]);
493     }
494
495     // ack
496     read_int(socketfd);
497
498     int outfd = open(outfile, O_RDONLY);
499     if (outfd <= 0) {
500         PLOGE("outfd %s ", outfile);
501         exit(-1);
502     }
503     int errfd = open(errfile, O_RDONLY);
504     if (errfd <= 0) {
505         PLOGE("errfd %s", errfile);
506         exit(-1);
507     }
508     int infd = open(infile, O_WRONLY);
509     if (infd <= 0) {
510         PLOGE("infd %s", infile);
511         exit(-1);
512     }
513
514     pump_async(STDIN_FILENO, infd);
515     pump_async(errfd, STDERR_FILENO);
516     pump(outfd, STDOUT_FILENO);
517
518     int code = read_int(socketfd);
519     LOGV("client exited %d", code);
520     return code;
521 }