2018-06-13 04:34:05 +08:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
#include "magisk.h"
|
|
|
|
#include "db.h"
|
|
|
|
|
2018-11-01 13:23:12 -04:00
|
|
|
#define DB_VERSION 7
|
2018-10-28 14:49:04 -04:00
|
|
|
|
2018-11-04 18:24:08 -05:00
|
|
|
db_strings::db_strings() {
|
|
|
|
memset(data, 0, sizeof(data));
|
|
|
|
}
|
|
|
|
|
|
|
|
char *db_strings::operator[](const char *key) {
|
|
|
|
return data[getKeyIdx(key)];
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *db_strings::operator[](const char *key) const {
|
|
|
|
return data[getKeyIdx(key)];
|
|
|
|
}
|
|
|
|
|
|
|
|
char *db_strings::operator[](const int idx) {
|
|
|
|
return data[idx];
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *db_strings::operator[](const int idx) const {
|
|
|
|
return data[idx];
|
|
|
|
}
|
|
|
|
|
|
|
|
int db_strings::getKeyIdx(const char *key) const {
|
|
|
|
int idx = DB_STRING_NUM;
|
|
|
|
for (int i = 0; i < DB_STRING_NUM; ++i) {
|
|
|
|
if (strcmp(key, DB_STRING_KEYS[i]) == 0)
|
|
|
|
idx = i;
|
|
|
|
}
|
|
|
|
return idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
db_settings::db_settings() : data {
|
|
|
|
ROOT_ACCESS_APPS_AND_ADB,
|
|
|
|
MULTIUSER_MODE_OWNER_ONLY,
|
|
|
|
NAMESPACE_MODE_REQUESTER
|
|
|
|
} {}
|
|
|
|
|
|
|
|
int &db_settings::operator[](const int idx) {
|
|
|
|
return data[idx];
|
|
|
|
}
|
|
|
|
|
|
|
|
const int &db_settings::operator[](const int idx) const {
|
|
|
|
return data[idx];
|
|
|
|
}
|
|
|
|
|
|
|
|
int &db_settings::operator[](const char *key) {
|
|
|
|
return data[getKeyIdx(key)];
|
|
|
|
}
|
|
|
|
|
|
|
|
const int &db_settings::operator[](const char *key) const {
|
|
|
|
return data[getKeyIdx(key)];
|
|
|
|
}
|
|
|
|
|
|
|
|
int db_settings::getKeyIdx(const char *key) const {
|
|
|
|
int idx = DB_SETTINGS_NUM;
|
|
|
|
for (int i = 0; i < DB_SETTINGS_NUM; ++i) {
|
|
|
|
if (strcmp(key, DB_SETTING_KEYS[i]) == 0)
|
|
|
|
idx = i;
|
|
|
|
}
|
|
|
|
return idx;
|
|
|
|
}
|
|
|
|
|
2018-11-04 03:38:06 -05:00
|
|
|
static int ver_cb(void *ver, int, char **data, char **) {
|
|
|
|
*((int *) ver) = atoi(data[0]);
|
2018-06-13 04:34:05 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-10-28 14:49:04 -04:00
|
|
|
#define err_abort(err) \
|
|
|
|
if (err) { \
|
|
|
|
LOGE("sqlite3_exec: %s\n", err); \
|
|
|
|
sqlite3_free(err); \
|
2018-11-04 03:38:06 -05:00
|
|
|
return nullptr; \
|
2018-10-28 14:49:04 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static sqlite3 *open_and_init_db() {
|
2018-10-27 17:54:48 -04:00
|
|
|
sqlite3 *db;
|
|
|
|
int ret = sqlite3_open(MAGISKDB, &db);
|
|
|
|
if (ret) {
|
|
|
|
LOGE("sqlite3 open failure: %s\n", sqlite3_errstr(ret));
|
2018-11-04 03:38:06 -05:00
|
|
|
return nullptr;
|
2018-10-27 17:54:48 -04:00
|
|
|
}
|
|
|
|
int ver, upgrade = 0;
|
2018-10-28 14:49:04 -04:00
|
|
|
char *err;
|
|
|
|
sqlite3_exec(db, "PRAGMA user_version", ver_cb, &ver, &err);
|
|
|
|
err_abort(err);
|
|
|
|
if (ver > DB_VERSION) {
|
|
|
|
// Don't support downgrading database
|
|
|
|
sqlite3_close_v2(db);
|
2018-11-04 03:38:06 -05:00
|
|
|
return nullptr;
|
2018-10-28 14:49:04 -04:00
|
|
|
}
|
2018-10-27 17:54:48 -04:00
|
|
|
if (ver < 3) {
|
|
|
|
// Policies
|
|
|
|
sqlite3_exec(db,
|
|
|
|
"CREATE TABLE IF NOT EXISTS policies "
|
|
|
|
"(uid INT, package_name TEXT, policy INT, until INT, "
|
|
|
|
"logging INT, notification INT, PRIMARY KEY(uid))",
|
2018-11-04 03:38:06 -05:00
|
|
|
nullptr, nullptr, &err);
|
2018-10-28 14:49:04 -04:00
|
|
|
err_abort(err);
|
2018-10-27 17:54:48 -04:00
|
|
|
// Logs
|
|
|
|
sqlite3_exec(db,
|
|
|
|
"CREATE TABLE IF NOT EXISTS logs "
|
|
|
|
"(from_uid INT, package_name TEXT, app_name TEXT, from_pid INT, "
|
|
|
|
"to_uid INT, action INT, time INT, command TEXT)",
|
2018-11-04 03:38:06 -05:00
|
|
|
nullptr, nullptr, &err);
|
2018-10-28 14:49:04 -04:00
|
|
|
err_abort(err);
|
2018-10-27 17:54:48 -04:00
|
|
|
// Settings
|
|
|
|
sqlite3_exec(db,
|
|
|
|
"CREATE TABLE IF NOT EXISTS settings "
|
|
|
|
"(key TEXT, value INT, PRIMARY KEY(key))",
|
2018-11-04 03:38:06 -05:00
|
|
|
nullptr, nullptr, &err);
|
2018-10-28 14:49:04 -04:00
|
|
|
err_abort(err);
|
2018-10-27 17:54:48 -04:00
|
|
|
ver = 3;
|
|
|
|
upgrade = 1;
|
|
|
|
}
|
|
|
|
if (ver == 3) {
|
|
|
|
// Strings
|
|
|
|
sqlite3_exec(db,
|
|
|
|
"CREATE TABLE IF NOT EXISTS strings "
|
|
|
|
"(key TEXT, value TEXT, PRIMARY KEY(key))",
|
2018-11-04 03:38:06 -05:00
|
|
|
nullptr, nullptr, &err);
|
2018-10-28 14:49:04 -04:00
|
|
|
err_abort(err);
|
2018-10-27 17:54:48 -04:00
|
|
|
ver = 4;
|
|
|
|
upgrade = 1;
|
|
|
|
}
|
|
|
|
if (ver == 4) {
|
2018-11-04 03:38:06 -05:00
|
|
|
sqlite3_exec(db, "UPDATE policies SET uid=uid%100000", nullptr, nullptr, &err);
|
2018-10-28 14:49:04 -04:00
|
|
|
err_abort(err);
|
2018-10-27 17:54:48 -04:00
|
|
|
/* Skip version 5 */
|
|
|
|
ver = 6;
|
|
|
|
upgrade = 1;
|
|
|
|
}
|
2018-11-01 13:23:12 -04:00
|
|
|
if (ver == 5 || ver == 6) {
|
|
|
|
// Hide list
|
|
|
|
sqlite3_exec(db,
|
|
|
|
"CREATE TABLE IF NOT EXISTS hidelist "
|
|
|
|
"(process TEXT, PRIMARY KEY(process))",
|
2018-11-04 03:38:06 -05:00
|
|
|
nullptr, nullptr, &err);
|
2018-11-01 13:23:12 -04:00
|
|
|
err_abort(err);
|
|
|
|
ver = 7;
|
|
|
|
upgrade =1 ;
|
|
|
|
}
|
2018-10-27 17:54:48 -04:00
|
|
|
|
|
|
|
if (upgrade) {
|
|
|
|
// Set version
|
|
|
|
char query[32];
|
|
|
|
sprintf(query, "PRAGMA user_version=%d", ver);
|
2018-11-04 03:38:06 -05:00
|
|
|
sqlite3_exec(db, query, nullptr, nullptr, &err);
|
2018-10-28 14:49:04 -04:00
|
|
|
err_abort(err);
|
|
|
|
}
|
|
|
|
return db;
|
|
|
|
}
|
|
|
|
|
|
|
|
sqlite3 *get_magiskdb() {
|
|
|
|
sqlite3 *db = open_and_init_db();
|
2018-11-04 03:38:06 -05:00
|
|
|
if (db == nullptr) {
|
2018-10-28 14:49:04 -04:00
|
|
|
// Open fails, remove and reconstruct
|
|
|
|
unlink(MAGISKDB);
|
|
|
|
db = open_and_init_db();
|
2018-10-27 17:54:48 -04:00
|
|
|
}
|
|
|
|
return db;
|
|
|
|
}
|
|
|
|
|
2018-06-13 04:34:05 +08:00
|
|
|
static int settings_cb(void *v, int col_num, char **data, char **col_name) {
|
2018-11-04 18:24:08 -05:00
|
|
|
auto &cfg = *(db_settings *) v;
|
|
|
|
int value = -1;
|
|
|
|
const char *key = "";
|
2018-06-13 04:34:05 +08:00
|
|
|
for (int i = 0; i < col_num; ++i) {
|
|
|
|
if (strcmp(col_name[i], "key") == 0) {
|
2018-11-04 18:24:08 -05:00
|
|
|
key = data[i];
|
2018-06-13 04:34:05 +08:00
|
|
|
} else if (strcmp(col_name[i], "value") == 0) {
|
|
|
|
value = atoi(data[i]);
|
|
|
|
}
|
|
|
|
}
|
2018-11-04 18:24:08 -05:00
|
|
|
if (key[0] && value >= 0) {
|
|
|
|
cfg[key] = value;
|
|
|
|
LOGD("magiskdb: query %s=[%d]\n", key, value);
|
2018-06-13 04:34:05 +08:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-04 18:24:08 -05:00
|
|
|
int get_db_settings(sqlite3 *db, struct db_settings *dbs, int key) {
|
2018-11-04 03:38:06 -05:00
|
|
|
if (db == nullptr)
|
2018-10-27 17:54:48 -04:00
|
|
|
return 1;
|
|
|
|
char *err;
|
|
|
|
if (key > 0) {
|
|
|
|
char query[128];
|
2018-10-27 17:56:20 -04:00
|
|
|
sprintf(query, "SELECT key, value FROM settings WHERE key='%s'", DB_SETTING_KEYS[key]);
|
2018-10-27 17:54:48 -04:00
|
|
|
sqlite3_exec(db, query, settings_cb, dbs, &err);
|
|
|
|
} else {
|
|
|
|
sqlite3_exec(db, "SELECT key, value FROM settings", settings_cb, dbs, &err);
|
|
|
|
}
|
|
|
|
if (err) {
|
|
|
|
LOGE("sqlite3_exec: %s\n", err);
|
2018-10-27 22:06:24 -04:00
|
|
|
sqlite3_free(err);
|
2018-10-27 17:54:48 -04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-06-13 04:34:05 +08:00
|
|
|
static int strings_cb(void *v, int col_num, char **data, char **col_name) {
|
2018-11-04 18:24:08 -05:00
|
|
|
auto &str = *(db_strings *) v;
|
|
|
|
const char *key = "", *value = "";
|
2018-06-13 04:34:05 +08:00
|
|
|
for (int i = 0; i < col_num; ++i) {
|
|
|
|
if (strcmp(col_name[i], "key") == 0) {
|
2018-11-04 18:24:08 -05:00
|
|
|
key = data[i];
|
2018-06-13 04:34:05 +08:00
|
|
|
} else if (strcmp(col_name[i], "value") == 0) {
|
|
|
|
value = data[i];
|
|
|
|
}
|
|
|
|
}
|
2018-11-04 18:24:08 -05:00
|
|
|
if (key[0] && value[0]) {
|
|
|
|
strcpy(str[key], value);
|
|
|
|
LOGD("magiskdb: query %s=[%s]\n", key, value);
|
2018-06-13 04:34:05 +08:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-04 18:24:08 -05:00
|
|
|
int get_db_strings(sqlite3 *db, struct db_strings *str, int key) {
|
2018-11-04 03:38:06 -05:00
|
|
|
if (db == nullptr)
|
2018-06-14 05:09:54 +08:00
|
|
|
return 1;
|
2018-06-13 04:34:05 +08:00
|
|
|
char *err;
|
|
|
|
if (key > 0) {
|
|
|
|
char query[128];
|
2018-10-27 17:56:20 -04:00
|
|
|
sprintf(query, "SELECT key, value FROM strings WHERE key='%s'", DB_STRING_KEYS[key]);
|
2018-06-13 04:34:05 +08:00
|
|
|
sqlite3_exec(db, query, strings_cb, str, &err);
|
|
|
|
} else {
|
|
|
|
sqlite3_exec(db, "SELECT key, value FROM strings", strings_cb, str, &err);
|
|
|
|
}
|
|
|
|
if (err) {
|
|
|
|
LOGE("sqlite3_exec: %s\n", err);
|
2018-10-27 22:06:24 -04:00
|
|
|
sqlite3_free(err);
|
2018-06-13 04:34:05 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-10-27 17:54:48 -04:00
|
|
|
static int policy_cb(void *v, int col_num, char **data, char **col_name) {
|
2018-11-04 03:38:06 -05:00
|
|
|
auto su = (su_access *) v;
|
2018-10-27 17:54:48 -04:00
|
|
|
for (int i = 0; i < col_num; i++) {
|
|
|
|
if (strcmp(col_name[i], "policy") == 0)
|
|
|
|
su->policy = (policy_t) atoi(data[i]);
|
|
|
|
else if (strcmp(col_name[i], "logging") == 0)
|
|
|
|
su->log = atoi(data[i]);
|
|
|
|
else if (strcmp(col_name[i], "notification") == 0)
|
|
|
|
su->notify = atoi(data[i]);
|
|
|
|
}
|
|
|
|
LOGD("magiskdb: query policy=[%d] log=[%d] notify=[%d]\n", su->policy, su->log, su->notify);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-06-13 04:34:05 +08:00
|
|
|
int get_uid_policy(sqlite3 *db, int uid, struct su_access *su) {
|
2018-11-04 03:38:06 -05:00
|
|
|
if (db == nullptr)
|
2018-06-14 05:09:54 +08:00
|
|
|
return 1;
|
2018-06-13 04:34:05 +08:00
|
|
|
char query[256], *err;
|
|
|
|
sprintf(query, "SELECT policy, logging, notification FROM policies "
|
2018-11-04 03:38:06 -05:00
|
|
|
"WHERE uid=%d AND (until=0 OR until>%li)", uid, time(nullptr));
|
2018-06-13 04:34:05 +08:00
|
|
|
sqlite3_exec(db, query, policy_cb, su, &err);
|
|
|
|
if (err) {
|
|
|
|
LOGE("sqlite3_exec: %s\n", err);
|
2018-10-27 22:06:24 -04:00
|
|
|
sqlite3_free(err);
|
2018-06-13 04:34:05 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-10-27 17:54:48 -04:00
|
|
|
int validate_manager(char *alt_pkg, int userid, struct stat *st) {
|
2018-11-04 03:38:06 -05:00
|
|
|
if (st == nullptr) {
|
2018-06-13 04:34:05 +08:00
|
|
|
struct stat stat;
|
|
|
|
st = &stat;
|
|
|
|
}
|
|
|
|
// Prefer DE storage
|
|
|
|
const char *base = access("/data/user_de", F_OK) == 0 ? "/data/user_de" : "/data/user";
|
|
|
|
char app_path[128];
|
2018-10-27 17:54:48 -04:00
|
|
|
sprintf(app_path, "%s/%d/%s", base, userid, alt_pkg[0] ? alt_pkg : "xxx");
|
2018-06-13 04:34:05 +08:00
|
|
|
if (stat(app_path, st)) {
|
|
|
|
// Check the official package name
|
2018-11-04 03:38:06 -05:00
|
|
|
sprintf(app_path, "%s/%d/" JAVA_PACKAGE_NAME, base, userid);
|
2018-06-13 04:34:05 +08:00
|
|
|
if (stat(app_path, st)) {
|
|
|
|
LOGE("su: cannot find manager");
|
|
|
|
memset(st, 0, sizeof(*st));
|
2018-10-27 17:54:48 -04:00
|
|
|
alt_pkg[0] = '\0';
|
2018-06-13 04:34:05 +08:00
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
// Switch to official package if exists
|
2018-10-27 17:54:48 -04:00
|
|
|
strcpy(alt_pkg, JAVA_PACKAGE_NAME);
|
2018-06-13 04:34:05 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2018-10-27 17:54:48 -04:00
|
|
|
|
|
|
|
static int print_cb(void *v, int col_num, char **data, char **col_name) {
|
|
|
|
for (int i = 0; i < col_num; ++i) {
|
|
|
|
if (i) printf("|");
|
|
|
|
printf("%s=%s", col_name[i], data[i]);
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int exec_sql(const char *sql) {
|
|
|
|
sqlite3 *db = get_magiskdb();
|
|
|
|
if (db) {
|
|
|
|
char *err;
|
2018-11-04 03:38:06 -05:00
|
|
|
sqlite3_exec(db, sql, print_cb, nullptr, &err);
|
2018-10-27 17:54:48 -04:00
|
|
|
sqlite3_close_v2(db);
|
|
|
|
if (err) {
|
|
|
|
fprintf(stderr, "sql_err: %s\n", err);
|
|
|
|
sqlite3_free(err);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|