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>
30 #define ACTION_REQUEST "start", "-n", REQUESTOR "/" REQUESTOR_PREFIX ".RequestActivity"
31 #define ACTION_NOTIFY "start", "-n", REQUESTOR "/" REQUESTOR_PREFIX ".NotifyActivity"
32 #define ACTION_RESULT "broadcast", "-n", REQUESTOR "/" REQUESTOR_PREFIX ".SuReceiver"
34 #define AM_PATH "/system/bin/app_process", "/system/bin", "com.android.commands.am.Am"
36 // TODO: leverage this with exec_log?
37 int silent_run(char* const args[]) {
49 int zero = open("/dev/zero", O_RDONLY | O_CLOEXEC);
51 int null = open("/dev/null", O_WRONLY | O_CLOEXEC);
54 setenv("CLASSPATH", "/system/framework/am.jar", 1);
61 int get_owner_login_user_args(struct su_context *ctx, char* user, int user_len) {
62 int needs_owner_login_prompt = 0;
64 if (ctx->user.multiuser_mode == MULTIUSER_MODE_OWNER_MANAGED) {
65 if (0 != ctx->user.android_user_id) {
66 needs_owner_login_prompt = 1;
68 snprintf(user, user_len, "0");
70 else if (ctx->user.multiuser_mode == MULTIUSER_MODE_USER) {
71 snprintf(user, user_len, "%d", ctx->user.android_user_id);
73 else if (ctx->user.multiuser_mode == MULTIUSER_MODE_NONE) {
77 snprintf(user, user_len, "0");
80 return needs_owner_login_prompt;
83 int send_result(struct su_context *ctx, policy_t policy) {
84 char binary_version[256];
85 sprintf(binary_version, "%d", VERSION_CODE);
88 sprintf(uid, "%d", ctx->from.uid);
90 char desired_uid[256];
91 sprintf(desired_uid, "%d", ctx->to.uid);
93 if (0 != ctx->user.android_user_id) {
94 char android_user_id[256];
95 sprintf(android_user_id, "%d", ctx->user.android_user_id);
97 char *user_result_command[] = {
117 get_command(&ctx->to),
120 policy == ALLOW ? "allow" : "deny",
125 silent_run(user_result_command);
129 get_owner_login_user_args(ctx, user, sizeof(user));
131 char *result_command[] = {
151 get_command(&ctx->to),
154 policy == ALLOW ? "allow" : "deny",
155 user[0] ? "--user" : NULL,
159 return silent_run(result_command);
162 int send_request(struct su_context *ctx) {
163 // if su is operating in MULTIUSER_MODEL_OWNER,
164 // and the user requestor is not the owner,
165 // the owner needs to be notified of the request.
166 // so there will be two activities shown.
168 int needs_owner_login_prompt = get_owner_login_user_args(ctx, user, sizeof(user));
171 if (needs_owner_login_prompt) {
173 sprintf(uid, "%d", ctx->from.uid);
175 char android_user_id[256];
176 sprintf(android_user_id, "%d", ctx->user.android_user_id);
178 // in multiuser mode, the owner gets the su prompt
179 char *notify_command[] = {
190 int ret = silent_run(notify_command);
196 char *request_command[] = {
202 user[0] ? "--user" : NULL,
207 return silent_run(request_command);