static int daemon_accept(int fd) { is_daemon = 1; int pid = read_int(fd); LOGD("remote pid: %d", pid); char *pts_slave = read_string(fd); LOGD("remote pts_slave: %s", pts_slave); daemon_from_uid = read_int(fd); LOGD("remote uid: %d", daemon_from_uid); daemon_from_pid = read_int(fd); LOGD("remote req pid: %d", daemon_from_pid); struct ucred credentials; int ucred_length = sizeof(struct ucred); /* fill in the user data structure */ if(getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &credentials, &ucred_length)) { LOGE("could obtain credentials from unix domain socket"); exit(-1); } // if the credentials on the other side of the wire are NOT root, // we can't trust anything being sent. if (credentials.uid != 0) { daemon_from_uid = credentials.uid; pid = credentials.pid; daemon_from_pid = credentials.pid; } int mount_storage = read_int(fd); // The the FDs for each of the streams int infd = recv_fd(fd); int outfd = recv_fd(fd); int errfd = recv_fd(fd); int argc = read_int(fd); if (argc < 0 || argc > 512) { LOGE("unable to allocate args: %d", argc); exit(-1); } LOGD("remote args: %d", argc); char** argv = (char**)malloc(sizeof(char*) * (argc + 1)); argv[argc] = NULL; int i; for (i = 0; i < argc; i++) { argv[i] = read_string(fd); } // ack write_int(fd, 1); // Fork the child process. The fork has to happen before calling // setsid() and opening the pseudo-terminal so that the parent // is not affected int child = fork(); if (child < 0) { // fork failed, send a return code and bail out PLOGE("unable to fork"); write(fd, &child, sizeof(int)); close(fd); return child; } if (child != 0) { // In parent, wait for the child to exit, and send the exit code // across the wire. int status, code; free(pts_slave); LOGD("waiting for child exit"); if (waitpid(child, &status, 0) > 0) { code = WEXITSTATUS(status); } else { code = -1; } // Pass the return code back to the client LOGD("sending code"); if (write(fd, &code, sizeof(int)) != sizeof(int)) { PLOGE("unable to write exit code"); } close(fd); LOGD("child exited"); return code; } // We are in the child now // Close the unix socket file descriptor close (fd); // Become session leader if (setsid() == (pid_t) -1) { PLOGE("setsid"); } int ptsfd; if (pts_slave[0]) { // Opening the TTY has to occur after the // fork() and setsid() so that it becomes // our controlling TTY and not the daemon's ptsfd = open(pts_slave, O_RDWR); if (ptsfd == -1) { PLOGE("open(pts_slave) daemon"); exit(-1); } if (infd < 0) { LOGD("daemon: stdin using PTY"); infd = ptsfd; } if (outfd < 0) { LOGD("daemon: stdout using PTY"); outfd = ptsfd; } if (errfd < 0) { LOGD("daemon: stderr using PTY"); errfd = ptsfd; } } else { // If a TTY was sent directly, make it the CTTY. if (isatty(infd)) { ioctl(infd, TIOCSCTTY, 1); } } free(pts_slave); #ifdef SUPERUSER_EMBEDDED if (mount_storage) { mount_emulated_storage(multiuser_get_user_id(daemon_from_uid)); } #endif return run_daemon_child(infd, outfd, errfd, argc, argv); }
gid_t multiuser_get_shared_app_gid(uid_t uid) { return multiuser_get_shared_gid(multiuser_get_user_id(uid), multiuser_get_app_id(uid)); }
static int daemon_accept(int fd) { is_daemon = 1; int pid = read_int(fd); LOGD("remote pid: %d", pid); int atty = read_int(fd); LOGD("remote atty: %d", atty); daemon_from_uid = read_int(fd); LOGD("remote uid: %d", daemon_from_uid); daemon_from_pid = read_int(fd); LOGD("remote req pid: %d", daemon_from_pid); struct ucred credentials; int ucred_length = sizeof(struct ucred); /* fill in the user data structure */ if(getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &credentials, &ucred_length)) { LOGE("could obtain credentials from unix domain socket"); exit(-1); } // if the credentials on the other side of the wire are NOT root, // we can't trust anything being sent. if (credentials.uid != 0) { daemon_from_uid = credentials.uid; pid = credentials.pid; daemon_from_pid = credentials.pid; } int mount_storage = read_int(fd); int argc = read_int(fd); if (argc < 0 || argc > 512) { LOGE("unable to allocate args: %d", argc); exit(-1); } LOGD("remote args: %d", argc); char** argv = (char**)malloc(sizeof(char*) * (argc + 1)); argv[argc] = NULL; int i; for (i = 0; i < argc; i++) { argv[i] = read_string(fd); } char errfile[PATH_MAX]; char outfile[PATH_MAX]; char infile[PATH_MAX]; sprintf(outfile, "%s/%d.stdout", REQUESTOR_DAEMON_PATH, pid); sprintf(errfile, "%s/%d.stderr", REQUESTOR_DAEMON_PATH, pid); sprintf(infile, "%s/%d.stdin", REQUESTOR_DAEMON_PATH, pid); if (mkfifo(outfile, 0660) != 0) { PLOGE("mkfifo %s", outfile); exit(-1); } if (mkfifo(errfile, 0660) != 0) { PLOGE("mkfifo %s", errfile); exit(-1); } if (mkfifo(infile, 0660) != 0) { PLOGE("mkfifo %s", infile); exit(-1); } chown(outfile, daemon_from_uid, 0); chown(infile, daemon_from_uid, 0); chown(errfile, daemon_from_uid, 0); chmod(outfile, 0660); chmod(infile, 0660); chmod(errfile, 0660); // ack write_int(fd, 1); int ptm = -1; char* devname = NULL; if (atty) { ptm = open("/dev/ptmx", O_RDWR); if (ptm <= 0) { PLOGE("ptm"); exit(-1); } if(grantpt(ptm) || unlockpt(ptm) || ((devname = (char*) ptsname(ptm)) == 0)) { PLOGE("ptm setup"); close(ptm); exit(-1); } LOGD("devname: %s", devname); } int outfd = open(outfile, O_WRONLY); if (outfd <= 0) { PLOGE("outfd daemon %s", outfile); goto done; } int errfd = open(errfile, O_WRONLY); if (errfd <= 0) { PLOGE("errfd daemon %s", errfile); goto done; } int infd = open(infile, O_RDONLY); if (infd <= 0) { PLOGE("infd daemon %s", infile); goto done; } int code; // now fork and run main, watch for the child pid exit, and send that // across the control channel as the response. int child = fork(); if (child < 0) { code = child; goto done; } // if this is the child, open the fifo streams // and dup2 them with stdin/stdout, and run main, which execs // the target. if (child == 0) { close(fd); if (devname != NULL) { int pts = open(devname, O_RDWR); if(pts < 0) { PLOGE("pts"); exit(-1); } struct termios slave_orig_term_settings; // Saved terminal settings tcgetattr(pts, &slave_orig_term_settings); struct termios new_term_settings; new_term_settings = slave_orig_term_settings; cfmakeraw(&new_term_settings); // WHY DOESN'T THIS WORK, FUUUUU new_term_settings.c_lflag &= ~(ECHO); tcsetattr(pts, TCSANOW, &new_term_settings); setsid(); ioctl(pts, TIOCSCTTY, 1); close(infd); close(outfd); close(errfd); close(ptm); errfd = pts; infd = pts; outfd = pts; } #ifdef SUPERUSER_EMBEDEDED if (mount_storage) { mount_emulated_storage(multiuser_get_user_id(daemon_from_uid)); } #endif return run_daemon_child(infd, outfd, errfd, argc, argv); } if (devname != NULL) { // pump ptm across the socket pump_async(infd, ptm); pump(ptm, outfd); } else { close(infd); close(outfd); close(errfd); } // wait for the child to exit, and send the exit code // across the wire. int status; LOGD("waiting for child exit"); if (waitpid(child, &status, 0) > 0) { code = WEXITSTATUS(status); } else { code = -1; } done: write(fd, &code, sizeof(int)); close(fd); LOGD("child exited"); return code; }