Browse Source

Added support for windows admin detection (#2657)

Credits to Microsoft
Lemongrass3110 7 years ago
parent
commit
f59298adda

+ 1 - 1
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

+ 2 - 1
src/common/common-minicore.vcxproj

@@ -36,7 +36,7 @@
     <ClInclude Include="showmsg.h" />
     <ClInclude Include="strlib.h" />
     <ClInclude Include="utils.h" />
-    <ClInclude Include="winapi.h" />
+    <ClInclude Include="winapi.hpp" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="cli.c" />
@@ -56,6 +56,7 @@
     <ClCompile Include="showmsg.c" />
     <ClCompile Include="strlib.c" />
     <ClCompile Include="utils.c" />
+    <ClCompile Include="winapi.cpp" />
   </ItemGroup>
   <PropertyGroup Label="Globals">
     <ProjectGuid>{352B45B3-FE88-4431-9D89-48CF811446DB}</ProjectGuid>

+ 4 - 1
src/common/common-minicore.vcxproj.filters

@@ -62,7 +62,7 @@
     <ClInclude Include="utils.h">
       <Filter>Header Files</Filter>
     </ClInclude>
-    <ClInclude Include="winapi.h">
+    <ClInclude Include="winapi.hpp">
       <Filter>Header Files</Filter>
     </ClInclude>
   </ItemGroup>
@@ -112,5 +112,8 @@
     <ClCompile Include="utils.c">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClInclude Include="winapi.cpp">
+      <Filter>Source Files</Filter>
+    </ClInclude>
   </ItemGroup>
 </Project>

+ 2 - 1
src/common/common.vcxproj

@@ -46,7 +46,7 @@
     <ClInclude Include="thread.h" />
     <ClInclude Include="timer.h" />
     <ClInclude Include="utils.h" />
-    <ClInclude Include="winapi.h" />
+    <ClInclude Include="winapi.hpp" />
     <ClInclude Include="yamlwrapper.h" />
   </ItemGroup>
   <ItemGroup>
@@ -75,6 +75,7 @@
     <ClCompile Include="thread.c" />
     <ClCompile Include="timer.c" />
     <ClCompile Include="utils.c" />
+    <ClCompile Include="winapi.cpp" />
     <ClCompile Include="yamlwrapper.cpp" />
   </ItemGroup>
   <PropertyGroup Label="Globals">

+ 6 - 3
src/common/common.vcxproj.filters

@@ -92,7 +92,7 @@
     <ClInclude Include="utils.h">
       <Filter>Header Files</Filter>
     </ClInclude>
-    <ClInclude Include="winapi.h">
+    <ClInclude Include="winapi.hpp">
       <Filter>Header Files</Filter>
     </ClInclude>
     <ClInclude Include="yamlwrapper.h">
@@ -106,6 +106,9 @@
     <ClCompile Include="conf.c">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="core.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
     <ClCompile Include="db.c">
       <Filter>Source Files</Filter>
     </ClCompile>
@@ -166,9 +169,9 @@
     <ClCompile Include="utils.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="core.cpp">
+    <ClInclude Include="winapi.cpp">
       <Filter>Source Files</Filter>
-    </ClCompile>
+    </ClInclude>
     <ClCompile Include="yamlwrapper.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>

+ 8 - 4
src/common/core.cpp

@@ -20,7 +20,7 @@
 #ifndef _WIN32
 #include <unistd.h>
 #else
-#include "winapi.h" // Console close event handling
+#include "winapi.hpp" // Console close event handling
 #include <direct.h> // _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
 }

+ 1 - 1
src/common/mempool.c

@@ -15,7 +15,7 @@
 #include <string.h>
 
 #ifdef WIN32
-#include "winapi.h"
+#include "winapi.hpp"
 #else
 #include <unistd.h>
 #endif

+ 1 - 1
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 <pthread.h>
 

+ 1 - 1
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 <sys/types.h>
 	#include <unistd.h>

+ 1 - 1
src/common/showmsg.c

@@ -10,7 +10,7 @@
 #include <stdlib.h> // atexit
 
 #ifdef WIN32
-	#include "winapi.h"
+	#include "winapi.hpp"
 
 	#ifdef DEBUGLOGMAP
 		#define DEBUGLOGPATH "log\\map-server.log"

+ 1 - 1
src/common/socket.c

@@ -12,7 +12,7 @@
 #include <stdlib.h>
 
 #ifdef WIN32
-	#include "winapi.h"
+	#include "winapi.hpp"
 #else
 	#include <errno.h>
 #include <netinet/tcp.h>

+ 1 - 1
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 <sys/types.h>

+ 1 - 1
src/common/spinlock.h

@@ -16,7 +16,7 @@
 //
  
 #ifdef WIN32
-#include "winapi.h"
+#include "winapi.hpp"
 #endif
 
 #include "cbasetypes.h"

+ 1 - 1
src/common/sql.c

@@ -9,7 +9,7 @@
 #include "sql.h"
 
 #ifdef WIN32
-#include "winapi.h"
+#include "winapi.hpp"
 #endif
 #include <mysql.h>
 #include <stdlib.h>// strtoul

+ 1 - 1
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

+ 1 - 1
src/common/timer.c

@@ -13,7 +13,7 @@
 #include <string.h>
 
 #ifdef WIN32
-#include "winapi.h" // GetTickCount()
+#include "winapi.hpp" // GetTickCount()
 #else
 #endif
 

+ 1 - 1
src/common/utils.c

@@ -11,7 +11,7 @@
 #include <math.h> // floor()
 
 #ifdef WIN32
-	#include "winapi.h"
+	#include "winapi.hpp"
 	#ifndef F_OK
 		#define F_OK   0x0
 	#endif  /* F_OK */

+ 168 - 0
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
+}

+ 2 - 0
src/common/winapi.h → src/common/winapi.hpp

@@ -46,4 +46,6 @@
 #include <Mswsock.h>
 #include <MMSystem.h>
 
+#include "cbasetypes.h"
 
+bool IsCurrentUserLocalAdministrator(void);