2 ** Copyright 2010, Adam Shanks (@ChainsDD)
3 ** Copyright 2008, Zinx Verituse (@zinxv)
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
9 ** http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <sys/types.h>
29 static void kill_child(pid_t pid) {
30 LOGD("killing child %d", pid);
35 sigaddset(&set, SIGCHLD);
36 if (sigprocmask(SIG_BLOCK, &set, &old)) {
37 PLOGE("sigprocmask(SIG_BLOCK)");
40 if (kill(pid, SIGKILL))
41 PLOGE("kill (%d)", pid);
42 else if (sigsuspend(&old) && errno != EINTR)
44 if (sigprocmask(SIG_SETMASK, &old, NULL))
45 PLOGE("sigprocmask(SIG_BLOCK)");
49 // TODO: leverage this with exec_log?
50 static int silent_run(char* command) {
51 char *args[] = { "sh", "-c", command, NULL, };
63 int zero = open("/dev/zero", O_RDONLY | O_CLOEXEC);
65 int null = open("/dev/null", O_WRONLY | O_CLOEXEC);
68 execv(_PATH_BSHELL, args);
74 int get_owner_login_user_args(struct su_context *ctx, char* user, int user_len) {
75 int needs_owner_login_prompt = 0;
77 if (ctx->user.multiuser_mode == MULTIUSER_MODE_OWNER_MANAGED) {
78 if (0 != ctx->user.android_user_id) {
79 needs_owner_login_prompt = 1;
81 snprintf(user, user_len, "--user 0");
83 else if (ctx->user.multiuser_mode == MULTIUSER_MODE_USER) {
84 snprintf(user, user_len, "--user %d", ctx->user.android_user_id);
86 else if (ctx->user.multiuser_mode == MULTIUSER_MODE_NONE) {
87 snprintf(user, user_len, "");
90 snprintf(user, user_len, "--user 0");
93 return needs_owner_login_prompt;
96 int send_result(struct su_context *ctx, policy_t policy) {
98 get_owner_login_user_args(ctx, user, sizeof(user));
100 if (0 != ctx->user.android_user_id) {
101 char user_result_command[ARG_MAX];
102 snprintf(user_result_command, sizeof(user_result_command), "exec /system/bin/am " ACTION_RESULT " --ei binary_version %d --es from_name '%s' --es desired_name '%s' --ei uid %d --ei desired_uid %d --es command '%s' --es action %s --user %d",
104 ctx->from.name, ctx->to.name,
105 ctx->from.uid, ctx->to.uid, get_command(&ctx->to), policy == ALLOW ? "allow" : "deny", ctx->user.android_user_id);
106 silent_run(user_result_command);
107 LOGD(user_result_command);
110 char result_command[ARG_MAX];
111 snprintf(result_command, sizeof(result_command), "exec /system/bin/am " ACTION_RESULT " --ei binary_version %d --es from_name '%s' --es desired_name '%s' --ei uid %d --ei desired_uid %d --es command '%s' --es action %s %s",
113 ctx->from.name, ctx->to.name,
114 ctx->from.uid, ctx->to.uid, get_command(&ctx->to), policy == ALLOW ? "allow" : "deny", user);
115 return silent_run(result_command);
118 int send_request(struct su_context *ctx) {
119 // if su is operating in MULTIUSER_MODEL_OWNER,
120 // and the user requestor is not the owner,
121 // the owner needs to be notified of the request.
122 // so there will be two activities shown.
124 int needs_owner_login_prompt = get_owner_login_user_args(ctx, user, sizeof(user));
127 if (needs_owner_login_prompt) {
128 // in multiuser mode, the owner gets the su prompt
129 char notify_command[ARG_MAX];
131 // start the activity that confirms the request
132 snprintf(notify_command, sizeof(notify_command),
133 "exec /system/bin/am " ACTION_NOTIFY " --ei caller_uid %d --user %d",
134 ctx->from.uid, ctx->user.android_user_id);
136 int ret = silent_run(notify_command);
142 char request_command[ARG_MAX];
144 // start the activity that confirms the request
145 snprintf(request_command, sizeof(request_command),
146 "exec /system/bin/am " ACTION_REQUEST " --es socket '%s' %s",
147 ctx->sock_path, user);
149 return silent_run(request_command);