1e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project/* 2e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project** 3e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project** Copyright 2008, The Android Open Source Project 4e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project** 5e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License"); 6e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project** you may not use this file except in compliance with the License. 7e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project** You may obtain a copy of the License at 8e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project** 9e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project** http://www.apache.org/licenses/LICENSE-2.0 10e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project** 11e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project** Unless required by applicable law or agreed to in writing, software 12e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project** distributed under the License is distributed on an "AS IS" BASIS, 13e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project** See the License for the specific language governing permissions and 15e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project** limitations under the License. 16e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project*/ 17e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 1826aaac4bf942c4f51de0f10ea85edf9751c234c8The Android Open Source Project#define LOG_TAG "su" 1926aaac4bf942c4f51de0f10ea85edf9751c234c8The Android Open Source Project 20e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <stdio.h> 21e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <stdlib.h> 22e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <string.h> 23e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <sys/types.h> 24e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <dirent.h> 25e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <errno.h> 26e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 27e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <unistd.h> 28e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <time.h> 29e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 30e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <pwd.h> 31e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 3226aaac4bf942c4f51de0f10ea85edf9751c234c8The Android Open Source Project#include <private/android_filesystem_config.h> 3326aaac4bf942c4f51de0f10ea85edf9751c234c8The Android Open Source Project 34d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall 35d198c429f50e1cad98e989d6212508adb45d7919JP Abgrallvoid pwtoid(const char *tok, uid_t *uid, gid_t *gid) 36d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall{ 37d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall struct passwd *pw; 38d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall pw = getpwnam(tok); 39d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall if (pw) { 40d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall if (uid) *uid = pw->pw_uid; 41d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall if (gid) *gid = pw->pw_gid; 42d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall } else { 43d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall uid_t tmpid = atoi(tok); 44d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall if (uid) *uid = tmpid; 45d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall if (gid) *gid = tmpid; 46d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall } 47d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall} 48d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall 49d198c429f50e1cad98e989d6212508adb45d7919JP Abgrallvoid extract_uidgids(const char *uidgids, uid_t *uid, gid_t *gid, gid_t *gids, 50d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall int *gids_count) 51d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall{ 52d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall char *clobberablegids; 53d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall char *nexttok; 54d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall char *tok; 55d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall int gids_found; 56d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall 57d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall if (!uidgids || !*uidgids) { 58d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall *gid = *uid = 0; 59d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall *gids_count = 0; 60d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall return; 61d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall } 62d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall clobberablegids = strdup(uidgids); 63d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall strcpy(clobberablegids, uidgids); 64d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall nexttok = clobberablegids; 65d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall tok = strsep(&nexttok, ","); 66d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall pwtoid(tok, uid, gid); 67d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall tok = strsep(&nexttok, ","); 68d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall if (!tok) { 69d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall /* gid is already set above */ 70d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall *gids_count = 0; 71d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall free(clobberablegids); 72d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall return; 73d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall } 74d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall pwtoid(tok, NULL, gid); 75d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall gids_found = 0; 76d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall while ((gids_found < *gids_count) && (tok = strsep(&nexttok, ","))) { 77d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall pwtoid(tok, NULL, gids); 78d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall gids_found++; 79d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall gids++; 80d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall } 81d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall if (nexttok && gids_found == *gids_count) { 82d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall fprintf(stderr, "too many group ids\n"); 83d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall } 84d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall *gids_count = gids_found; 85d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall free(clobberablegids); 86d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall} 87d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall 88e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project/* 89e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * SU can be given a specific command to exec. UID _must_ be 90e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * specified for this (ie argc => 3). 91e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * 92e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * Usage: 93d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall * su 1000 94d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall * su 1000 ls -l 95d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall * or 96d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall * su [uid[,gid[,group1]...] [cmd]] 97d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall * E.g. 98d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall * su 1000,shell,net_bw_acct,net_bw_stats id 99d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall * will return 100d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall * uid=1000(system) gid=2000(shell) groups=3006(net_bw_stats),3007(net_bw_acct) 101e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project */ 102e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectint main(int argc, char **argv) 103e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project{ 104e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project struct passwd *pw; 105d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall uid_t uid, myuid; 106d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall gid_t gid, gids[10]; 107e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 10817928c8ab5e696517cd03969364f7288ab5b911cNick Kralevich /* Until we have something better, only root and the shell can use su. */ 10917928c8ab5e696517cd03969364f7288ab5b911cNick Kralevich myuid = getuid(); 11017928c8ab5e696517cd03969364f7288ab5b911cNick Kralevich if (myuid != AID_ROOT && myuid != AID_SHELL) { 11117928c8ab5e696517cd03969364f7288ab5b911cNick Kralevich fprintf(stderr,"su: uid %d not allowed to su\n", myuid); 11217928c8ab5e696517cd03969364f7288ab5b911cNick Kralevich return 1; 11317928c8ab5e696517cd03969364f7288ab5b911cNick Kralevich } 11417928c8ab5e696517cd03969364f7288ab5b911cNick Kralevich 115e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if(argc < 2) { 116e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project uid = gid = 0; 117e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } else { 118d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall int gids_count = sizeof(gids)/sizeof(gids[0]); 119d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall extract_uidgids(argv[1], &uid, &gid, gids, &gids_count); 120d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall if(gids_count) { 121d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall if(setgroups(gids_count, gids)) { 122d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall fprintf(stderr, "su: failed to set groups\n"); 123d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall return 1; 124d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall } 125e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 126e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 127e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 128e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if(setgid(gid) || setuid(uid)) { 129e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project fprintf(stderr,"su: permission denied\n"); 130e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project return 1; 131e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 132e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 133e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project /* User specified command for exec. */ 134e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (argc == 3 ) { 135e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (execlp(argv[2], argv[2], NULL) < 0) { 136d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall int saved_errno = errno; 137e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project fprintf(stderr, "su: exec failed for %s Error:%s\n", argv[2], 138e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project strerror(errno)); 139d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall return -saved_errno; 140e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 141e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } else if (argc > 3) { 142e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project /* Copy the rest of the args from main. */ 143e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project char *exec_args[argc - 1]; 144e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project memset(exec_args, 0, sizeof(exec_args)); 145e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project memcpy(exec_args, &argv[2], sizeof(exec_args)); 146e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (execvp(argv[2], exec_args) < 0) { 147d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall int saved_errno = errno; 148e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project fprintf(stderr, "su: exec failed for %s Error:%s\n", argv[2], 149e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project strerror(errno)); 150d198c429f50e1cad98e989d6212508adb45d7919JP Abgrall return -saved_errno; 151e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 152e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 153e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 154e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project /* Default exec shell. */ 155e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project execlp("/system/bin/sh", "sh", NULL); 156e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 157e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project fprintf(stderr, "su: exec failed\n"); 158e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project return 1; 159e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project} 160