From 3d2ce33a7549ebf6379dc6d1d7ff8f829fb87705 Mon Sep 17 00:00:00 2001 From: arm64v8a <48624112+arm64v8a@users.noreply.github.com> Date: Tue, 2 May 2023 11:58:33 +0900 Subject: [PATCH] Optimize permission for linux --- main/NekoRay.cpp | 22 ++++++++++++++++++++++ main/NekoRay.hpp | 3 +++ main/NekoRay_DataStore.hpp | 1 + main/main.cpp | 1 + res/public/linux_pkexec.sh | 9 +++++++++ res/public/linux_pkexec_root.sh | 9 +++++++++ res/vpn/vpn-run-root.sh | 2 +- sys/ExternalProcess.cpp | 18 ++++++++++++++---- sys/ExternalProcess.hpp | 2 +- ui/mainwindow.cpp | 17 ++++++++++++----- 10 files changed, 73 insertions(+), 11 deletions(-) create mode 100644 res/public/linux_pkexec.sh create mode 100644 res/public/linux_pkexec_root.sh diff --git a/main/NekoRay.cpp b/main/NekoRay.cpp index 6d0dab8..aa57fe7 100644 --- a/main/NekoRay.cpp +++ b/main/NekoRay.cpp @@ -9,6 +9,12 @@ #include #include +#ifdef Q_OS_WIN +#include "sys/windows/guihelper.h" +#else +#include +#endif + namespace NekoRay { DataStore *dataStore = new DataStore(); @@ -371,4 +377,20 @@ namespace NekoRay { return {}; } + short isAdminCache = -1; + + bool isAdmin() { + if (isAdminCache >= 0) return isAdminCache; + + auto admin = NekoRay::dataStore->flag_linux_run_core_as_admin; +#ifdef Q_OS_WIN + admin = Windows_IsInAdmin(); +#else + admin |= geteuid() == 0; +#endif + + isAdminCache = admin; + return admin; + }; + } // namespace NekoRay diff --git a/main/NekoRay.hpp b/main/NekoRay.hpp index 2629b89..96d7ccb 100644 --- a/main/NekoRay.hpp +++ b/main/NekoRay.hpp @@ -11,6 +11,9 @@ namespace NekoRay { inline int coreType = NekoRay::CoreType::V2RAY; QString FindCoreAsset(const QString &name); + + bool isAdmin(); + } // namespace NekoRay #define IS_NEKO_BOX (NekoRay::coreType == NekoRay::CoreType::SING_BOX) diff --git a/main/NekoRay_DataStore.hpp b/main/NekoRay_DataStore.hpp index 99b3d8f..11fe718 100644 --- a/main/NekoRay_DataStore.hpp +++ b/main/NekoRay_DataStore.hpp @@ -71,6 +71,7 @@ namespace NekoRay { bool flag_many = false; bool flag_tray = false; bool flag_debug = false; + bool flag_linux_run_core_as_admin = false; // Saved diff --git a/main/main.cpp b/main/main.cpp index 35fb379..d31955f 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -81,6 +81,7 @@ int main(int argc, char* argv[]) { if (NekoRay::dataStore->argv.contains("-appdata")) NekoRay::dataStore->flag_use_appdata = true; if (NekoRay::dataStore->argv.contains("-tray")) NekoRay::dataStore->flag_tray = true; if (NekoRay::dataStore->argv.contains("-debug")) NekoRay::dataStore->flag_debug = true; + if (NekoRay::dataStore->argv.contains("-flag_linux_run_core_as_admin")) NekoRay::dataStore->flag_linux_run_core_as_admin = true; #ifdef NKR_CPP_USE_APPDATA NekoRay::dataStore->flag_use_appdata = true; // Example: Package & MacOS #endif diff --git a/res/public/linux_pkexec.sh b/res/public/linux_pkexec.sh new file mode 100644 index 0000000..9bfe24b --- /dev/null +++ b/res/public/linux_pkexec.sh @@ -0,0 +1,9 @@ +set -e + +command -v pkexec >/dev/null 2>&1 || echo "[Warning] pkexec not found" +command -v pkill >/dev/null 2>&1 || echo "[Warning] pkill not found" + +BASEDIR="$(dirname -- "$(readlink -f -- "$0")")" + +pkexec --keep-cwd \ + bash "$BASEDIR"/linux_pkexec_root.sh $@ diff --git a/res/public/linux_pkexec_root.sh b/res/public/linux_pkexec_root.sh new file mode 100644 index 0000000..f332ce6 --- /dev/null +++ b/res/public/linux_pkexec_root.sh @@ -0,0 +1,9 @@ +set -e + +if [ "$EUID" -ne 0 ]; then + echo "[Warning] Not running as root" +fi + +#echo $$ >$PID_FILE + +$@ diff --git a/res/vpn/vpn-run-root.sh b/res/vpn/vpn-run-root.sh index dae1523..9564611 100755 --- a/res/vpn/vpn-run-root.sh +++ b/res/vpn/vpn-run-root.sh @@ -11,7 +11,7 @@ if [ "$(uname)" == "Darwin" ]; then fi [ -z $TABLE_FWMARK ] && echo "Please set env TABLE_FWMARK" && exit -command -v pkill >/dev/null 2>&1 || exit +command -v pkill >/dev/null 2>&1 || echo "[Warning] pkill not found" BASEDIR=$(dirname "$0") cd $BASEDIR diff --git a/sys/ExternalProcess.cpp b/sys/ExternalProcess.cpp index da7513d..0648664 100644 --- a/sys/ExternalProcess.cpp +++ b/sys/ExternalProcess.cpp @@ -19,7 +19,7 @@ namespace NekoRay::sys { if (started) return; started = true; - if (show_log) { + if (managed) { connect(this, &QProcess::readyReadStandardOutput, this, [&]() { MW_show_log_ext_vt100(readAllStandardOutput().trimmed()); }); @@ -30,7 +30,7 @@ namespace NekoRay::sys { if (!killed) { crashed = true; MW_show_log_ext(tag, "errorOccurred:" + errorString()); - if (managed) MW_dialog_message("ExternalProcess", "Crashed"); + MW_dialog_message("ExternalProcess", "Crashed"); } }); connect(this, &QProcess::stateChanged, this, [&](QProcess::ProcessState state) { @@ -41,15 +41,26 @@ namespace NekoRay::sys { crashed = true; MW_show_log_ext(tag, "[Error] Program exited accidentally: " + errorString()); Kill(); - if (managed) MW_dialog_message("ExternalProcess", "Crashed"); + MW_dialog_message("ExternalProcess", "Crashed"); } } }); MW_show_log_ext(tag, "[Starting] " + env.join(" ") + " " + program + " " + arguments.join(" ")); } + QProcess::setEnvironment(env); + + if (NekoRay::dataStore->flag_linux_run_core_as_admin && dynamic_cast(this)) { + arguments.prepend(program); + arguments.prepend(QApplication::applicationDirPath() + "/linux_pkexec.sh"); + program = "bash"; + } + QProcess::setEnvironment(env); QProcess::start(program, arguments); + + // waitForStarted(); + // pid = processId(); } void ExternalProcess::Kill() { @@ -64,7 +75,6 @@ namespace NekoRay::sys { CoreProcess::CoreProcess(const QString &core_path, const QStringList &args) : ExternalProcess() { ExternalProcess::managed = false; - ExternalProcess::show_log = false; ExternalProcess::program = core_path; ExternalProcess::arguments = args; diff --git a/sys/ExternalProcess.hpp b/sys/ExternalProcess.hpp index 71870f9..3da532f 100644 --- a/sys/ExternalProcess.hpp +++ b/sys/ExternalProcess.hpp @@ -9,9 +9,9 @@ namespace NekoRay::sys { QString program; QStringList arguments; QStringList env; + qint64 pid = 0; bool managed = true; // MW_dialog_message - bool show_log = true; ExternalProcess(); ~ExternalProcess(); diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index 351dd45..5895441 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -640,6 +640,7 @@ void MainWindow::on_menu_exit_triggered() { QProcess::startDetached("./updater", QStringList{}); } else if (exit_reason == 2 || exit_reason == 3) { QDir::setCurrent(QApplication::applicationDirPath()); + auto arguments = NekoRay::dataStore->argv; if (arguments.length() > 0) arguments.removeFirst(); auto isLauncher = qEnvironmentVariable("NKR_FROM_LAUNCHER") == "1"; @@ -649,6 +650,9 @@ void MainWindow::on_menu_exit_triggered() { if (exit_reason == 3) { // restart as admin #ifdef Q_OS_WIN WinCommander::runProcessElevated(program, arguments, "", WinCommander::SW_NORMAL, false); +#else + arguments << "-flag_linux_run_core_as_admin"; + QProcess::startDetached(program, arguments); #endif } else { QProcess::startDetached(program, arguments); @@ -701,8 +705,15 @@ void MainWindow::neko_set_spmode_vpn(bool enable, bool save) { if (enable != NekoRay::dataStore->spmode_vpn) { if (enable) { if (IS_NEKO_BOX_INTERNAL_TUN) { + bool requestPermission = false; #ifdef Q_OS_WIN if (!Windows_IsInAdmin()) { + requestPermission = true; + } +#else + requestPermission = !NekoRay::isAdmin(); +#endif + if (requestPermission) { auto n = QMessageBox::warning(GetMessageBoxParent(), software_name, tr("Please run NekoBox as admin"), QMessageBox::Yes | QMessageBox::No); if (n == QMessageBox::Yes) { this->exit_reason = 3; @@ -710,8 +721,6 @@ void MainWindow::neko_set_spmode_vpn(bool enable, bool save) { } neko_set_spmode_FAILED } -#endif - // TODO check permission for Linux } else { if (NekoRay::dataStore->need_keep_vpn_off) { MessageBoxWarning(software_name, tr("Current server is incompatible with VPN. Please stop the server first, enable VPN mode, and then restart.")); @@ -781,9 +790,7 @@ void MainWindow::refresh_status(const QString &traffic_update) { auto make_title = [=](bool isTray) { QStringList tt; -#ifdef Q_OS_WIN - if (!isTray && Windows_IsInAdmin()) tt << "[Admin]"; -#endif + if (!isTray && NekoRay::isAdmin()) tt << "[Admin]"; if (select_mode) tt << "[" + tr("Select") + "]"; if (!title_error.isEmpty()) tt << "[" + title_error + "]"; if (NekoRay::dataStore->spmode_vpn) tt << "[VPN]";