Permalink
Browse files

Added threaded user validation

  • Loading branch information...
fador committed Aug 7, 2012
1 parent 0b040e1 commit 41e827b801ab1dda1352403ea82472b150736c9f
Showing with 222 additions and 21 deletions.
  1. +2 −0 README.md
  2. +1 −4 files/config.cfg
  3. +5 −0 include/mineserver.h
  4. +1 −0 include/sockets.h
  5. +2 −2 include/user.h
  6. +50 −7 src/mineserver.cpp
  7. +18 −6 src/packets.cpp
  8. +92 −0 src/sockets.cpp
  9. +49 −0 src/user.cpp
  10. +2 −2 win32/mineserver.vcxproj
View
@@ -38,6 +38,7 @@ C++ compiler. MS Visual C++ 10 and GCC 4.4 should be sufficient. The build syste
* Physics for water (currently revising this)
* Flatland and terrain map generation (Also biomegen!)
* Working chests, furnaces & signs
+ * User validation from minecraft.net
* Protocol Encryption (NEW)
### Configuration Notes
@@ -71,6 +72,7 @@ Mineserver requires the following libraries:
* [libevent 1.4.14b](http://monkey.org/~provos/libevent/)
* [libnoise 1.0](http://libnoise.sourceforge.net/)
* [openssl/libssl](http://www.openssl.org/)
+ * [pthread](http://en.wikipedia.org/wiki/POSIX_Threads)
* Installing on Debian and Ubuntu: (For Ubuntu libevent1 -> libevent-1.4-2)
View
@@ -19,15 +19,12 @@ system.interface.use_cli = true;
system.server_name = "Mineserver testserver";
# Validate usernames against minecraft.net? NOT WORKING
-system.user_validation = false;
+system.user_validation = true;
# Encryption required for validation
# will encrypt the whole protocol with AES/CFB8
system.protocol_encryption = true;
-# Allow connecting when auth is down
-system.allow_connect_on_auth_timeout = true;
-
# Disclose Software Version
system.show_version = true;
View
@@ -62,6 +62,8 @@
#include "plugin_api.h"
#undef MINESERVER
+#include <pthread.h>
+
struct event_base;
class Mineserver
@@ -77,6 +79,9 @@ class Mineserver
bool m_damage_enabled;
bool m_only_helmets;
struct event m_listenEvent;
+ pthread_mutex_t m_validation_mutex;
+ struct userValidation { User* user; bool valid; uint32_t UID; };
+ std::vector<userValidation> validatedUsers;
#ifdef PROTOCOL_ENCRYPTION
//Protocol encryption
View
@@ -32,3 +32,4 @@
extern "C" void accept_callback(int fd, short ev, void* arg);
extern "C" void client_callback(int fd, short ev, void* arg);
+extern "C" void *user_validation_thread(void *arg);
View
@@ -94,9 +94,9 @@ class User
OpenInventory openInv;
std::string secret;
EVP_CIPHER_CTX en, de;
-
+ std::string generateDigest();
void initCipher()
- {
+ {
unsigned char key[16], iv[16];
memcpy(&iv,secret.c_str(),16);
memcpy(&key,secret.c_str(),16);
View
@@ -25,10 +25,12 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef DEBUG & _MSC_VER
+#ifdef DEBUG
+ #ifdef _MSC_VER
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
- #include <crtdbg.h>
+ #include <crtdbg.h>
+ #endif
#endif
#ifdef WIN32
@@ -127,8 +129,10 @@ int printHelp(int code)
int main(int argc, char* argv[])
{
bool ret = false;
- #ifdef DEBUG & _MSC_VER
- _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
+ #ifdef DEBUG
+ #ifdef _MSC_VER
+ _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
+ #endif
#endif
// Try and start a new server instance
try
@@ -170,7 +174,8 @@ Mineserver::Mineserver(int args, char **argarray)
m_furnaceManager(NULL),
m_packetHandler (NULL),
m_inventory (NULL),
- m_mobs (NULL)
+ m_mobs (NULL),
+ m_validation_mutex(PTHREAD_MUTEX_INITIALIZER)
{
ServerInstance = this;
InitSignals();
@@ -283,7 +288,6 @@ Mineserver::Mineserver(int args, char **argarray)
LOG2(INFO, "Welcome to Mineserver v" + VERSION);
LOG2(INFO, "Using zlib "+std::string(ZLIB_VERSION)+" libevent "+std::string(event_get_version()));
- #ifdef PROTOCOL_ENCRYPTION
LOG2(INFO, "Generating RSA key pair for protocol encryption");
//Protocol encryption
@@ -327,7 +331,11 @@ Mineserver::Mineserver(int args, char **argarray)
}
LOG2(INFO, "ServerID: " + serverID);
- #endif
+
+ if(!m_config->bData("system.user_validation"))
+ {
+ serverID = "-";
+ }
MapGen* mapgen = new MapGen();
MapGen* nethergen = new NetherGen();
@@ -755,6 +763,41 @@ bool Mineserver::run()
// Check for Furnace activity
furnaceManager()->update();
+ // Check for user validation results
+ pthread_mutex_lock(&ServerInstance->m_validation_mutex);
+ for(int i = 0; i < ServerInstance->validatedUsers.size(); i++)
+ {
+ //To make sure user hasn't timed out or anything while validating
+ User *tempuser = NULL;
+ for (std::set<User*>::const_iterator it = users().begin(); it != users().end(); ++it)
+ {
+ if((*it)->UID == ServerInstance->validatedUsers[i].UID)
+ {
+ tempuser = (*it);
+ break;
+ }
+ }
+
+ if(tempuser != NULL)
+ {
+ if(ServerInstance->validatedUsers[i].valid)
+ {
+ LOG(INFO, "Packets", tempuser->nick + " is VALID ");
+ tempuser->crypted = true;
+ tempuser->buffer << (int8_t)PACKET_ENCRYPTION_RESPONSE << (int16_t)0 << (int16_t) 0;
+ tempuser->uncryptedLeft = 5;
+ }
+ else
+ {
+ tempuser->kick("User not Premium");
+ }
+ //Flush
+ client_callback(tempuser->fd, EV_WRITE, tempuser);
+ }
+ }
+ ServerInstance->validatedUsers.clear();
+ pthread_mutex_unlock(&ServerInstance->m_validation_mutex);
+
// Run 1s timer hook
static_cast<Hook0<bool>*>(plugin()->getHook("Timer1000"))->doAll();
}
View
@@ -61,6 +61,7 @@
#include "mob.h"
#include "utf8.h"
#include "protocol.h"
+#include "sockets.h"
#ifdef PROTOCOL_ENCRYPTION
#include <openssl/rsa.h>
@@ -213,13 +214,24 @@ int PacketHandler::encryption_response(User* user)
user->secret = std::string((char *)buffer, ret);
//We're going crypted!
user->initCipher();
- user->crypted = true;
- //Response
- user->buffer << (int8_t)PACKET_ENCRYPTION_RESPONSE << (int16_t)0 << (int16_t) 0;
- user->uncryptedLeft = 5; //5 first bytes are uncrypted
-
- //ToDo: validate user
+
+ if(!ServerInstance->config()->bData("system.user_validation"))
+ {
+ //Response
+ user->crypted = true;
+ user->buffer << (int8_t)PACKET_ENCRYPTION_RESPONSE << (int16_t)0 << (int16_t) 0;
+ user->uncryptedLeft = 5; //5 first bytes are uncrypted
+ }
+ else
+ {
+ pthread_t validation_thread;
+ Mineserver::userValidation* valid = new Mineserver::userValidation;
+ valid->user = user;
+ valid->UID = user->UID;
+ pthread_create(&validation_thread,NULL,user_validation_thread,(void*)valid);
+ }
+
return PACKET_OK;
}
View
@@ -49,6 +49,7 @@ typedef int socklen_t;
#include "nbt.h"
#include "mineserver.h"
#include "packets.h"
+#include "config.h"
extern int setnonblock(int fd);
@@ -260,3 +261,94 @@ extern "C" void accept_callback(int fd, short ev, void* arg)
event_set(client->GetEvent(), client_fd, EV_WRITE | EV_READ, client_callback, client);
event_add(client->GetEvent(), NULL);
}
+
+
+int socket_connect(char* host, int port)
+{
+ struct hostent* hp;
+ struct sockaddr_in addr;
+ int on = 1, sock;
+
+ if ((hp = gethostbyname(host)) == NULL)
+ {
+ return 0;
+ }
+
+ memmove(&addr.sin_addr, hp->h_addr, hp->h_length);
+ addr.sin_port = htons(port);
+ addr.sin_family = AF_INET;
+ sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+ struct timeval tv;
+ tv.tv_sec = 5;
+ setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(struct timeval));
+ setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (const char*)&tv, sizeof(struct timeval));
+
+ setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (const char*)&on, sizeof(int));
+
+ if (sock == -1)
+ {
+ return 0;
+ }
+
+ if (connect(sock, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) == -1)
+ {
+ return 0;
+ }
+
+ return sock;
+}
+
+void *user_validation_thread(void *arg)
+{
+ Mineserver::userValidation *user = reinterpret_cast<Mineserver::userValidation *>(arg);
+ user->valid=false;
+ std::string url = "/game/checkserver.jsp?user=" + user->user->nick + "&serverId=" + user->user->generateDigest();
+ LOG(INFO, "Packets", "Validating " + user->user->nick + " against minecraft.net: ");
+
+ std::string http_request = "GET " + url + " HTTP/1.1\r\n"
+ + "Host: session.minecraft.net\r\n"
+ + "Connection: close\r\n\r\n";
+
+ int fd = socket_connect((char*)"session.minecraft.net", 80);
+ if (fd)
+ {
+#ifdef WIN32
+ send(fd, http_request.c_str(), http_request.length(), NULL);
+#else
+ write(fd, http_request.c_str(), http_request.length());
+#endif
+
+#define BUFFER_SIZE 1024
+ char* buffer = new char[BUFFER_SIZE];
+ std::string stringbuffer;
+
+#ifdef WIN32
+ while (int received = recv(fd, buffer, BUFFER_SIZE - 1, NULL) != 0)
+ {
+#else
+ while (read(fd, buffer, BUFFER_SIZE - 1) != 0)
+ {
+#endif
+ stringbuffer += std::string(buffer);
+ }
+ delete[] buffer;
+#ifdef WIN32
+ closesocket(fd);
+#else
+ close(fd);
+#endif
+
+ if ((stringbuffer.size() >= 3 && stringbuffer.find("\r\n\r\nYES", 0) != std::string::npos))
+ {
+ user->valid = true;
+ }
+ }
+ pthread_mutex_lock(&ServerInstance->m_validation_mutex);
+ ServerInstance->validatedUsers.push_back(*user);
+ pthread_mutex_unlock(&ServerInstance->m_validation_mutex);
+ user->user = NULL;
+ delete user;
+ pthread_exit(NULL);
+ return NULL;
+}
View
@@ -1493,3 +1493,52 @@ void User::setCurrentItemSlot(int16_t item_slot)
{
m_currentItemSlot = item_slot;
}
+
+std::string User::generateDigest()
+{
+ SHA_CTX context;
+ unsigned char md[20];
+ std::string out;
+ int i;
+ const char hex[] = "0123456789abcdef";
+
+ SHA1_Init(&context);
+ SHA1_Update(&context, (unsigned char*)ServerInstance->serverID.data(), ServerInstance->serverID.size());
+ SHA1_Update(&context, (unsigned char*)secret.data(), secret.size());
+ SHA1_Update(&context, (unsigned char*)ServerInstance->publicKey.data(), ServerInstance->publicKey.size());
+ SHA1_Final(md, &context);
+
+ if(md[0] & 0x80)
+ {
+ unsigned char carry = 1;
+ out = '-';
+ for (i = 19; i >= 0; i--)
+ {
+ unsigned short twocomp = (unsigned char)~md[i];
+ twocomp+=carry;
+ if(twocomp & 0xff00)
+ {
+ twocomp = twocomp&0xff;
+ }
+ else
+ {
+ carry = 0;
+ }
+ md[i] = twocomp;
+ }
+ }
+
+ for (i = 0; i < 20; i++)
+ {
+ if(i || md[i]>>4)
+ {
+ out += hex[(md[i]>>4)];
+ }
+ if(i || md[i]>>4 || md[i]&0xf)
+ {
+ out += hex[(md[i]&0xf)];
+ }
+ }
+
+ return out;
+}
View
@@ -214,7 +214,7 @@
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>libeay32.lib;ssleay32.lib;Winmm.lib;libnoise.lib;zlibwapi.lib;ws2_32.lib;libevent.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>pthread.lib;libeay32.lib;ssleay32.lib;Winmm.lib;libnoise.lib;zlibwapi.lib;ws2_32.lib;libevent.lib;%(AdditionalDependencies)</AdditionalDependencies>
<IgnoreSpecificDefaultLibraries>LIBCMT</IgnoreSpecificDefaultLibraries>
</Link>
</ItemDefinitionGroup>
@@ -238,7 +238,7 @@
<GenerateDebugInformation>false</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
- <AdditionalDependencies>libeay32.lib;ssleay32.lib;Winmm.lib;libnoise.lib;zlibwapi.lib;libevent.lib;Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>pthread.lib;libeay32.lib;ssleay32.lib;Winmm.lib;libnoise.lib;zlibwapi.lib;libevent.lib;Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<IgnoreSpecificDefaultLibraries>LIBCMT</IgnoreSpecificDefaultLibraries>
<AdditionalLibraryDirectories>
</AdditionalLibraryDirectories>

0 comments on commit 41e827b

Please sign in to comment.