This got back in somehow. It is defined in our extras/su repo.
Change-Id: Ic109ab15585dd22d16eef377fab64e0f82919d49
+++ /dev/null
-bin
-armeabi
-x86
-obj
-local.properties
-gen
-.DS_Store
-.settings
-libs
+++ /dev/null
-Copyright 2013 Koushik Dutta (2013)
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
\ No newline at end of file
+++ /dev/null
-#define LOG_TAG "su"
-
-#include <binder/AppOpsManager.h>
-#include <utils/Log.h>
-
-using namespace android;
-
-extern "C" {
-
-int appops_start_op_su(int uid, const char *pkgName) {
- ALOGD("Checking whether app [uid:%d, pkgName: %s] is allowed to be root", uid, pkgName);
- AppOpsManager *ops = new AppOpsManager();
-
- int mode = ops->startOp(AppOpsManager::OP_SU, uid, String16(pkgName));
-
- switch (mode) {
- case AppOpsManager::MODE_ALLOWED:
- ALOGD("Privilege elevation allowed by appops");
- return 0;
- default:
- ALOGD("Privilege elevation denied by appops");
- return 1;
- }
-
- delete ops;
-}
-
-void appops_finish_op_su(int uid, const char *pkgName) {
- ALOGD("Finishing su operation for app [uid:%d, pkgName: %s]", uid, pkgName);
- AppOpsManager *ops = new AppOpsManager();
- ops->finishOp(AppOpsManager::OP_SU, uid, String16(pkgName));
- delete ops;
-}
-
-}
+++ /dev/null
-#include "../utils.h"
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <utils/Log.h>
-
-#define PACKAGE_LIST_PATH "/data/system/packages.list"
-#define PACKAGE_NAME_MAX_LEN (1<<16)
-
-/* Tries to resolve a package name from a uid via the packages list file.
- *
- * If there is no matching uid, it will return an empty string which can
- * be resolved by appops in some cases (i.e. apps with uid = 0, uid = AID_SHELL).
- *
- * Since packages may share UID, this function will return the first present
- * in packages.list.
- */
-const char* resolve_package_name(int uid) {
- char *packages = read_file(PACKAGE_LIST_PATH);
-
- if (packages == NULL) {
- goto notfound;
- }
-
- char *p = packages;
- while (*p) {
- char *line_end = strstr(p, "\n");
- if (line_end == NULL)
- break;
-
- char *token;
- char *pkgName = strtok_r(p, " ", &token);
- if (pkgName != NULL) {
- char *pkgUid = strtok_r(NULL, " ", &token);
- if (pkgUid != NULL) {
- char *endptr;
- errno = 0;
- int pkgUidInt = strtoul(pkgUid, &endptr, 10);
- if ((errno == 0 && endptr != NULL && !(*endptr)) && pkgUidInt == uid)
- return strdup(pkgName);
- }
- }
- p = ++line_end;
- }
- free(packages);
-
-notfound:
- return "";
-}
+++ /dev/null
-#ifndef _HAS_PM_WRAPPER_H
-#define _HAS_PM_WRAPPER_H
-
-const char* resolve_package_name(int uid);
-
-#endif
+++ /dev/null
-/*
-** Copyright 2010, Adam Shanks (@ChainsDD)
-** Copyright 2008, Zinx Verituse (@zinxv)
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#define _GNU_SOURCE /* for unshare() */
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/wait.h>
-#include <sys/select.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include <stdint.h>
-#include <pwd.h>
-#include <sys/mount.h>
-#include <sys/stat.h>
-#include <stdarg.h>
-#include <sys/types.h>
-#include <pthread.h>
-#include <sched.h>
-#include <termios.h>
-#include <signal.h>
-#include <string.h>
-#include <log/log.h>
-
-#include <cutils/multiuser.h>
-
-#include "su.h"
-#include "utils.h"
-#include "pts.h"
-
-int is_daemon = 0;
-int daemon_from_uid = 0;
-int daemon_from_pid = 0;
-
-// Constants for the atty bitfield
-#define ATTY_IN 1
-#define ATTY_OUT 2
-#define ATTY_ERR 4
-
-/*
- * Receive a file descriptor from a Unix socket.
- * Contributed by @mkasick
- *
- * Returns the file descriptor on success, or -1 if a file
- * descriptor was not actually included in the message
- *
- * On error the function terminates by calling exit(-1)
- */
-static int recv_fd(int sockfd) {
- // Need to receive data from the message, otherwise don't care about it.
- char iovbuf;
-
- struct iovec iov = {
- .iov_base = &iovbuf,
- .iov_len = 1,
- };
-
- char cmsgbuf[CMSG_SPACE(sizeof(int))];
-
- struct msghdr msg = {
- .msg_iov = &iov,
- .msg_iovlen = 1,
- .msg_control = cmsgbuf,
- .msg_controllen = sizeof(cmsgbuf),
- };
-
- if (recvmsg(sockfd, &msg, MSG_WAITALL) != 1) {
- goto error;
- }
-
- // Was a control message actually sent?
- switch (msg.msg_controllen) {
- case 0:
- // No, so the file descriptor was closed and won't be used.
- return -1;
- case sizeof(cmsgbuf):
- // Yes, grab the file descriptor from it.
- break;
- default:
- goto error;
- }
-
- struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
-
- if (cmsg == NULL ||
- cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
- cmsg->cmsg_level != SOL_SOCKET ||
- cmsg->cmsg_type != SCM_RIGHTS) {
-error:
- ALOGE("unable to read fd");
- exit(-1);
- }
-
- return *(int *)CMSG_DATA(cmsg);
-}
-
-/*
- * Send a file descriptor through a Unix socket.
- * Contributed by @mkasick
- *
- * On error the function terminates by calling exit(-1)
- *
- * fd may be -1, in which case the dummy data is sent,
- * but no control message with the FD is sent.
- */
-static void send_fd(int sockfd, int fd) {
- // Need to send some data in the message, this will do.
- struct iovec iov = {
- .iov_base = "",
- .iov_len = 1,
- };
-
- struct msghdr msg = {
- .msg_iov = &iov,
- .msg_iovlen = 1,
- };
-
- char cmsgbuf[CMSG_SPACE(sizeof(int))];
-
- if (fd != -1) {
- // Is the file descriptor actually open?
- if (fcntl(fd, F_GETFD) == -1) {
- if (errno != EBADF) {
- goto error;
- }
- // It's closed, don't send a control message or sendmsg will EBADF.
- } else {
- // It's open, send the file descriptor in a control message.
- msg.msg_control = cmsgbuf;
- msg.msg_controllen = sizeof(cmsgbuf);
-
- struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
-
- cmsg->cmsg_len = CMSG_LEN(sizeof(int));
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
-
- *(int *)CMSG_DATA(cmsg) = fd;
- }
- }
-
- if (sendmsg(sockfd, &msg, 0) != 1) {
-error:
- PLOGE("unable to send fd");
- exit(-1);
- }
-}
-
-static int read_int(int fd) {
- int val;
- int len = read(fd, &val, sizeof(int));
- if (len != sizeof(int)) {
- ALOGE("unable to read int: %d", len);
- exit(-1);
- }
- return val;
-}
-
-static void write_int(int fd, int val) {
- int written = write(fd, &val, sizeof(int));
- if (written != sizeof(int)) {
- PLOGE("unable to write int");
- exit(-1);
- }
-}
-
-static char* read_string(int fd) {
- int len = read_int(fd);
- if (len > PATH_MAX || len < 0) {
- ALOGE("invalid string length %d", len);
- exit(-1);
- }
- char* val = malloc(sizeof(char) * (len + 1));
- if (val == NULL) {
- ALOGE("unable to malloc string");
- exit(-1);
- }
- val[len] = '\0';
- int amount = read(fd, val, len);
- if (amount != len) {
- ALOGE("unable to read string");
- exit(-1);
- }
- return val;
-}
-
-static void write_string(int fd, char* val) {
- int len = strlen(val);
- write_int(fd, len);
- int written = write(fd, val, len);
- if (written != len) {
- PLOGE("unable to write string");
- exit(-1);
- }
-}
-
-static void mount_emulated_storage(int user_id) {
- const char *emulated_source = getenv("EMULATED_STORAGE_SOURCE");
- const char *emulated_target = getenv("EMULATED_STORAGE_TARGET");
- const char* legacy = getenv("EXTERNAL_STORAGE");
-
- if (!emulated_source || !emulated_target) {
- // No emulated storage is present
- return;
- }
-
- // Create a second private mount namespace for our process
- if (unshare(CLONE_NEWNS) < 0) {
- PLOGE("unshare");
- return;
- }
-
- if (mount("rootfs", "/", NULL, MS_SLAVE | MS_REC, NULL) < 0) {
- PLOGE("mount rootfs as slave");
- return;
- }
-
- // /mnt/shell/emulated -> /storage/emulated
- if (mount(emulated_source, emulated_target, NULL, MS_BIND, NULL) < 0) {
- PLOGE("mount emulated storage");
- }
-
- char target_user[PATH_MAX];
- snprintf(target_user, PATH_MAX, "%s/%d", emulated_target, user_id);
-
- // /mnt/shell/emulated/<user> -> /storage/emulated/legacy
- if (mount(target_user, legacy, NULL, MS_BIND | MS_REC, NULL) < 0) {
- PLOGE("mount legacy path");
- }
-}
-
-static int run_daemon_child(int infd, int outfd, int errfd, int argc, char** argv) {
- if (-1 == dup2(outfd, STDOUT_FILENO)) {
- PLOGE("dup2 child outfd");
- exit(-1);
- }
-
- if (-1 == dup2(errfd, STDERR_FILENO)) {
- PLOGE("dup2 child errfd");
- exit(-1);
- }
-
- if (-1 == dup2(infd, STDIN_FILENO)) {
- PLOGE("dup2 child infd");
- exit(-1);
- }
-
- close(infd);
- close(outfd);
- close(errfd);
-
- return su_main(argc, argv, 0);
-}
-
-static int daemon_accept(int fd) {
- char mypath[PATH_MAX], remotepath[PATH_MAX];
- int caller_is_self = 0;
-
- is_daemon = 1;
- int pid = read_int(fd);
- int child_result;
- ALOGD("remote pid: %d", pid);
- char *pts_slave = read_string(fd);
- ALOGD("remote pts_slave: %s", pts_slave);
- daemon_from_pid = read_int(fd);
- ALOGV("remote req pid: %d", daemon_from_pid);
-
- struct ucred credentials;
- socklen_t ucred_length = sizeof(struct ucred);
- /* fill in the user data structure */
- if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &credentials, &ucred_length)) {
- ALOGE("could obtain credentials from unix domain socket");
- exit(-1);
- }
-
- daemon_from_uid = credentials.uid;
-
- 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) {
- ALOGE("unable to allocate args: %d", argc);
- exit(-1);
- }
- ALOGV("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) {
- for (i = 0; i < argc; i++) {
- free(argv[i]);
- }
- free(argv);
-
- // 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) {
- for (i = 0; i < argc; i++) {
- free(argv[i]);
- }
- free(argv);
-
- // In parent, wait for the child to exit, and send the exit code
- // across the wire.
- int status, code;
-
- free(pts_slave);
-
- ALOGD("waiting for child exit");
- if (waitpid(child, &status, 0) > 0) {
- code = WEXITSTATUS(status);
- }
- else {
- code = -1;
- }
-
- // Is the file descriptor actually open?
- if (fcntl(fd, F_GETFD) == -1) {
- if (errno != EBADF) {
- goto error;
- }
- }
-
- // Pass the return code back to the client
- ALOGD("sending code");
- if (write(fd, &code, sizeof(int)) != sizeof(int)) {
- PLOGE("unable to write exit code");
- }
-
- close(fd);
-error:
- ALOGD("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);
- }
-
- struct stat st;
- if (fstat(ptsfd, &st)) {
- PLOGE("failed to stat pts_slave");
- exit(-1);
- }
-
- if (st.st_uid != credentials.uid) {
- PLOGE("caller doesn't own proposed PTY");
- exit(-1);
- }
-
- if (!S_ISCHR(st.st_mode)) {
- PLOGE("proposed PTY isn't a chardev");
- exit(-1);
- }
-
- if (infd < 0) {
- ALOGD("daemon: stdin using PTY");
- infd = ptsfd;
- }
- if (outfd < 0) {
- ALOGD("daemon: stdout using PTY");
- outfd = ptsfd;
- }
- if (errfd < 0) {
- ALOGD("daemon: stderr using PTY");
- errfd = ptsfd;
- }
- } else {
- // TODO: Check system property, if PTYs are disabled,
- // made infd the CTTY using:
- // ioctl(infd, TIOCSCTTY, 1);
- }
- free(pts_slave);
-
- if (mount_storage) {
- mount_emulated_storage(multiuser_get_user_id(daemon_from_uid));
- }
-
- child_result = run_daemon_child(infd, outfd, errfd, argc, argv);
- for (i = 0; i < argc; i++) {
- free(argv[i]);
- }
- free(argv);
- return child_result;
-}
-
-int run_daemon() {
- if (getuid() != 0 || getgid() != 0) {
- PLOGE("daemon requires root. uid/gid not root");
- return -1;
- }
-
- int fd;
- struct sockaddr_un sun;
-
- fd = socket(AF_LOCAL, SOCK_STREAM, 0);
- if (fd < 0) {
- PLOGE("socket");
- return -1;
- }
- if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
- PLOGE("fcntl FD_CLOEXEC");
- goto err;
- }
-
- memset(&sun, 0, sizeof(sun));
- sun.sun_family = AF_LOCAL;
- sprintf(sun.sun_path, "%s/su-daemon", DAEMON_SOCKET_PATH);
-
- /*
- * Delete the socket to protect from situations when
- * something bad occured previously and the kernel reused pid from that process.
- * Small probability, isn't it.
- */
- unlink(sun.sun_path);
- unlink(DAEMON_SOCKET_PATH);
-
- int previous_umask = umask(027);
- mkdir(DAEMON_SOCKET_PATH, 0711);
-
- if (bind(fd, (struct sockaddr*)&sun, sizeof(sun)) < 0) {
- PLOGE("daemon bind");
- goto err;
- }
-
- chmod(DAEMON_SOCKET_PATH, 0711);
- chmod(sun.sun_path, 0666);
-
- umask(previous_umask);
-
- if (listen(fd, 10) < 0) {
- PLOGE("daemon listen");
- goto err;
- }
-
- int client;
- while ((client = accept(fd, NULL, NULL)) > 0) {
- if (fork_zero_fucks() == 0) {
- close(fd);
- return daemon_accept(client);
- }
- else {
- close(client);
- }
- }
-
- ALOGE("daemon exiting");
-err:
- close(fd);
- return -1;
-}
-
-// List of signals which cause process termination
-static int quit_signals[] = { SIGALRM, SIGHUP, SIGPIPE, SIGQUIT, SIGTERM, SIGINT, 0 };
-
-static void sighandler(__attribute__ ((unused)) int sig) {
- restore_stdin();
-
- // Assume we'll only be called before death
- // See note before sigaction() in set_stdin_raw()
- //
- // Now, close all standard I/O to cause the pumps
- // to exit so we can continue and retrieve the exit
- // code
- close(STDIN_FILENO);
- close(STDOUT_FILENO);
- close(STDERR_FILENO);
-
- // Put back all the default handlers
- struct sigaction act;
- int i;
-
- memset(&act, '\0', sizeof(act));
- act.sa_handler = SIG_DFL;
- for (i = 0; quit_signals[i]; i++) {
- if (sigaction(quit_signals[i], &act, NULL) < 0) {
- PLOGE("Error removing signal handler");
- continue;
- }
- }
-}
-
-/**
- * Setup signal handlers trap signals which should result in program termination
- * so that we can restore the terminal to its normal state and retrieve the
- * return code.
- */
-static void setup_sighandlers(void) {
- struct sigaction act;
- int i;
-
- // Install the termination handlers
- // Note: we're assuming that none of these signal handlers are already trapped.
- // If they are, we'll need to modify this code to save the previous handler and
- // call it after we restore stdin to its previous state.
- memset(&act, '\0', sizeof(act));
- act.sa_handler = &sighandler;
- for (i = 0; quit_signals[i]; i++) {
- if (sigaction(quit_signals[i], &act, NULL) < 0) {
- PLOGE("Error installing signal handler");
- continue;
- }
- }
-}
-
-int connect_daemon(int argc, char *argv[], int ppid) {
- int ptmx = -1;
- char pts_slave[PATH_MAX];
-
- struct sockaddr_un sun;
-
- // Open a socket to the daemon
- int socketfd = socket(AF_LOCAL, SOCK_STREAM, 0);
- if (socketfd < 0) {
- PLOGE("socket");
- exit(-1);
- }
- if (fcntl(socketfd, F_SETFD, FD_CLOEXEC)) {
- PLOGE("fcntl FD_CLOEXEC");
- exit(-1);
- }
-
- memset(&sun, 0, sizeof(sun));
- sun.sun_family = AF_LOCAL;
- sprintf(sun.sun_path, "%s/su-daemon", DAEMON_SOCKET_PATH);
-
- if (0 != connect(socketfd, (struct sockaddr*)&sun, sizeof(sun))) {
- PLOGE("connect");
- exit(-1);
- }
-
- ALOGV("connecting client %d", getpid());
-
- int mount_storage = getenv("MOUNT_EMULATED_STORAGE") != NULL;
-
- // Determine which one of our streams are attached to a TTY
- int atty = 0;
-
- // TODO: Check a system property and never use PTYs if
- // the property is set.
- if (isatty(STDIN_FILENO)) atty |= ATTY_IN;
- if (isatty(STDOUT_FILENO)) atty |= ATTY_OUT;
- if (isatty(STDERR_FILENO)) atty |= ATTY_ERR;
-
- if (atty) {
- // We need a PTY. Get one.
- ptmx = pts_open(pts_slave, sizeof(pts_slave));
- if (ptmx < 0) {
- PLOGE("pts_open");
- exit(-1);
- }
- } else {
- pts_slave[0] = '\0';
- }
-
- // Send some info to the daemon, starting with our PID
- write_int(socketfd, getpid());
- // Send the slave path to the daemon
- // (This is "" if we're not using PTYs)
- write_string(socketfd, pts_slave);
- // Parent PID
- write_int(socketfd, ppid);
- write_int(socketfd, mount_storage);
-
- // Send stdin
- if (atty & ATTY_IN) {
- // Using PTY
- send_fd(socketfd, -1);
- } else {
- send_fd(socketfd, STDIN_FILENO);
- }
-
- // Send stdout
- if (atty & ATTY_OUT) {
- // Forward SIGWINCH
- watch_sigwinch_async(STDOUT_FILENO, ptmx);
-
- // Using PTY
- send_fd(socketfd, -1);
- } else {
- send_fd(socketfd, STDOUT_FILENO);
- }
-
- // Send stderr
- if (atty & ATTY_ERR) {
- // Using PTY
- send_fd(socketfd, -1);
- } else {
- send_fd(socketfd, STDERR_FILENO);
- }
-
- // Number of command line arguments
- write_int(socketfd, mount_storage ? argc - 1 : argc);
-
- // Command line arguments
- int i;
- for (i = 0; i < argc; i++) {
- if (i == 1 && mount_storage) {
- continue;
- }
- write_string(socketfd, argv[i]);
- }
-
- // Wait for acknowledgement from daemon
- read_int(socketfd);
-
- if (atty & ATTY_IN) {
- setup_sighandlers();
- pump_stdin_async(ptmx);
- }
- if (atty & ATTY_OUT) {
- pump_stdout_blocking(ptmx);
- }
-
- // Get the exit code
- int code = read_int(socketfd);
- close(socketfd);
- ALOGD("client exited %d", code);
-
- return code;
-}
+++ /dev/null
-/*
- * Copyright 2013, Tan Chee Eng (@tan-ce)
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /*
- * pts.c
- *
- * Manages the pseudo-terminal driver on Linux/Android and provides some
- * helper functions to handle raw input mode and terminal window resizing
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <termios.h>
-#include <errno.h>
-#include <pthread.h>
-
-#include "pts.h"
-
-/**
- * Helper functions
- */
-// Ensures all the data is written out
-static int write_blocking(int fd, char *buf, size_t bufsz) {
- ssize_t ret, written;
-
- written = 0;
- do {
- ret = write(fd, buf + written, bufsz - written);
- if (ret == -1) return -1;
- written += ret;
- } while (written < (ssize_t)bufsz);
-
- return 0;
-}
-
-/**
- * Pump data from input FD to output FD. If close_output is
- * true, then close the output FD when we're done.
- */
-static void pump_ex(int input, int output, int close_output) {
- char buf[4096];
- int len;
- while ((len = read(input, buf, 4096)) > 0) {
- if (write_blocking(output, buf, len) == -1) break;
- }
- close(input);
- if (close_output) close(output);
-}
-
-/**
- * Pump data from input FD to output FD. Will close the
- * output FD when done.
- */
-static void pump(int input, int output) {
- pump_ex(input, output, 1);
-}
-
-static void* pump_thread(void* data) {
- int* files = (int*)data;
- int input = files[0];
- int output = files[1];
- pump(input, output);
- free(data);
- return NULL;
-}
-
-static void pump_async(int input, int output) {
- pthread_t writer;
- int* files = (int*)malloc(sizeof(int) * 2);
- if (files == NULL) {
- exit(-1);
- }
- files[0] = input;
- files[1] = output;
- pthread_create(&writer, NULL, pump_thread, files);
-}
-
-
-/**
- * pts_open
- *
- * Opens a pts device and returns the name of the slave tty device.
- *
- * Arguments
- * slave_name the name of the slave device
- * slave_name_size the size of the buffer passed via slave_name
- *
- * Return Values
- * on failure either -2 or -1 (errno set) is returned.
- * on success, the file descriptor of the master device is returned.
- */
-int pts_open(char *slave_name, size_t slave_name_size) {
- int fdm;
- char sn_tmp[slave_name_size];
-
- // Open master ptmx device
- fdm = open("/dev/ptmx", O_RDWR);
- if (fdm == -1) return -1;
-
- // Get the slave name
- if (ptsname_r(fdm, sn_tmp, slave_name_size) != 0) {
- close(fdm);
- return -2;
- }
-
- if (strlcpy(slave_name, sn_tmp, slave_name_size) >= slave_name_size) {
- return -1;
- }
-
- // Grant, then unlock
- if (grantpt(fdm) == -1) {
- close(fdm);
- return -1;
- }
- if (unlockpt(fdm) == -1) {
- close(fdm);
- return -1;
- }
-
- return fdm;
-}
-
-// Stores the previous termios of stdin
-static struct termios old_stdin;
-static int stdin_is_raw = 0;
-
-/**
- * set_stdin_raw
- *
- * Changes stdin to raw unbuffered mode, disables echo,
- * auto carriage return, etc.
- *
- * Return Value
- * on failure -1, and errno is set
- * on success 0
- */
-int set_stdin_raw(void) {
- struct termios new_termios;
-
- // Save the current stdin termios
- if (tcgetattr(STDIN_FILENO, &old_stdin) < 0) {
- return -1;
- }
-
- // Start from the current settings
- new_termios = old_stdin;
-
- // Make the terminal like an SSH or telnet client
- new_termios.c_iflag |= IGNPAR;
- new_termios.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
- new_termios.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
- new_termios.c_oflag &= ~OPOST;
- new_termios.c_cc[VMIN] = 1;
- new_termios.c_cc[VTIME] = 0;
-
- if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &new_termios) < 0) {
- return -1;
- }
-
- stdin_is_raw = 1;
-
- return 0;
-}
-
-/**
- * restore_stdin
- *
- * Restore termios on stdin to the state it was before
- * set_stdin_raw() was called. If set_stdin_raw() was
- * never called, does nothing and doesn't return an error.
- *
- * This function is async-safe.
- *
- * Return Value
- * on failure, -1 and errno is set
- * on success, 0
- */
-int restore_stdin(void) {
- if (!stdin_is_raw) return 0;
-
- if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &old_stdin) < 0) {
- return -1;
- }
-
- stdin_is_raw = 0;
-
- return 0;
-}
-
-// Flag indicating whether the sigwinch watcher should terminate.
-static volatile int closing_time = 0;
-
-/**
- * Thread process. Wait for a SIGWINCH to be received, then update
- * the terminal size.
- */
-static void *watch_sigwinch(void *data) {
- sigset_t winch;
- int sig;
- int master = ((int *)data)[0];
- int slave = ((int *)data)[1];
-
- sigemptyset(&winch);
- sigaddset(&winch, SIGWINCH);
-
- do {
- // Wait for a SIGWINCH
- sigwait(&winch, &sig);
-
- if (closing_time) break;
-
- // Get the new terminal size
- struct winsize w;
- if (ioctl(master, TIOCGWINSZ, &w) == -1) {
- continue;
- }
-
- // Set the new terminal size
- ioctl(slave, TIOCSWINSZ, &w);
-
- } while (1);
-
- free(data);
- return NULL;
-}
-
-/**
- * watch_sigwinch_async
- *
- * After calling this function, if the application receives
- * SIGWINCH, the terminal window size will be read from
- * "input" and set on "output".
- *
- * NOTE: This function blocks SIGWINCH and spawns a thread.
- * NOTE 2: This function must be called before any of the
- * pump functions.
- *
- * Arguments
- * master A file descriptor of the TTY window size to follow
- * slave A file descriptor of the TTY window size which is
- * to be set on SIGWINCH
- *
- * Return Value
- * on failure, -1 and errno will be set. In this case, no
- * thread has been spawned and SIGWINCH will not be
- * blocked.
- * on success, 0
- */
-int watch_sigwinch_async(int master, int slave) {
- pthread_t watcher;
- int *files = (int *) malloc(sizeof(int) * 2);
- if (files == NULL) {
- return -1;
- }
-
- // Block SIGWINCH so sigwait can later receive it
- sigset_t winch;
- sigemptyset(&winch);
- sigaddset(&winch, SIGWINCH);
- if (sigprocmask(SIG_BLOCK, &winch, NULL) == -1) {
- free(files);
- return -1;
- }
-
- // Initialize some variables, then start the thread
- closing_time = 0;
- files[0] = master;
- files[1] = slave;
- int ret = pthread_create(&watcher, NULL, &watch_sigwinch, files);
- if (ret != 0) {
- free(files);
- errno = ret;
- return -1;
- }
-
- // Set the initial terminal size
- raise(SIGWINCH);
- return 0;
-}
-
-/**
- * watch_sigwinch_cleanup
- *
- * Cause the SIGWINCH watcher thread to terminate
- */
-void watch_sigwinch_cleanup(void) {
- closing_time = 1;
- raise(SIGWINCH);
-}
-
-/**
- * pump_stdin_async
- *
- * Forward data from STDIN to the given FD
- * in a seperate thread
- */
-void pump_stdin_async(int outfd) {
- // Put stdin into raw mode
- set_stdin_raw();
-
- // Pump data from stdin to the PTY
- pump_async(STDIN_FILENO, outfd);
-}
-
-/**
- * pump_stdout_blocking
- *
- * Forward data from the FD to STDOUT.
- * Returns when the remote end of the FD closes.
- *
- * Before returning, restores stdin settings.
- */
-void pump_stdout_blocking(int infd) {
- // Pump data from stdout to PTY
- pump_ex(infd, STDOUT_FILENO, 0 /* Don't close output when done */);
-
- // Cleanup
- restore_stdin();
- watch_sigwinch_cleanup();
-}
+++ /dev/null
-/*
- * Copyright 2013, Tan Chee Eng (@tan-ce)
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /*
- * pts.h
- *
- * Manages the pseudo-terminal driver on Linux/Android and provides some
- * helper functions to handle raw input mode and terminal window resizing
- */
-
-#ifndef _PTS_H_
-#define _PTS_H_
-
-/**
- * pts_open
- *
- * Opens a pts device and returns the name of the slave tty device.
- *
- * Arguments
- * slave_name the name of the slave device
- * slave_name_size the size of the buffer passed via slave_name
- *
- * Return Values
- * on failure either -2 or -1 (errno set) is returned.
- * on success, the file descriptor of the master device is returned.
- */
-int pts_open(char *slave_name, size_t slave_name_size);
-
-/**
- * set_stdin_raw
- *
- * Changes stdin to raw unbuffered mode, disables echo,
- * auto carriage return, etc.
- *
- * Return Value
- * on failure -1, and errno is set
- * on success 0
- */
-int set_stdin_raw(void);
-
-/**
- * restore_stdin
- *
- * Restore termios on stdin to the state it was before
- * set_stdin_raw() was called. If set_stdin_raw() was
- * never called, does nothing and doesn't return an error.
- *
- * This function is async-safe.
- *
- * Return Value
- * on failure, -1 and errno is set
- * on success, 0
- */
-int restore_stdin(void);
-
-/**
- * watch_sigwinch_async
- *
- * After calling this function, if the application receives
- * SIGWINCH, the terminal window size will be read from
- * "input" and set on "output".
- *
- * NOTE: This function blocks SIGWINCH and spawns a thread.
- *
- * Arguments
- * master A file descriptor of the TTY window size to follow
- * slave A file descriptor of the TTY window size which is
- * to be set on SIGWINCH
- *
- * Return Value
- * on failure, -1 and errno will be set. In this case, no
- * thread has been spawned and SIGWINCH will not be
- * blocked.
- * on success, 0
- */
-int watch_sigwinch_async(int master, int slave);
-
-/**
- * watch_sigwinch_cleanup
- *
- * Cause the SIGWINCH watcher thread to terminate
- */
-void watch_sigwinch_cleanup(void);
-
-/**
- * pump_stdin_async
- *
- * Forward data from STDIN to the given FD
- * in a seperate thread
- */
-void pump_stdin_async(int outfd);
-
-/**
- * pump_stdout_blocking
- *
- * Forward data from the FD to STDOUT.
- * Returns when the remote end of the FD closes.
- *
- * Before returning, restores stdin settings.
- */
-void pump_stdout_blocking(int infd);
-
-#endif
+++ /dev/null
-/*
-** Copyright 2010, Adam Shanks (@ChainsDD)
-** Copyright 2008, Zinx Verituse (@zinxv)
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef SU_h
-#define SU_h 1
-
-#ifdef LOG_TAG
-#undef LOG_TAG
-#endif
-#define LOG_TAG "su"
-
-// CyanogenMod-specific behavior
-#define CM_ROOT_ACCESS_DISABLED 0
-#define CM_ROOT_ACCESS_APPS_ONLY 1
-#define CM_ROOT_ACCESS_ADB_ONLY 2
-#define CM_ROOT_ACCESS_APPS_AND_ADB 3
-
-#define DAEMON_SOCKET_PATH "/dev/socket/su-daemon/"
-
-#define DEFAULT_SHELL "/system/bin/sh"
-
-#define xstr(a) str(a)
-#define str(a) #a
-
-#ifndef VERSION_CODE
-#define VERSION_CODE 16
-#endif
-#define VERSION xstr(VERSION_CODE) " cm-su"
-
-#define PROTO_VERSION 1
-
-struct su_initiator {
- pid_t pid;
- unsigned uid;
- unsigned user;
- char name[64];
- char bin[PATH_MAX];
- char args[4096];
-};
-
-struct su_request {
- unsigned uid;
- char name[64];
- int login;
- int keepenv;
- char *shell;
- char *command;
- char **argv;
- int argc;
- int optind;
-};
-
-struct su_context {
- struct su_initiator from;
- struct su_request to;
- mode_t umask;
- char sock_path[PATH_MAX];
-};
-
-typedef enum {
- INTERACTIVE = 0,
- DENY = 1,
- ALLOW = 2,
-} policy_t;
-
-extern void set_identity(unsigned int uid);
-
-static inline char *get_command(const struct su_request *to)
-{
- if (to->command)
- return to->command;
- if (to->shell)
- return to->shell;
- char* ret = to->argv[to->optind];
- if (ret)
- return ret;
- return DEFAULT_SHELL;
-}
-
-int appops_start_op_su(int uid, const char *pkgName);
-int appops_finish_op_su(int uid, const char *pkgName);
-
-int run_daemon();
-int connect_daemon(int argc, char *argv[], int ppid);
-int su_main(int argc, char *argv[], int need_client);
-// for when you give zero fucks about the state of the child process.
-// this version of fork understands you don't care about the child.
-// deadbeat dad fork.
-int fork_zero_fucks();
-
-#ifndef LOG_NDEBUG
-#define LOG_NDEBUG 1
-#endif
-
-#include <errno.h>
-#include <string.h>
-#define PLOGE(fmt,args...) ALOGE(fmt " failed with %d: %s", ##args, errno, strerror(errno))
-#define PLOGEV(fmt,err,args...) ALOGE(fmt " failed with %d: %s", ##args, err, strerror(err))
-
-#endif
+++ /dev/null
-# su daemon
-service su_daemon /system/xbin/su --daemon
- user root
- group root
- disabled
- seclabel u:r:sudaemon:s0
-
-on property:persist.sys.root_access=0
- stop su_daemon
-
-on property:persist.sys.root_access=2
- start su_daemon
-
-on property:persist.sys.root_access=1
- start su_daemon
-
-on property:persist.sys.root_access=3
- start su_daemon
+++ /dev/null
-/*
-** Copyright 2012, The CyanogenMod Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "utils.h"
-
-/* reads a file, making sure it is terminated with \n \0 */
-char* read_file(const char *fn)
-{
- struct stat st;
- char *data = NULL;
-
- int fd = open(fn, O_RDONLY);
- if (fd < 0) return data;
-
- if (fstat(fd, &st)) goto oops;
-
- data = malloc(st.st_size + 2);
- if (!data) goto oops;
-
- if (read(fd, data, st.st_size) != st.st_size) goto oops;
- close(fd);
- data[st.st_size] = '\n';
- data[st.st_size + 1] = 0;
- return data;
-
-oops:
- close(fd);
- if (data) free(data);
- return NULL;
-}
-
-int get_property(const char *data, char *found, const char *searchkey, const char *not_found)
-{
- char *key, *value, *eol, *sol, *tmp;
- if (data == NULL) goto defval;
- int matched = 0;
- char *dup = strdup(data);
-
- sol = dup;
- while((eol = strchr(sol, '\n'))) {
- key = sol;
- *eol++ = 0;
- sol = eol;
-
- value = strchr(key, '=');
- if(value == 0) continue;
- *value++ = 0;
-
- while(isspace(*key)) key++;
- if(*key == '#') continue;
- tmp = value - 2;
- while((tmp > key) && isspace(*tmp)) *tmp-- = 0;
-
- while(isspace(*value)) value++;
- tmp = eol - 2;
- while((tmp > value) && isspace(*tmp)) *tmp-- = 0;
-
- if (strncmp(searchkey, key, strlen(searchkey)) == 0) {
- matched = 1;
- break;
- }
- }
- free(dup);
- int len;
- if (matched) {
- len = strlen(value);
- if (len >= PROPERTY_VALUE_MAX)
- return -1;
- memcpy(found, value, len + 1);
- } else goto defval;
- return len;
-
-defval:
- len = strlen(not_found);
- memcpy(found, not_found, len + 1);
- return len;
-}
-
-/*
- * Fast version of get_property which purpose is to check
- * whether the property with given prefix exists.
- *
- * Assume nobody is stupid enough to put a propery with prefix ro.cm.version
- * in his build.prop on a non-CM ROM and comment it out.
- */
-int check_property(const char *data, const char *prefix)
-{
- if (!data)
- return 0;
- return strstr(data, prefix) != NULL;
-}
+++ /dev/null
-/*
-** Copyright 2012, The CyanogenMod Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef _UTILS_H_
-#define _UTILS_H_
-
-#ifndef PROPERTY_VALUE_MAX
-#define PROPERTY_VALUE_MAX 92
-#endif
-
-/* reads a file, making sure it is terminated with \n \0 */
-extern char* read_file(const char *fn);
-
-extern int get_property(const char *data, char *found, const char *searchkey,
- const char *not_found);
-extern int check_property(const char *data, const char *prefix);
-#endif