Remove bind, init, and GNU compiler dependancy
This commit is contained in:
parent
42a66ad49e
commit
7955ddceb2
246
binds.c
246
binds.c
@ -1,246 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2016, Pierre-Hugues Husson <phh@phh.me>
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program; if not, write to the Free Software Foundation,
|
|
||||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
#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 <strings.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <pwd.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <selinux/selinux.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include "binds.h"
|
|
||||||
|
|
||||||
int bind_foreach(bind_cb cb, void* arg) {
|
|
||||||
int res = 0;
|
|
||||||
char *str = NULL;
|
|
||||||
int fd = open("/data/su/binds", O_RDONLY);
|
|
||||||
if(fd<0)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
off_t size = lseek(fd, 0, SEEK_END);
|
|
||||||
lseek(fd, 0, SEEK_SET);
|
|
||||||
|
|
||||||
str = malloc(size);
|
|
||||||
if(read(fd, str, size) != size)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
char *base = str;
|
|
||||||
while(base < str+size) {
|
|
||||||
char *parse_src, *parse_dst;
|
|
||||||
int uid;
|
|
||||||
|
|
||||||
char *ptr = memchr(base, 0, size-(base-str));
|
|
||||||
if(ptr == NULL)
|
|
||||||
goto error;
|
|
||||||
sscanf(base, "%d", &uid);
|
|
||||||
|
|
||||||
parse_src = strchr(base, ':');
|
|
||||||
if(!parse_src)
|
|
||||||
goto error;
|
|
||||||
parse_src++;
|
|
||||||
|
|
||||||
parse_dst = strchr(parse_src, ':');
|
|
||||||
if(!parse_dst)
|
|
||||||
goto error;
|
|
||||||
*parse_dst = 0; // Split parse_src string
|
|
||||||
parse_dst++;
|
|
||||||
|
|
||||||
cb(arg, uid, parse_src, parse_dst);
|
|
||||||
|
|
||||||
base = ptr+1;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = 1;
|
|
||||||
error:
|
|
||||||
if(str) free(str);
|
|
||||||
close(fd);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
int bind_uniq_dst(const char *dst) {
|
|
||||||
static int _res;
|
|
||||||
static const char *_dst;
|
|
||||||
|
|
||||||
_res = 1;
|
|
||||||
_dst = dst;
|
|
||||||
auto void cb(void *arg, int uid, const char *src, const char *dst) {
|
|
||||||
if(strcmp(dst, _dst) == 0)
|
|
||||||
_res = 0;
|
|
||||||
}
|
|
||||||
if(!bind_foreach(cb, NULL))
|
|
||||||
return 0;
|
|
||||||
return _res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bind_ls(int uid) {
|
|
||||||
static int _uid;
|
|
||||||
_uid=uid;
|
|
||||||
auto void cb(void *arg, int uid, const char *src, const char *dst) {
|
|
||||||
if(_uid == 0 || _uid == 2000 || _uid == uid) {
|
|
||||||
fprintf(stderr, "%d %s => %s\n", uid, src, dst);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bind_foreach(cb, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
int bind_remove(const char *path, int uid) {
|
|
||||||
static int _found = 0;
|
|
||||||
static const char *_path;
|
|
||||||
static int _fd;
|
|
||||||
static int _uid;
|
|
||||||
|
|
||||||
|
|
||||||
_path = path;
|
|
||||||
_found = 0;
|
|
||||||
_uid = uid;
|
|
||||||
|
|
||||||
unlink("/data/su/bind.new");
|
|
||||||
_fd = open("/data/su/bind.new", O_WRONLY|O_CREAT, 0600);
|
|
||||||
if(_fd<0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
auto void cb(void *arg, int uid, const char *src, const char *dst) {
|
|
||||||
//The one we want to drop
|
|
||||||
if(strcmp(dst, _path) == 0 &&
|
|
||||||
(_uid == 0 || _uid == 2000 || _uid == uid)) {
|
|
||||||
_found = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
char *str = NULL;
|
|
||||||
int len = asprintf(&str, "%d:%s:%s", uid, src, dst);
|
|
||||||
write(_fd, str, len+1); //len doesn't include final \0 and we want to write it
|
|
||||||
free(str);
|
|
||||||
}
|
|
||||||
bind_foreach(cb, NULL);
|
|
||||||
close(_fd);
|
|
||||||
unlink("/data/su/bind");
|
|
||||||
rename("/data/su/bind.new", "/data/su/bind");
|
|
||||||
return _found;
|
|
||||||
}
|
|
||||||
|
|
||||||
int init_foreach(init_cb icb, void* arg) {
|
|
||||||
int res = 0;
|
|
||||||
char *str = NULL;
|
|
||||||
int fd = open("/data/su/init", O_RDONLY);
|
|
||||||
if(fd<0)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
off_t size = lseek(fd, 0, SEEK_END);
|
|
||||||
lseek(fd, 0, SEEK_SET);
|
|
||||||
|
|
||||||
str = malloc(size);
|
|
||||||
if(read(fd, str, size) != size)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
char *base = str;
|
|
||||||
while(base < str+size) {
|
|
||||||
char *parsed;
|
|
||||||
int uid;
|
|
||||||
|
|
||||||
char *ptr = memchr(base, 0, size-(base-str));
|
|
||||||
if(ptr == NULL)
|
|
||||||
goto error;
|
|
||||||
sscanf(base, "%d", &uid);
|
|
||||||
|
|
||||||
parsed = strchr(base, ':');
|
|
||||||
if(!parsed)
|
|
||||||
goto error;
|
|
||||||
parsed++;
|
|
||||||
|
|
||||||
|
|
||||||
icb(arg, uid, parsed);
|
|
||||||
|
|
||||||
base = ptr+1;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = 1;
|
|
||||||
error:
|
|
||||||
if(str) free(str);
|
|
||||||
close(fd);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
int init_uniq(const char *path) {
|
|
||||||
static int _res;
|
|
||||||
static const char *_path;
|
|
||||||
|
|
||||||
_res = 1;
|
|
||||||
_path = path;
|
|
||||||
auto void cb(void *arg, int uid, const char *path) {
|
|
||||||
if(strcmp(path, _path) == 0)
|
|
||||||
_res = 0;
|
|
||||||
}
|
|
||||||
if(!init_foreach(cb, NULL))
|
|
||||||
return 0;
|
|
||||||
return _res;
|
|
||||||
}
|
|
||||||
|
|
||||||
int init_remove(const char *path, int uid) {
|
|
||||||
static int _found = 0;
|
|
||||||
static const char *_path;
|
|
||||||
static int fd;
|
|
||||||
static int _uid;
|
|
||||||
|
|
||||||
_path = path;
|
|
||||||
_found = 0;
|
|
||||||
_uid = uid;
|
|
||||||
|
|
||||||
unlink("/data/su/init.new");
|
|
||||||
fd = open("/data/su/init.new", O_WRONLY|O_CREAT, 0600);
|
|
||||||
if(fd<0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
auto void cb(void *arg, int uid, const char *path) {
|
|
||||||
//The one we want to drop
|
|
||||||
if(strcmp(path, _path) == 0 &&
|
|
||||||
(_uid == 0 || _uid == 2000 || uid == _uid)) {
|
|
||||||
_found = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
char *str = NULL;
|
|
||||||
int len = asprintf(&str, "%d:%s", uid, path);
|
|
||||||
write(fd, str, len+1); //len doesn't include final \0 and we want to write it
|
|
||||||
free(str);
|
|
||||||
}
|
|
||||||
init_foreach(cb, NULL);
|
|
||||||
close(fd);
|
|
||||||
unlink("/data/su/init");
|
|
||||||
rename("/data/su/init.new", "/data/su/init");
|
|
||||||
return _found;
|
|
||||||
}
|
|
||||||
|
|
||||||
void init_ls(int uid) {
|
|
||||||
static int _uid;
|
|
||||||
_uid = uid;
|
|
||||||
auto void cb(void *arg, int uid, const char *path) {
|
|
||||||
if(_uid == 2000 || _uid == 0 || _uid == uid)
|
|
||||||
fprintf(stderr, "%d %s\n", uid, path);
|
|
||||||
}
|
|
||||||
init_foreach(cb, NULL);
|
|
||||||
}
|
|
33
binds.h
33
binds.h
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2016, Pierre-Hugues Husson <phh@phh.me>
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program; if not, write to the Free Software Foundation,
|
|
||||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef BINDSH
|
|
||||||
#define BINDS_H
|
|
||||||
|
|
||||||
typedef void (*bind_cb)(void *arg, int uid, const char *src, const char *dst);
|
|
||||||
extern int bind_foreach(bind_cb cb, void* arg);
|
|
||||||
extern int bind_uniq_dst(const char *dst);
|
|
||||||
extern int bind_remove(const char *path, int uid);
|
|
||||||
extern void bind_ls(int uid);
|
|
||||||
|
|
||||||
typedef void (*init_cb)(void *arg, int uid, const char *path);
|
|
||||||
extern int init_foreach(init_cb cb, void* arg);
|
|
||||||
extern int init_uniq(const char *dst);
|
|
||||||
extern int init_remove(const char *path, int uid);
|
|
||||||
extern void init_ls(int uid);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* BINDS_H */
|
|
104
daemon.c
104
daemon.c
@ -47,7 +47,6 @@
|
|||||||
#include <cutils/multiuser.h>
|
#include <cutils/multiuser.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "binds.h"
|
|
||||||
#include "su.h"
|
#include "su.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "pts.h"
|
#include "pts.h"
|
||||||
@ -499,79 +498,68 @@ static void prepare_su_bind() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void prepare_binds() {
|
static void bind_cb_func(void *arg, int uid, const char *src, const char *dst) {
|
||||||
mkdir("/data/su", 0700);
|
int ret = 0, i = 0;
|
||||||
static int i = 0;
|
|
||||||
|
|
||||||
auto void cb(void *arg, int uid, const char *src, const char *dst) {
|
char *tmpfile = NULL;
|
||||||
int ret = 0;
|
asprintf(&tmpfile, "/dev/su/bind%d", i++);
|
||||||
|
struct stat stbuf;
|
||||||
|
ret = stat(src, &stbuf);
|
||||||
|
if(ret) {
|
||||||
|
free(tmpfile);
|
||||||
|
LOGE("Failed to stat src %s file", src);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
char *tmpfile = NULL;
|
//Only shell uid is allowed to bind files not his own
|
||||||
asprintf(&tmpfile, "/dev/su/bind%d", i++);
|
if(uid != 2000 && uid != stbuf.st_uid) {
|
||||||
struct stat stbuf;
|
LOGE("File %s has wrong owner: %d vs %d", src, uid, stbuf.st_uid);
|
||||||
ret = stat(src, &stbuf);
|
return;
|
||||||
if(ret) {
|
}
|
||||||
free(tmpfile);
|
|
||||||
LOGE("Failed to stat src %s file", src);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Only shell uid is allowed to bind files not his own
|
ret = copy_file(src, tmpfile, 0);
|
||||||
if(uid != 2000 && uid != stbuf.st_uid) {
|
if(ret) {
|
||||||
LOGE("File %s has wrong owner: %d vs %d", src, uid, stbuf.st_uid);
|
free(tmpfile);
|
||||||
return;
|
PLOGE("Failed to copy su");
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
chmod(tmpfile, stbuf.st_mode);
|
||||||
|
|
||||||
ret = copy_file(src, tmpfile, 0);
|
ret = setfilecon(tmpfile, "u:object_r:system_file:s0");
|
||||||
if(ret) {
|
if(ret) {
|
||||||
free(tmpfile);
|
LOGE("Failed to set file context");
|
||||||
PLOGE("Failed to copy su");
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
chmod(tmpfile, stbuf.st_mode);
|
|
||||||
|
|
||||||
ret = setfilecon(tmpfile, "u:object_r:system_file:s0");
|
ret = mount(tmpfile, dst, "", MS_BIND, NULL);
|
||||||
if(ret) {
|
if(ret) {
|
||||||
LOGE("Failed to set file context");
|
LOGE("Failed to mount bind");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = mount(tmpfile, dst, "", MS_BIND, NULL);
|
|
||||||
if(ret) {
|
|
||||||
LOGE("Failed to mount bind");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bind_foreach(cb, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_init() {
|
static void init_cb_func(void *arg, int uid, const char *path) {
|
||||||
auto void cb(void *arg, int uid, const char *path) {
|
int ret = 0;
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
int p = fork();
|
int p = fork();
|
||||||
if(p)
|
if(p)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
while(access("/system/bin/sh", R_OK)) sleep(1);
|
while(access("/system/bin/sh", R_OK)) sleep(1);
|
||||||
ret = setexeccon("u:r:su:s0");
|
ret = setexeccon("u:r:su:s0");
|
||||||
execl(path, path, NULL);
|
execl(path, path, NULL);
|
||||||
LOGE("Failed to execute %s. Trying as shell script, ret = %d", path, ret);
|
LOGE("Failed to execute %s. Trying as shell script, ret = %d", path, ret);
|
||||||
|
|
||||||
ret = setexeccon("u:r:su:s0");
|
ret = setexeccon("u:r:su:s0");
|
||||||
execl("/system/bin/sh", "/system/bin/sh", path, NULL);
|
execl("/system/bin/sh", "/system/bin/sh", path, NULL);
|
||||||
LOGE("Failed to execute %s as shell script", path);
|
LOGE("Failed to execute %s as shell script", path);
|
||||||
_exit(1);
|
_exit(1);
|
||||||
}
|
|
||||||
init_foreach(cb, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void prepare() {
|
static void prepare() {
|
||||||
setfscreatecon("u:object_r:su_daemon:s0");
|
setfscreatecon("u:object_r:su_daemon:s0");
|
||||||
mkdir("/dev/su", 0700);
|
mkdir("/dev/su", 0700);
|
||||||
prepare_su_bind();
|
prepare_su_bind();
|
||||||
prepare_binds();
|
|
||||||
do_init();
|
|
||||||
setfscreatecon(NULL);
|
setfscreatecon(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
187
su.c
187
su.c
@ -42,7 +42,6 @@
|
|||||||
|
|
||||||
#include "su.h"
|
#include "su.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "binds.h"
|
|
||||||
|
|
||||||
extern int is_daemon;
|
extern int is_daemon;
|
||||||
extern int daemon_from_uid;
|
extern int daemon_from_uid;
|
||||||
@ -470,70 +469,6 @@ static void usage(int status) {
|
|||||||
exit(status);
|
exit(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
static __attribute__ ((noreturn)) void allow_bind(struct su_context *ctx) {
|
|
||||||
if(ctx->from.uid == 0)
|
|
||||||
exit(1);
|
|
||||||
|
|
||||||
if(ctx->bind.from[0] == '!') {
|
|
||||||
int ret = bind_remove(ctx->bind.to, ctx->from.uid);
|
|
||||||
if(!ret) {
|
|
||||||
fprintf(stderr, "The mentioned bind destination path didn't exist\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
if(strcmp("--ls", ctx->bind.from)==0) {
|
|
||||||
bind_ls(ctx->from.uid);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!bind_uniq_dst(ctx->bind.to)) {
|
|
||||||
fprintf(stderr, "BIND: Distant file NOT unique. I refuse.\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
int fd = open("/data/su/binds", O_WRONLY|O_APPEND|O_CREAT, 0600);
|
|
||||||
if(fd<0) {
|
|
||||||
fprintf(stderr, "Failed to open binds file\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
char *str = NULL;
|
|
||||||
int len = asprintf(&str, "%d:%s:%s", ctx->from.uid, ctx->bind.from, ctx->bind.to);
|
|
||||||
write(fd, str, len+1); //len doesn't include final \0 and we want to write it
|
|
||||||
free(str);
|
|
||||||
close(fd);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static __attribute__ ((noreturn)) void allow_init(struct su_context *ctx) {
|
|
||||||
if(ctx->init[0]=='!') {
|
|
||||||
int ret = init_remove(ctx->init+1, ctx->from.uid);
|
|
||||||
if(!ret) {
|
|
||||||
fprintf(stderr, "The mentioned init path didn't exist\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
if(strcmp("--ls", ctx->init) == 0) {
|
|
||||||
init_ls(ctx->from.uid);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
if(!init_uniq(ctx->init))
|
|
||||||
//This script is already in init list
|
|
||||||
exit(1);
|
|
||||||
|
|
||||||
int fd = open("/data/su/init", O_WRONLY|O_APPEND|O_CREAT, 0600);
|
|
||||||
if(fd<0) {
|
|
||||||
fprintf(stderr, "Failed to open init file\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
char *str = NULL;
|
|
||||||
int len = asprintf(&str, "%d:%s", ctx->from.uid, ctx->init);
|
|
||||||
write(fd, str, len+1); //len doesn't include final \0 and we want to write it
|
|
||||||
free(str);
|
|
||||||
close(fd);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static __attribute__ ((noreturn)) void deny(struct su_context *ctx) {
|
static __attribute__ ((noreturn)) void deny(struct su_context *ctx) {
|
||||||
char *cmd = get_command(&ctx->to);
|
char *cmd = get_command(&ctx->to);
|
||||||
|
|
||||||
@ -575,11 +510,11 @@ static __attribute__ ((noreturn)) void allow(struct su_context *ctx) {
|
|||||||
if (send_to_app)
|
if (send_to_app)
|
||||||
send_result(ctx, ALLOW);
|
send_result(ctx, ALLOW);
|
||||||
|
|
||||||
if(ctx->bind.from[0] && ctx->bind.to[0])
|
// if(ctx->bind.from[0] && ctx->bind.to[0])
|
||||||
allow_bind(ctx);
|
// allow_bind(ctx);
|
||||||
|
|
||||||
if(ctx->init[0])
|
// if(ctx->init[0])
|
||||||
allow_init(ctx);
|
// allow_init(ctx);
|
||||||
|
|
||||||
char *binary;
|
char *binary;
|
||||||
argc = ctx->to.optind;
|
argc = ctx->to.optind;
|
||||||
@ -777,21 +712,14 @@ int su_main_nodaemon(int argc, char **argv) {
|
|||||||
.database_path = REQUESTOR_DATA_PATH REQUESTOR_DATABASE_PATH,
|
.database_path = REQUESTOR_DATA_PATH REQUESTOR_DATABASE_PATH,
|
||||||
.base_path = REQUESTOR_DATA_PATH REQUESTOR
|
.base_path = REQUESTOR_DATA_PATH REQUESTOR
|
||||||
},
|
},
|
||||||
.bind = {
|
|
||||||
.from = "",
|
|
||||||
.to = "",
|
|
||||||
},
|
|
||||||
.init = "",
|
|
||||||
};
|
};
|
||||||
struct stat st;
|
struct stat st;
|
||||||
int c, socket_serv_fd, fd;
|
int c, socket_serv_fd, fd;
|
||||||
char buf[64], *result;
|
char buf[64], *result;
|
||||||
policy_t dballow;
|
policy_t dballow;
|
||||||
struct option long_opts[] = {
|
struct option long_opts[] = {
|
||||||
{ "bind", required_argument, NULL, 'b' },
|
|
||||||
{ "command", required_argument, NULL, 'c' },
|
{ "command", required_argument, NULL, 'c' },
|
||||||
{ "help", no_argument, NULL, 'h' },
|
{ "help", no_argument, NULL, 'h' },
|
||||||
{ "init", required_argument, NULL, 'i' },
|
|
||||||
{ "login", no_argument, NULL, 'l' },
|
{ "login", no_argument, NULL, 'l' },
|
||||||
{ "preserve-environment", no_argument, NULL, 'p' },
|
{ "preserve-environment", no_argument, NULL, 'p' },
|
||||||
{ "shell", required_argument, NULL, 's' },
|
{ "shell", required_argument, NULL, 's' },
|
||||||
@ -800,71 +728,54 @@ int su_main_nodaemon(int argc, char **argv) {
|
|||||||
{ NULL, 0, NULL, 0 },
|
{ NULL, 0, NULL, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
while ((c = getopt_long(argc, argv, "+b:c:hlmps:Vvuz:", long_opts, NULL)) != -1) {
|
while ((c = getopt_long(argc, argv, "c:hlmps:Vvuz:", long_opts, NULL)) != -1) {
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case 'b': {
|
case 'c':
|
||||||
char *s = strdup(optarg);
|
ctx.to.shell = DEFAULT_SHELL;
|
||||||
|
ctx.to.command = optarg;
|
||||||
char *pos = strchr(s, ':');
|
break;
|
||||||
if(pos) {
|
case 'h':
|
||||||
pos[0] = 0;
|
usage(EXIT_SUCCESS);
|
||||||
ctx.bind.to = pos + 1;
|
break;
|
||||||
ctx.bind.from = s;
|
case 'l':
|
||||||
} else {
|
ctx.to.login = 1;
|
||||||
ctx.bind.from = "--ls";
|
break;
|
||||||
ctx.bind.to = "--ls";
|
case 'm':
|
||||||
}
|
case 'p':
|
||||||
|
ctx.to.keepenv = 1;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
ctx.to.shell = optarg;
|
||||||
|
break;
|
||||||
|
case 'V':
|
||||||
|
printf("%d\n", VERSION_CODE);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
case 'v':
|
||||||
|
printf("%s (topjohnwu v1)\n", VERSION);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
case 'u':
|
||||||
|
switch (get_multiuser_mode()) {
|
||||||
|
case MULTIUSER_MODE_USER:
|
||||||
|
printf("%s\n", MULTIUSER_VALUE_USER);
|
||||||
|
break;
|
||||||
|
case MULTIUSER_MODE_OWNER_MANAGED:
|
||||||
|
printf("%s\n", MULTIUSER_VALUE_OWNER_MANAGED);
|
||||||
|
break;
|
||||||
|
case MULTIUSER_MODE_OWNER_ONLY:
|
||||||
|
printf("%s\n", MULTIUSER_VALUE_OWNER_ONLY);
|
||||||
|
break;
|
||||||
|
case MULTIUSER_MODE_NONE:
|
||||||
|
printf("%s\n", MULTIUSER_VALUE_NONE);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
case 'z':
|
||||||
|
ctx.to.context = optarg;
|
||||||
break;
|
break;
|
||||||
case 'c':
|
default:
|
||||||
ctx.to.shell = DEFAULT_SHELL;
|
/* Bionic getopt_long doesn't terminate its error output by newline */
|
||||||
ctx.to.command = optarg;
|
fprintf(stderr, "\n");
|
||||||
break;
|
usage(2);
|
||||||
case 'h':
|
|
||||||
usage(EXIT_SUCCESS);
|
|
||||||
break;
|
|
||||||
case 'i':
|
|
||||||
ctx.init = optarg;
|
|
||||||
break;
|
|
||||||
case 'l':
|
|
||||||
ctx.to.login = 1;
|
|
||||||
break;
|
|
||||||
case 'm':
|
|
||||||
case 'p':
|
|
||||||
ctx.to.keepenv = 1;
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
ctx.to.shell = optarg;
|
|
||||||
break;
|
|
||||||
case 'V':
|
|
||||||
printf("%d\n", VERSION_CODE);
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
case 'v':
|
|
||||||
printf("%s cm-su subind suinit\n", VERSION);
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
case 'u':
|
|
||||||
switch (get_multiuser_mode()) {
|
|
||||||
case MULTIUSER_MODE_USER:
|
|
||||||
printf("%s\n", MULTIUSER_VALUE_USER);
|
|
||||||
break;
|
|
||||||
case MULTIUSER_MODE_OWNER_MANAGED:
|
|
||||||
printf("%s\n", MULTIUSER_VALUE_OWNER_MANAGED);
|
|
||||||
break;
|
|
||||||
case MULTIUSER_MODE_OWNER_ONLY:
|
|
||||||
printf("%s\n", MULTIUSER_VALUE_OWNER_ONLY);
|
|
||||||
break;
|
|
||||||
case MULTIUSER_MODE_NONE:
|
|
||||||
printf("%s\n", MULTIUSER_VALUE_NONE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
case 'z':
|
|
||||||
ctx.to.context = optarg;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* Bionic getopt_long doesn't terminate its error output by newline */
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
usage(2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hacks_init();
|
hacks_init();
|
||||||
|
Loading…
Reference in New Issue
Block a user