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);