From f59298adda16cedc5f58f6c26556e952d12dab5e Mon Sep 17 00:00:00 2001 From: Lemongrass3110 Date: Fri, 1 Dec 2017 19:09:51 +0100 Subject: [PATCH] Added support for windows admin detection (#2657) Credits to Microsoft --- src/common/atomic.h | 2 +- src/common/common-minicore.vcxproj | 3 +- src/common/common-minicore.vcxproj.filters | 5 +- src/common/common.vcxproj | 3 +- src/common/common.vcxproj.filters | 9 +- src/common/core.cpp | 12 +- src/common/mempool.c | 2 +- src/common/mutex.c | 2 +- src/common/random.c | 2 +- src/common/showmsg.c | 2 +- src/common/socket.c | 2 +- src/common/socket.h | 2 +- src/common/spinlock.h | 2 +- src/common/sql.c | 2 +- src/common/thread.c | 2 +- src/common/timer.c | 2 +- src/common/utils.c | 2 +- src/common/winapi.cpp | 168 +++++++++++++++++++++ src/common/{winapi.h => winapi.hpp} | 2 + 19 files changed, 204 insertions(+), 22 deletions(-) create mode 100644 src/common/winapi.cpp rename src/common/{winapi.h => winapi.hpp} (92%) diff --git a/src/common/atomic.h b/src/common/atomic.h index 716917f9ef..3412c6db9c 100644 --- a/src/common/atomic.h +++ b/src/common/atomic.h @@ -17,7 +17,7 @@ #include "cbasetypes.h" #if defined(_MSC_VER) -#include "winapi.h" +#include "winapi.hpp" // This checks if C/C++ Compiler Version is 18.00 or Windows is older than Vista #if _MSC_VER < 1800 || WINVER < _WIN32_WINNT_VISTA diff --git a/src/common/common-minicore.vcxproj b/src/common/common-minicore.vcxproj index 0c59414750..c7fc725b28 100644 --- a/src/common/common-minicore.vcxproj +++ b/src/common/common-minicore.vcxproj @@ -36,7 +36,7 @@ - + @@ -56,6 +56,7 @@ + {352B45B3-FE88-4431-9D89-48CF811446DB} diff --git a/src/common/common-minicore.vcxproj.filters b/src/common/common-minicore.vcxproj.filters index 1bfeea47cb..5cb744f813 100644 --- a/src/common/common-minicore.vcxproj.filters +++ b/src/common/common-minicore.vcxproj.filters @@ -62,7 +62,7 @@ Header Files - + Header Files @@ -112,5 +112,8 @@ Source Files + + Source Files + diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj index 872ab6bae8..ba2039054f 100644 --- a/src/common/common.vcxproj +++ b/src/common/common.vcxproj @@ -46,7 +46,7 @@ - + @@ -75,6 +75,7 @@ + diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters index 94e9209989..32934539ac 100644 --- a/src/common/common.vcxproj.filters +++ b/src/common/common.vcxproj.filters @@ -92,7 +92,7 @@ Header Files - + Header Files @@ -106,6 +106,9 @@ Source Files + + Source Files + Source Files @@ -166,9 +169,9 @@ Source Files - + Source Files - + Source Files diff --git a/src/common/core.cpp b/src/common/core.cpp index 1a5ceb054f..7c24f9858d 100644 --- a/src/common/core.cpp +++ b/src/common/core.cpp @@ -20,7 +20,7 @@ #ifndef _WIN32 #include #else -#include "winapi.h" // Console close event handling +#include "winapi.hpp" // Console close event handling #include // _chdir #endif @@ -304,10 +304,14 @@ static void display_title(void) { void usercheck(void) { #if !defined(BUILDBOT) -#ifndef _WIN32 - if (geteuid() == 0) { +#ifdef _WIN32 + if (IsCurrentUserLocalAdministrator()) { + ShowWarning("You are running rAthena with admin privileges, it is not necessary.\n"); + } +#else + if (geteuid() == 0) { ShowWarning ("You are running rAthena with root privileges, it is not necessary.\n"); - } + } #endif #endif } diff --git a/src/common/mempool.c b/src/common/mempool.c index b43a04db2c..099cf5ca9d 100644 --- a/src/common/mempool.c +++ b/src/common/mempool.c @@ -15,7 +15,7 @@ #include #ifdef WIN32 -#include "winapi.h" +#include "winapi.hpp" #else #include #endif diff --git a/src/common/mutex.c b/src/common/mutex.c index c62839fc34..6bf1fc86fc 100644 --- a/src/common/mutex.c +++ b/src/common/mutex.c @@ -2,7 +2,7 @@ // For more information, see LICENCE in the main folder #ifdef WIN32 -#include "winapi.h" +#include "winapi.hpp" #else #include diff --git a/src/common/random.c b/src/common/random.c index bce981dd86..ef051bb40b 100644 --- a/src/common/random.c +++ b/src/common/random.c @@ -5,7 +5,7 @@ #include "timer.h" // gettick #include "random.h" #if defined(WIN32) - #include "winapi.h" + #include "winapi.hpp" #elif defined(HAVE_GETPID) || defined(HAVE_GETTID) #include #include diff --git a/src/common/showmsg.c b/src/common/showmsg.c index 31ea115a7d..f710c9e52b 100644 --- a/src/common/showmsg.c +++ b/src/common/showmsg.c @@ -10,7 +10,7 @@ #include // atexit #ifdef WIN32 - #include "winapi.h" + #include "winapi.hpp" #ifdef DEBUGLOGMAP #define DEBUGLOGPATH "log\\map-server.log" diff --git a/src/common/socket.c b/src/common/socket.c index 510c5ffe35..21996abd5c 100644 --- a/src/common/socket.c +++ b/src/common/socket.c @@ -12,7 +12,7 @@ #include #ifdef WIN32 - #include "winapi.h" + #include "winapi.hpp" #else #include #include diff --git a/src/common/socket.h b/src/common/socket.h index 844db868d9..87c71a71f3 100644 --- a/src/common/socket.h +++ b/src/common/socket.h @@ -7,7 +7,7 @@ #include "cbasetypes.h" #ifdef WIN32 - #include "winapi.h" + #include "winapi.hpp" typedef long in_addr_t; #else #include diff --git a/src/common/spinlock.h b/src/common/spinlock.h index 7bd1665cc5..27f932aa55 100644 --- a/src/common/spinlock.h +++ b/src/common/spinlock.h @@ -16,7 +16,7 @@ // #ifdef WIN32 -#include "winapi.h" +#include "winapi.hpp" #endif #include "cbasetypes.h" diff --git a/src/common/sql.c b/src/common/sql.c index 38760139be..84fb1e4e54 100644 --- a/src/common/sql.c +++ b/src/common/sql.c @@ -9,7 +9,7 @@ #include "sql.h" #ifdef WIN32 -#include "winapi.h" +#include "winapi.hpp" #endif #include #include // strtoul diff --git a/src/common/thread.c b/src/common/thread.c index f79a4e29dd..6daadf7e8d 100644 --- a/src/common/thread.c +++ b/src/common/thread.c @@ -7,7 +7,7 @@ // For more information, see LICENCE in the main folder #ifdef WIN32 -#include "winapi.h" +#include "winapi.hpp" #define getpagesize() 4096 // @TODO: implement this properly (GetSystemInfo .. dwPageSize..). (Atm as on all supported win platforms its 4k its static.) #define __thread __declspec( thread ) #else diff --git a/src/common/timer.c b/src/common/timer.c index 0ef2a1c00b..a5f0ff1e8e 100644 --- a/src/common/timer.c +++ b/src/common/timer.c @@ -13,7 +13,7 @@ #include #ifdef WIN32 -#include "winapi.h" // GetTickCount() +#include "winapi.hpp" // GetTickCount() #else #endif diff --git a/src/common/utils.c b/src/common/utils.c index f4e7adf7aa..ebbf5e31e5 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -11,7 +11,7 @@ #include // floor() #ifdef WIN32 - #include "winapi.h" + #include "winapi.hpp" #ifndef F_OK #define F_OK 0x0 #endif /* F_OK */ diff --git a/src/common/winapi.cpp b/src/common/winapi.cpp new file mode 100644 index 0000000000..2c3013ee6a --- /dev/null +++ b/src/common/winapi.cpp @@ -0,0 +1,168 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "winapi.hpp" + +#include "cbasetypes.h" + +// Taken from https://support.microsoft.com/de-de/help/118626/how-to-determine-whether-a-thread-is-running-in-user-context-of-local +bool IsCurrentUserLocalAdministrator(void){ +#ifdef WIN32 + BOOL fReturn = FALSE; + DWORD dwStatus; + DWORD dwAccessMask; + DWORD dwAccessDesired; + DWORD dwACLSize; + DWORD dwStructureSize = sizeof(PRIVILEGE_SET); + PACL pACL = NULL; + PSID psidAdmin = NULL; + + HANDLE hToken = NULL; + HANDLE hImpersonationToken = NULL; + + PRIVILEGE_SET ps; + GENERIC_MAPPING GenericMapping; + + PSECURITY_DESCRIPTOR psdAdmin = NULL; + SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY; + + + /* + Determine if the current thread is running as a user that is a member + of the local admins group. + To do this, create a security descriptor that has a DACL which has an ACE + that allows only local aministrators access. + Then, call AccessCheck with the current thread's token and the security + descriptor. It will say whether the user could access an object if it + had that security descriptor. + + Note: you do not need to actually create the object. Just checking access + against the security descriptor alone will be sufficient. + */ + const DWORD ACCESS_READ = 1; + const DWORD ACCESS_WRITE = 2; + + + __try + { + + /* + AccessCheck() requires an impersonation token. We first get a + primary token and then create a duplicate impersonation token. The + impersonation token is not actually assigned to the thread, but is + used in the call to AccessCheck. Thus, this function itself never + impersonates, but does use the identity of the thread. If the + thread was impersonating already, this function uses that impersonation + context. + */ + if (!OpenThreadToken(GetCurrentThread(), TOKEN_DUPLICATE | TOKEN_QUERY, + + TRUE, &hToken)) + { + if (GetLastError() != ERROR_NO_TOKEN) + __leave; + + if (!OpenProcessToken(GetCurrentProcess(), + + TOKEN_DUPLICATE | TOKEN_QUERY, &hToken)) + __leave; + } + + if (!DuplicateToken(hToken, SecurityImpersonation, + + &hImpersonationToken)) + __leave; + + + /* + Create the binary representation of the well-known SID that + represents the local administrators group. Then create the + + security + descriptor and DACL with an ACE that allows only local admins + + access. + After that, perform the access check. This will determine whether + the current user is a local admin. + */ + if (!AllocateAndInitializeSid(&SystemSidAuthority, 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, + 0, 0, 0, 0, 0, 0, &psidAdmin)) + __leave; + + psdAdmin = LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); + if (psdAdmin == NULL) + __leave; + + if (!InitializeSecurityDescriptor(psdAdmin, + + SECURITY_DESCRIPTOR_REVISION)) + __leave; + + // Compute size needed for the ACL. + dwACLSize = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + + GetLengthSid(psidAdmin) - sizeof(DWORD); + + pACL = (PACL)LocalAlloc(LPTR, dwACLSize); + if (pACL == NULL) + __leave; + + if (!InitializeAcl(pACL, dwACLSize, ACL_REVISION2)) + __leave; + + dwAccessMask = ACCESS_READ | ACCESS_WRITE; + + if (!AddAccessAllowedAce(pACL, ACL_REVISION2, dwAccessMask, + + psidAdmin)) + __leave; + + if (!SetSecurityDescriptorDacl(psdAdmin, TRUE, pACL, FALSE)) + __leave; + + /* + AccessCheck validates a security descriptor somewhat; + set the group and owner so that enough of the security descriptor is + filled out to make AccessCheck happy. + */ + SetSecurityDescriptorGroup(psdAdmin, psidAdmin, FALSE); + SetSecurityDescriptorOwner(psdAdmin, psidAdmin, FALSE); + + if (!IsValidSecurityDescriptor(psdAdmin)) + __leave; + + dwAccessDesired = ACCESS_READ; + + /* + Initialize GenericMapping structure even though you + do not use generic rights. + */ + GenericMapping.GenericRead = ACCESS_READ; + GenericMapping.GenericWrite = ACCESS_WRITE; + GenericMapping.GenericExecute = 0; + GenericMapping.GenericAll = ACCESS_READ | ACCESS_WRITE; + + if (!AccessCheck(psdAdmin, hImpersonationToken, dwAccessDesired, + &GenericMapping, &ps, &dwStructureSize, &dwStatus, + &fReturn)) + { + fReturn = FALSE; + __leave; + } + } + __finally + { + // Clean up. + if (pACL) LocalFree(pACL); + if (psdAdmin) LocalFree(psdAdmin); + if (psidAdmin) FreeSid(psidAdmin); + if (hImpersonationToken) CloseHandle(hImpersonationToken); + if (hToken) CloseHandle(hToken); + } + + return fReturn; +#else + return false; +#endif +} diff --git a/src/common/winapi.h b/src/common/winapi.hpp similarity index 92% rename from src/common/winapi.h rename to src/common/winapi.hpp index 88015929cc..ffb8b0c13b 100644 --- a/src/common/winapi.h +++ b/src/common/winapi.hpp @@ -46,4 +46,6 @@ #include #include +#include "cbasetypes.h" +bool IsCurrentUserLocalAdministrator(void);