From c1287779c23cf7218ebde32995bf1c1fdb8ec222 Mon Sep 17 00:00:00 2001 From: moonshadow565 Date: Tue, 8 Aug 2023 20:45:23 +0200 Subject: [PATCH] fix macos elevation --- .github/workflows/builditmac.yaml | 11 +-- CMakeLists.txt | 4 +- cslol-tools/lib/lol/io/sys.cpp | 2 +- cslol-tools/lib/lol/patcher/utility/delay.hpp | 4 +- cslol-tools/lib/lol/utility/zip.cpp | 2 +- cslol-tools/lib/lol/wad/toc.hpp | 8 +- cslol-tools/src/main_wad_extract.cpp | 2 +- make-release-mac.sh | 24 ++++++ src/CSLOLToolsImpl.cpp | 8 +- src/CSLOLUtils.cpp | 81 +++++++++++++++++-- src/CSLOLUtils.h | 3 +- src/main.cpp | 2 + src/main_elevate.c | 48 ----------- 13 files changed, 118 insertions(+), 81 deletions(-) create mode 100755 make-release-mac.sh delete mode 100644 src/main_elevate.c diff --git a/.github/workflows/builditmac.yaml b/.github/workflows/builditmac.yaml index b9d091f5..19c31fb9 100644 --- a/.github/workflows/builditmac.yaml +++ b/.github/workflows/builditmac.yaml @@ -20,16 +20,7 @@ jobs: - name: "Package" shell: bash run: | - mkdir cslol-manager-macos - cp LICENSE cslol-manager-macos/ - cp dist/SOURCE.URL cslol-manager-macos/ - cp build/cslol-tools/wad-* cslol-manager-macos/ - cp -R build/cslol-manager.app cslol-manager-macos/ - cp build/cslol-manager-elevate cslol-manager-macos/cslol-manager.app/Contents/MacOS/ - plutil -replace CFBundleExecutable -string cslol-manager-elevate cslol-manager-macos/cslol-manager.app/Contents/Info.plist - plutil -replace CFBundleName -string cslol-manager-elevate cslol-manager-macos/cslol-manager.app/Contents/Info.plist - mkdir cslol-manager-macos/cslol-manager.app/Contents/MacOS/cslol-tools - cp build/cslol-tools/mod-tools cslol-manager-macos/cslol-manager.app/Contents/MacOS/cslol-tools + ./make-release-mac.sh "build" "cslol-manager-macos" tar caf cslol-manager-macos.tar.xz cslol-manager-macos/ - name: 'Upload Artifact' uses: actions/upload-artifact@v2 diff --git a/CMakeLists.txt b/CMakeLists.txt index 3be922c0..5c14784d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,9 +53,7 @@ elseif(APPLE) src/main.cpp src/res/icon.icns ) - add_executable(cslol-manager-elevate - src/main_elevate.c - ) + target_link_libraries(cslol-manager PRIVATE "-framework Security") set_target_properties(cslol-manager PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/src/res/MacOSXBundleInfo.plist.in" diff --git a/cslol-tools/lib/lol/io/sys.cpp b/cslol-tools/lib/lol/io/sys.cpp index 6bae5bb3..e86848ef 100644 --- a/cslol-tools/lib/lol/io/sys.cpp +++ b/cslol-tools/lib/lol/io/sys.cpp @@ -98,7 +98,7 @@ static struct ResourceLimit { public: ResourceLimit() { rlimit resourceLimit; getrlimit(RLIMIT_NOFILE, &resourceLimit); - resourceLimit.rlim_cur = resourceLimit.rlim_max; + resourceLimit.rlim_cur = resourceLimit.rlim_max == RLIM_INFINITY ? 65000 : resourceLimit.rlim_max - 1; setrlimit(RLIMIT_NOFILE, &resourceLimit); } } resourceLimit_ = {}; diff --git a/cslol-tools/lib/lol/patcher/utility/delay.hpp b/cslol-tools/lib/lol/patcher/utility/delay.hpp index 720d0bd9..c4a07d61 100644 --- a/cslol-tools/lib/lol/patcher/utility/delay.hpp +++ b/cslol-tools/lib/lol/patcher/utility/delay.hpp @@ -24,8 +24,8 @@ namespace lol { Intervals() -> Intervals<1>; - template - inline auto run_until_or(auto deadline, Intervals intervals, auto&& poll, auto&& fail) { + template + inline auto run_until_or(D deadline, Intervals intervals, P&& poll, F&& fail) { auto total = static_cast(std::chrono::duration_cast(deadline).count()); for (auto interval : intervals.intervals) { auto slice = total / S; diff --git a/cslol-tools/lib/lol/utility/zip.cpp b/cslol-tools/lib/lol/utility/zip.cpp index 591cc9ce..a36933f9 100644 --- a/cslol-tools/lib/lol/utility/zip.cpp +++ b/cslol-tools/lib/lol/utility/zip.cpp @@ -49,7 +49,7 @@ auto utility::unzip(fs::path const& src, fs::path const& dst) -> void { mz_zip_archive_file_stat stat = {}; lol_throw_if_zip(mz_zip_reader_file_stat, zip.get(), index, &stat); if (stat.m_is_directory || !stat.m_is_supported) continue; - auto file_path = fs::path((char8_t const*)stat.m_filename).lexically_normal(); + auto file_path = fs::path((char const*)stat.m_filename).lexically_normal(); for (auto const& component : file_path) { lol_throw_if(component == ".."); } diff --git a/cslol-tools/lib/lol/wad/toc.hpp b/cslol-tools/lib/lol/wad/toc.hpp index 80716eeb..302a58a7 100644 --- a/cslol-tools/lib/lol/wad/toc.hpp +++ b/cslol-tools/lib/lol/wad/toc.hpp @@ -16,8 +16,12 @@ namespace lol::wad { inline bool is_wad() const noexcept { return magic == std::array{'R', 'W'}; } - constexpr bool operator==(Version const&) const noexcept = default; - constexpr auto operator<=>(Version const&) const noexcept = default; + bool operator==(Version const& other) const noexcept { + return magic == other.magic && major == other.major && minor == other.minor; + } + bool operator!=(Version const& other) const noexcept { + return !(*this == other); + } }; using Signature = std::array; diff --git a/cslol-tools/src/main_wad_extract.cpp b/cslol-tools/src/main_wad_extract.cpp index ffd8289e..c292d781 100644 --- a/cslol-tools/src/main_wad_extract.cpp +++ b/cslol-tools/src/main_wad_extract.cpp @@ -15,7 +15,7 @@ static auto wad_extract(fs::path src, fs::path dst, fs::path hashdict) -> void { if (dst.empty()) { dst = src; if (dst.extension().empty()) { - dst.replace_extension(u8".wad"); + dst.replace_extension(".wad"); } else { dst.replace_extension(); } diff --git a/make-release-mac.sh b/make-release-mac.sh new file mode 100755 index 00000000..d6d4fd2e --- /dev/null +++ b/make-release-mac.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +copy2folder() { + mkdir -p "$2" + + cp "./dist/SOURCE.URL" "$2" + cp "./LICENSE" "$2" + + cp -R "$1/cslol-manager.app" "$2" + mkdir -p "$2/cslol-manager.app/Contents/MacOS/cslol-tools" + cp "$1/cslol-tools/mod-tools" "$2/cslol-manager.app/Contents/MacOS/cslol-tools" + cp "$1/cslol-tools/wad-"* "$2" +} + +VERSION=$(git log --date=short --format="%ad-%h" -1) +echo "Version: $VERSION" + +if [ "$#" -gt 0 ] && [ -d "$1" ]; then + copy2folder "$1" "cslol-manager-macos" + echo "Version: $VERSION" > "cslol-manager-macos/version.txt" +else + echo "Error: Provide at least one valid path." + exit +fi; diff --git a/src/CSLOLToolsImpl.cpp b/src/CSLOLToolsImpl.cpp index 21672650..9787123f 100644 --- a/src/CSLOLToolsImpl.cpp +++ b/src/CSLOLToolsImpl.cpp @@ -281,10 +281,10 @@ void CSLOLToolsImpl::init() { if (state_ == CSLOLState::StateUnitialized) { setState(CSLOLState::StateBusy); - if (CSLOLUtils utils{}; utils.isUnnecessaryAdmin()) { - doReportError("Unnecessary admin", - "Try running without admin at least once.\nIf this issue still persist import FIX-ADMIN.reg", - "Running as admin is disabled by default"); + if (QString error = CSLOLUtils::isPlatformUnsuported(); !error.isEmpty()) { + doReportError("Unsupported platform", + error, + "Application launched on unsupported machine or configuration."); setState(CSLOLState::StateCriticalError); return; } diff --git a/src/CSLOLUtils.cpp b/src/CSLOLUtils.cpp index 1dea6911..42e273c8 100644 --- a/src/CSLOLUtils.cpp +++ b/src/CSLOLUtils.cpp @@ -102,26 +102,38 @@ QString CSLOLUtils::detectGamePath() { return ""; } -bool CSLOLUtils::isUnnecessaryAdmin() { - return false; +QString CSLOLUtils::isPlatformUnsuported() { if (QFileInfo info(QCoreApplication::applicationDirPath() + "/admin_allowed.txt"); info.exists()) { - return false; + return ""; } - bool result = 0; + + QString result{""}; + return result; + HANDLE token = {}; if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) { TOKEN_ELEVATION elevation = {}; DWORD size = sizeof(TOKEN_ELEVATION); if (GetTokenInformation(token, TokenElevation, &elevation, sizeof(elevation), &size)) { - result = elevation.TokenIsElevated; + if (elevation.TokenIsElevated) { + result = "Try running without admin at least once.\nIf this issue still persist import FIX-ADMIN.reg"; + } } CloseHandle(token); } return result; } + +void CSLOLUtils::relaunchAdmin(int argc, char *argv[]) {} #elif defined(__APPLE__) # include +# include # include +# include +# include +# include +# include +# include QString CSLOLUtils::detectGamePath() { pid_t *pid_list; @@ -200,11 +212,64 @@ QString CSLOLUtils::detectGamePath() { return ""; } -// TODO: macos implementation -bool CSLOLUtils::isUnnecessaryAdmin() { return false; } +QString CSLOLUtils::isPlatformUnsuported() { + int ret = 0; + size_t size = sizeof(ret); + if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == 0 && ret == 1) { + return QString{"Apple silicon (M1, M2...) macs are not supported.\nOnly intel based macs are supported."}; + } + return QString{""}; +} + +void CSLOLUtils::relaunchAdmin(int argc, char *argv[]) { + QCoreApplication::setSetuidAllowed(true); + char path[PATH_MAX]; + uint32_t path_max_size = PATH_MAX; + if (_NSGetExecutablePath(path, &path_max_size) != KERN_SUCCESS) { + return; + } + + if (argc > 1 && strcmp(argv[1], "admin") == 0) { + puts("Authed!"); + return; + } + + AuthorizationRef authorizationRef; + OSStatus createStatus = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorizationRef); + if (createStatus != errAuthorizationSuccess) { + fprintf(stderr, "Failed to create auth!\n"); + return; + } + + AuthorizationItem right = {kAuthorizationRightExecute, 0, NULL, 0}; + AuthorizationRights rights = {1, &right}; + AuthorizationFlags flags = kAuthorizationFlagDefaults + | kAuthorizationFlagInteractionAllowed + | kAuthorizationFlagExtendRights; + OSStatus copyStatus = AuthorizationCopyRights(authorizationRef, &rights, NULL, flags, NULL); + if (copyStatus != errAuthorizationSuccess) { + fprintf(stderr, "Failed to create copy!\n"); + return; + } + + char* args[] = { strdup("admin"), NULL }; + FILE* pipe = NULL; + + OSStatus execStatus = AuthorizationExecuteWithPrivileges(authorizationRef, path, kAuthorizationFlagDefaults, args, &pipe); + if (execStatus != errAuthorizationSuccess) { + fprintf(stderr, "Failed to exec auth: %x\n", execStatus); + return; + } + + AuthorizationFree(authorizationRef, kAuthorizationFlagDestroyRights); + + exit(0); +} #else QString CSLOLUtils::detectGamePath() { return ""; } -bool CSLOLUtils::isUnnecessaryAdmin() { return false; } +QString CSLOLUtils::isPlatformUnsuported() { return QString{""}; } + +void CSLOLUtils::relaunchAdmin(int argc, char *argv[]) {} #endif diff --git a/src/CSLOLUtils.h b/src/CSLOLUtils.h index bd19e035..c1126f57 100644 --- a/src/CSLOLUtils.h +++ b/src/CSLOLUtils.h @@ -14,8 +14,9 @@ class CSLOLUtils : public QObject { Q_INVOKABLE QString toFile(QString file); Q_INVOKABLE QString checkGamePath(QString path); Q_INVOKABLE QString detectGamePath(); - Q_INVOKABLE bool isUnnecessaryAdmin(); + static QString isPlatformUnsuported(); + static void relaunchAdmin(int argc, char *argv[]); private: }; diff --git a/src/main.cpp b/src/main.cpp index 610ae19e..d433fc2f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,6 +12,8 @@ #include "CSLOLVersion.h" int main(int argc, char *argv[]) { + CSLOLUtils::relaunchAdmin(argc, argv); + qmlRegisterType("customskinlol.tools", 1, 0, "CSLOLTools"); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) diff --git a/src/main_elevate.c b/src/main_elevate.c deleted file mode 100644 index f9dafe0c..00000000 --- a/src/main_elevate.c +++ /dev/null @@ -1,48 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include - -#define COMMAND_CHAR_COUNT_MAX 1000 + PATH_MAX - -int main() -{ - char pathBuff[PATH_MAX]; - uint32_t buffSize = PATH_MAX; - - // - // Find the absolute path - // of this executable. - // - if (_NSGetExecutablePath(pathBuff, &buffSize) != KERN_SUCCESS) - return -1; - - // - // Remove the file component of the abs. path. - // - char *parentDir = dirname(pathBuff); - - char str[COMMAND_CHAR_COUNT_MAX]; - - sprintf( - str, - "do shell script \"sudo %s/cslol-manager >/dev/null 2>&1 &\"" - " with prompt \"CSLOL-Manager needs administrator privileges to restart.\"" - " with administrator privileges" - " without altering line endings", - parentDir - ); - - int code = execlp ( - "osascript", - "osascript", - "-e", - str, - NULL); - - return code; -} \ No newline at end of file