Passwords - password entry at main menu, stored and checked by server
authorCiaran Gultnieks <ciaran@ciarang.com>
Fri, 20 May 2011 19:28:03 +0000 (20:28 +0100)
committerCiaran Gultnieks <ciaran@ciarang.com>
Fri, 20 May 2011 19:28:03 +0000 (20:28 +0100)
17 files changed:
src/CMakeLists.txt
src/base64.cpp [new file with mode: 0644]
src/base64.h [new file with mode: 0644]
src/client.cpp
src/client.h
src/clientserver.h
src/game.cpp
src/game.h
src/guiMainMenu.cpp
src/guiMainMenu.h
src/main.cpp
src/player.cpp
src/player.h
src/server.cpp
src/server.h
src/sha1.cpp [new file with mode: 0644]
src/sha1.h [new file with mode: 0644]

index 42260b3ae439d3fc402e4471eef2be3eadf7898e..26f4872da47f7bb13a2ea1b6f660168f5785aefb 100644 (file)
@@ -95,6 +95,8 @@ set(minetest_SRCS
        tile.cpp
        game.cpp
        main.cpp
+       sha1.cpp
+       base64.cpp
 )
 
 # Server sources
diff --git a/src/base64.cpp b/src/base64.cpp
new file mode 100644 (file)
index 0000000..2a863d1
--- /dev/null
@@ -0,0 +1,123 @@
+/* 
+   base64.cpp and base64.h
+
+   Copyright (C) 2004-2008 RenĂ© Nyffenegger
+
+   This source code is provided 'as-is', without any express or implied
+   warranty. In no event will the author be held liable for any damages
+   arising from the use of this software.
+
+   Permission is granted to anyone to use this software for any purpose,
+   including commercial applications, and to alter it and redistribute it
+   freely, subject to the following restrictions:
+
+   1. The origin of this source code must not be misrepresented; you must not
+      claim that you wrote the original source code. If you use this source code
+      in a product, an acknowledgment in the product documentation would be
+      appreciated but is not required.
+
+   2. Altered source versions must be plainly marked as such, and must not be
+      misrepresented as being the original source code.
+
+   3. This notice may not be removed or altered from any source distribution.
+
+   RenĂ© Nyffenegger rene.nyffenegger@adp-gmbh.ch
+
+*/
+
+#include "base64.h"
+#include <iostream>
+
+static const std::string base64_chars = 
+             "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+             "abcdefghijklmnopqrstuvwxyz"
+             "0123456789+/";
+
+
+static inline bool is_base64(unsigned char c) {
+  return (isalnum(c) || (c == '+') || (c == '/'));
+}
+
+std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
+  std::string ret;
+  int i = 0;
+  int j = 0;
+  unsigned char char_array_3[3];
+  unsigned char char_array_4[4];
+
+  while (in_len--) {
+    char_array_3[i++] = *(bytes_to_encode++);
+    if (i == 3) {
+      char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
+      char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
+      char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
+      char_array_4[3] = char_array_3[2] & 0x3f;
+
+      for(i = 0; (i <4) ; i++)
+        ret += base64_chars[char_array_4[i]];
+      i = 0;
+    }
+  }
+
+  if (i)
+  {
+    for(j = i; j < 3; j++)
+      char_array_3[j] = '\0';
+
+    char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
+    char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
+    char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
+    char_array_4[3] = char_array_3[2] & 0x3f;
+
+    for (j = 0; (j < i + 1); j++)
+      ret += base64_chars[char_array_4[j]];
+
+    while((i++ < 3))
+      ret += '=';
+
+  }
+
+  return ret;
+
+}
+
+std::string base64_decode(std::string const& encoded_string) {
+  int in_len = encoded_string.size();
+  int i = 0;
+  int j = 0;
+  int in_ = 0;
+  unsigned char char_array_4[4], char_array_3[3];
+  std::string ret;
+
+  while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
+    char_array_4[i++] = encoded_string[in_]; in_++;
+    if (i ==4) {
+      for (i = 0; i <4; i++)
+        char_array_4[i] = base64_chars.find(char_array_4[i]);
+
+      char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
+      char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
+      char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
+
+      for (i = 0; (i < 3); i++)
+        ret += char_array_3[i];
+      i = 0;
+    }
+  }
+
+  if (i) {
+    for (j = i; j <4; j++)
+      char_array_4[j] = 0;
+
+    for (j = 0; j <4; j++)
+      char_array_4[j] = base64_chars.find(char_array_4[j]);
+
+    char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
+    char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
+    char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
+
+    for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
+  }
+
+  return ret;
+}
diff --git a/src/base64.h b/src/base64.h
new file mode 100644 (file)
index 0000000..65d5db8
--- /dev/null
@@ -0,0 +1,4 @@
+#include <string>
+
+std::string base64_encode(unsigned char const* , unsigned int len);
+std::string base64_decode(std::string const& s);
index ce862a0025552746a5b613ef057e366ff2bfaa0b..e2cda97c140e3f5d970b8f8d9e68034c6f9b1ec3 100644 (file)
@@ -68,6 +68,7 @@ void * MeshUpdateThread::Thread()
 Client::Client(
                IrrlichtDevice *device,
                const char *playername,
+               std::string password,
                MapDrawControl &control):
        m_mesh_update_thread(),
        m_env(
@@ -83,7 +84,9 @@ Client::Client(
        m_server_ser_ver(SER_FMT_VER_INVALID),
        m_inventory_updated(false),
        m_time_of_day(0),
-       m_map_seed(0)
+       m_map_seed(0),
+       m_password(password),
+       m_access_denied(false)
 {
        m_packetcounter_timer = 0.0;
        m_delete_unused_sectors_timer = 0.0;
@@ -299,11 +302,14 @@ void Client::step(float dtime)
                        // [0] u16 TOSERVER_INIT
                        // [2] u8 SER_FMT_VER_HIGHEST
                        // [3] u8[20] player_name
-                       SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE);
+                       // [23] u8[28] password
+                       SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE+PASSWORD_SIZE);
                        writeU16(&data[0], TOSERVER_INIT);
                        writeU8(&data[2], SER_FMT_VER_HIGHEST);
                        memset((char*)&data[3], 0, PLAYERNAME_SIZE);
                        snprintf((char*)&data[3], PLAYERNAME_SIZE, "%s", myplayer->getName());
+                       snprintf((char*)&data[23], PASSWORD_SIZE, "%s", m_password.c_str());
+
                        // Send as unreliable
                        Send(0, data, false);
                }
@@ -597,7 +603,16 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
 
                return;
        }
-       
+
+       if(command == TOCLIENT_ACCESS_DENIED)
+       {
+               // The server didn't like our password. Note, this needs
+               // to be processed even if the serialisation format has
+               // not been agreed yet, the same as TOCLIENT_INIT.
+               m_access_denied = true;
+               return;
+       }
+
        if(ser_version == SER_FMT_VER_INVALID)
        {
                dout_client<<DTIME<<"WARNING: Client: Server serialization"
index ee73cc42ce83a1e6d3e61076ae84e1e5cd881700..222f83ab739615c24e7e0d0ca05651db4cbd04a9 100644 (file)
@@ -207,6 +207,7 @@ public:
        Client(
                        IrrlichtDevice *device,
                        const char *playername,
+                       std::string password,
                        MapDrawControl &control
                        );
        
@@ -377,6 +378,11 @@ public:
        // Get event from queue. CE_NONE is returned if queue is empty.
        ClientEvent getClientEvent();
        
+       inline bool accessDenied()
+       {
+               return m_access_denied;
+       }
+
 private:
        
        // Virtual methods from con::PeerHandler
@@ -430,6 +436,9 @@ private:
        // The seed returned by the server in TOCLIENT_INIT is stored here
        u64 m_map_seed;
        
+       std::string m_password;
+       bool m_access_denied;
+
        InventoryContext m_inventory_context;
 
        Queue<ClientEvent> m_client_event_queue;
index 46ffa5eab365d25281356840a2fdb04f2cef9e5a..a64a11f08a858d0f387036bce21fec32c07458cd 100644 (file)
@@ -150,6 +150,11 @@ enum ToClientCommand
                f1000 player pitch
                f1000 player yaw
        */
+
+       TOCLIENT_ACCESS_DENIED = 0x35,
+       /*
+               u16 command
+       */
 };
 
 enum ToServerCommand
@@ -161,6 +166,7 @@ enum ToServerCommand
                [0] u16 TOSERVER_INIT
                [2] u8 SER_FMT_VER_HIGHEST
                [3] u8[20] player_name
+               [23] u8[28] password
        */
 
        TOSERVER_INIT2 = 0x11,
index d6b1117c145ec4877cdbee83c9d85f3f6dafb7de..69e673fa46669b1c3b1209e9ec1cc5352f0bf9f7 100644 (file)
@@ -634,6 +634,7 @@ void the_game(
        gui::IGUIFont* font,
        std::string map_dir,
        std::string playername,
+       std::string password,
        std::string address,
        u16 port,
        std::wstring &error_message
@@ -689,7 +690,7 @@ void the_game(
        */
 
        std::cout<<DTIME<<"Creating client"<<std::endl;
-       Client client(device, playername.c_str(), draw_control);
+       Client client(device, playername.c_str(), password, draw_control);
                        
        Address connect_address(0,0,0,0, port);
        try{
@@ -728,6 +729,10 @@ void the_game(
                                could_connect = true;
                                break;
                        }
+                       if(client.accessDenied())
+                       {
+                               break;
+                       }
                        // Wait for 10 seconds
                        if(time_counter >= 10.0)
                        {
@@ -756,8 +761,16 @@ void the_game(
 
        if(could_connect == false)
        {
-               std::cout<<DTIME<<"Timed out."<<std::endl;
-               error_message = L"Connection timed out.";
+               if(client.accessDenied())
+               {
+                       error_message = L"Access denied. Check your password and try again.";
+                       std::cout<<DTIME<<"Access denied."<<std::endl;
+               }
+               else
+               {
+                       error_message = L"Connection timed out.";
+                       std::cout<<DTIME<<"Timed out."<<std::endl;
+               }
                gui_loadingtext->remove();
                return;
        }
index 7cba1299e3e8137561c14c4e9f724e78df343810..eb289b8f27f2df2dc141ce74bbf28d3469c1b029 100644 (file)
@@ -67,6 +67,7 @@ void the_game(
        gui::IGUIFont* font,
        std::string map_dir,
        std::string playername,
+       std::string password,
        std::string address,
        u16 port,
        std::wstring &error_message
index ac02f79e37facaeedb0a2db4465b4387b01e2616..a30e006a63b468065685cd80286178be972fb9fb 100644 (file)
@@ -164,30 +164,38 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
                //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
        }
 
-       // Nickname
+       // Nickname + password
        {
-               core::rect<s32> rect(0, 0, 100, 20);
-               rect += topleft_client + v2s32(40, 50+6);
-               const wchar_t *text = L"Nickname";
+               core::rect<s32> rect(0, 0, 110, 20);
+               rect += topleft_client + v2s32(35, 50+6);
+               const wchar_t *text = L"Name/Password";
                Environment->addStaticText(text, rect, false, true, this, -1);
        }
        {
-               core::rect<s32> rect(0, 0, 250, 30);
+               core::rect<s32> rect(0, 0, 230, 30);
                rect += topleft_client + v2s32(160, 50);
                gui::IGUIElement *e = 
                Environment->addEditBox(text_name.c_str(), rect, true, this, 258);
                if(text_name == L"")
                        Environment->setFocus(e);
        }
+       {
+               core::rect<s32> rect(0, 0, 120, 30);
+               rect += topleft_client + v2s32(size_client.X-60-100, 50);
+               gui::IGUIEditBox *e =
+               Environment->addEditBox(L"", rect, true, this, 264);
+               e->setPasswordBox(true);
+
+       }
        // Address + port
        {
-               core::rect<s32> rect(0, 0, 100, 20);
-               rect += topleft_client + v2s32(40, 100+6);
-               const wchar_t *text = L"Address + Port";
+               core::rect<s32> rect(0, 0, 110, 20);
+               rect += topleft_client + v2s32(35, 100+6);
+               const wchar_t *text = L"Address/Port";
                Environment->addStaticText(text, rect, false, true, this, -1);
        }
        {
-               core::rect<s32> rect(0, 0, 250, 30);
+               core::rect<s32> rect(0, 0, 230, 30);
                rect += topleft_client + v2s32(160, 100);
                gui::IGUIElement *e = 
                Environment->addEditBox(text_address.c_str(), rect, true, this, 256);
@@ -195,9 +203,9 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
                        Environment->setFocus(e);
        }
        {
-               core::rect<s32> rect(0, 0, 100, 30);
+               core::rect<s32> rect(0, 0, 120, 30);
                //rect += topleft_client + v2s32(160+250+20, 125);
-               rect += topleft_client + v2s32(size_client.X-40-100, 100);
+               rect += topleft_client + v2s32(size_client.X-60-100, 100);
                Environment->addEditBox(text_port.c_str(), rect, true, this, 257);
        }
        {
@@ -208,13 +216,13 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
        }
        {
                core::rect<s32> rect(0, 0, 250, 30);
-               rect += topleft_client + v2s32(40, 150);
+               rect += topleft_client + v2s32(35, 150);
                Environment->addCheckBox(fancy_trees, rect, this, 263,
                                L"Fancy trees");
        }
        {
                core::rect<s32> rect(0, 0, 250, 30);
-               rect += topleft_client + v2s32(40, 150+30);
+               rect += topleft_client + v2s32(35, 150+30);
                Environment->addCheckBox(smooth_lighting, rect, this, 262,
                                L"Smooth Lighting");
        }
@@ -245,12 +253,12 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
        // Server parameters
        {
                core::rect<s32> rect(0, 0, 250, 30);
-               rect += topleft_server + v2s32(40, 30);
+               rect += topleft_server + v2s32(35, 30);
                Environment->addCheckBox(creative_mode, rect, this, 259, L"Creative Mode");
        }
        {
                core::rect<s32> rect(0, 0, 250, 30);
-               rect += topleft_server + v2s32(40, 60);
+               rect += topleft_server + v2s32(35, 60);
                Environment->addCheckBox(enable_damage, rect, this, 261, L"Enable Damage");
        }
        // Map delete button
@@ -296,6 +304,11 @@ void GUIMainMenu::acceptInput()
                if(e != NULL)
                        m_data->name = e->getText();
        }
+       {
+               gui::IGUIElement *e = getElementFromId(264);
+               if(e != NULL)
+                       m_data->password = e->getText();
+       }
        {
                gui::IGUIElement *e = getElementFromId(256);
                if(e != NULL)
@@ -380,7 +393,7 @@ bool GUIMainMenu::OnEvent(const SEvent& event)
                {
                        switch(event.GUIEvent.Caller->getID())
                        {
-                       case 256: case 257: case 258:
+                               case 256: case 257: case 258: case 264:
                                acceptInput();
                                quitMenu();
                                return true;
index 4999d68ba668923ceec5326b906af2c9be230885..edd519024fb6a56879538d6cf144183f92f4c18b 100644 (file)
@@ -46,6 +46,7 @@ struct MainMenuData
        std::wstring address;
        std::wstring port;
        std::wstring name;
+       std::wstring password;
        bool fancy_trees;
        bool smooth_lighting;
        // Server options
index 5d607b2d8eef0c8c2c197848195532f622dc6c2b..0b181a36dcee75561aa60a71f3ed4b7db7519dfa 100644 (file)
@@ -325,6 +325,8 @@ Making it more portable:
 #include "materials.h"\r
 #include "game.h"\r
 #include "keycode.h"\r
+#include "sha1.h"\r
+#include "base64.h"\r
 \r
 // This makes textures\r
 ITextureSource *g_texturesource = NULL;\r
@@ -1170,6 +1172,7 @@ int main(int argc, char *argv[])
                return 0;\r
        }\r
 \r
+\r
        /*\r
                More parameters\r
        */\r
@@ -1324,11 +1327,15 @@ int main(int argc, char *argv[])
        */\r
        std::wstring error_message = L"";\r
 \r
+       // The password entered during the menu screen,\r
+       std::string password;\r
+\r
        /*\r
                Menu-game loop\r
        */\r
        while(device->run() && kill == false)\r
        {\r
+\r
                // This is used for catching disconnects\r
                try\r
                {\r
@@ -1428,6 +1435,25 @@ int main(int argc, char *argv[])
                                }\r
 \r
                                playername = wide_to_narrow(menudata.name);\r
+\r
+                               // Get an sha-1 hash of the player's name combined with\r
+                               // the password entered. That's what the server uses as\r
+                               // their password. (Exception : if the password field is\r
+                               // blank, we send a blank password - this is for backwards\r
+                               // compatibility with password-less players).\r
+                               if(menudata.password.length() > 0)\r
+                               {\r
+                                               std::string slt=playername + wide_to_narrow(menudata.password);\r
+                                               SHA1 *sha1 = new SHA1();\r
+                                               sha1->addBytes(slt.c_str(), slt.length());\r
+                                               unsigned char *digest = sha1->getDigest();\r
+                                               password = base64_encode(digest, 20);\r
+                               }\r
+                               else\r
+                               {\r
+                                               password = "";\r
+                               }\r
+\r
                                address = wide_to_narrow(menudata.address);\r
                                int newport = stoi(wide_to_narrow(menudata.port));\r
                                if(newport != 0)\r
@@ -1474,6 +1500,7 @@ int main(int argc, char *argv[])
                                font,\r
                                map_dir,\r
                                playername,\r
+                               password,\r
                                address,\r
                                port,\r
                                error_message\r
index 3f92e899c27ac2ed832104f6ecabaee847167f47..539244709ee5a48b3be1329a5f008145565893c6 100644 (file)
@@ -87,6 +87,7 @@ Player::Player():
        m_position(0,0,0)
 {
        updateName("<not set>");
+       updatePassword("");
        resetInventory();
 }
 
@@ -145,6 +146,7 @@ void Player::serialize(std::ostream &os)
        Settings args;
        args.setS32("version", 1);
        args.set("name", m_name);
+       args.set("password", m_password);
        args.setFloat("pitch", m_pitch);
        args.setFloat("yaw", m_yaw);
        args.setV3F("position", m_position);
@@ -179,6 +181,10 @@ void Player::deSerialize(std::istream &is)
        //args.getS32("version");
        std::string name = args.get("name");
        updateName(name.c_str());
+       std::string password = "";
+       if(args.exists("password"))
+               password = args.get("password");
+       updatePassword(password.c_str());
        m_pitch = args.getFloat("pitch");
        m_yaw = args.getFloat("yaw");
        m_position = args.getV3F("position");
index be93766fd7a949ed2fa30498fc9fd5e9af4abb30..925252e49d6a48f361ff01c44179587f5d78270e 100644 (file)
@@ -25,6 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "collision.h"
 
 #define PLAYERNAME_SIZE 20
+#define PASSWORD_SIZE 28       // Maximum password length. Allows for
+                               // base64-encoded SHA-1.
 
 #define PLAYERNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.,"
 
@@ -121,6 +123,16 @@ public:
                return m_name;
        }
 
+       virtual void updatePassword(const char *password)
+       {
+               snprintf(m_password, PASSWORD_SIZE, "%s", password);
+       }
+
+       const char * getPassword()
+       {
+               return m_password;
+       }
+
        virtual bool isLocal() const = 0;
 
        virtual void updateLight(u8 light_at_pos) {};
@@ -157,6 +169,7 @@ public:
 
 protected:
        char m_name[PLAYERNAME_SIZE];
+       char m_password[PASSWORD_SIZE];
        f32 m_pitch;
        f32 m_yaw;
        v3f m_speed;
index d211186eb0cdcbdc2a55a9627b6e2156d8f7a9b4..051ca85fbdff0ab0d85bff72fe873213c0b4d179 100644 (file)
@@ -1734,8 +1734,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                // [0] u16 TOSERVER_INIT
                // [2] u8 SER_FMT_VER_HIGHEST
                // [3] u8[20] player_name
+               // [23] u8[28] password <--- can be sent without this, from old versions
 
-               if(datasize < 3)
+               if(datasize < 2+1+PLAYERNAME_SIZE)
                        return;
 
                derr_server<<DTIME<<"Server: Got TOSERVER_INIT from "
@@ -1767,17 +1768,41 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                */
                
                // Get player name
-               const u32 playername_size = 20;
-               char playername[playername_size];
-               for(u32 i=0; i<playername_size-1; i++)
+               char playername[PLAYERNAME_SIZE];
+               for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
                {
                        playername[i] = data[3+i];
                }
-               playername[playername_size-1] = 0;
-               
+               playername[PLAYERNAME_SIZE-1] = 0;
+       
+               // Get password
+               char password[PASSWORD_SIZE];
+               if(datasize == 2+1+PLAYERNAME_SIZE)
+               {
+                       // old version - assume blank password
+                       *password = 0;
+               }
+               else
+               {
+                               for(u32 i=0; i<PASSWORD_SIZE-1; i++)
+                               {
+                                       password[i] = data[23+i];
+                               }
+                               password[PASSWORD_SIZE-1] = 0;
+               }
+               Player *checkplayer = m_env.getPlayer(playername);
+               if(checkplayer != NULL && strcmp(checkplayer->getPassword(),password))
+               {
+                       derr_server<<DTIME<<"Server: peer_id="<<peer_id
+                                       <<": supplied invalid password for "
+                                       <<playername<<std::endl;
+                       SendAccessDenied(m_con, peer_id);
+                       return;
+               }
+
                // Get player
-               Player *player = emergePlayer(playername, "", peer_id);
-               //Player *player = m_env.getPlayer(peer_id);
+               Player *player = emergePlayer(playername, password, peer_id);
+
 
                /*{
                        // DEBUG: Test serialization
@@ -3138,6 +3163,20 @@ void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
        con.Send(peer_id, 0, data, true);
 }
 
+void Server::SendAccessDenied(con::Connection &con, u16 peer_id)
+{
+       DSTACK(__FUNCTION_NAME);
+       std::ostringstream os(std::ios_base::binary);
+
+       writeU16(os, TOCLIENT_ACCESS_DENIED);
+
+       // Make data buffer
+       std::string s = os.str();
+       SharedBuffer<u8> data((u8*)s.c_str(), s.size());
+       // Send as reliable
+       con.Send(peer_id, 0, data, true);
+}
+
 /*
        Non-static send methods
 */
@@ -4052,8 +4091,7 @@ v3f findSpawnPos(ServerMap &map)
                        ), BS);
 }
 
-Player *Server::emergePlayer(const char *name, const char *password,
-               u16 peer_id)
+Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
 {
        /*
                Try to get an existing player
@@ -4099,6 +4137,7 @@ Player *Server::emergePlayer(const char *name, const char *password,
                //player->peer_id = PEER_ID_INEXISTENT;
                player->peer_id = peer_id;
                player->updateName(name);
+               player->updatePassword(password);
 
                /*
                        Set player position
index d8b47aef9f96396471731bfb73a9107ab2295f5a..289f096189020fb8c2ac5c5c0b58b54bfc627578 100644 (file)
@@ -436,6 +436,7 @@ private:
        */
        
        static void SendHP(con::Connection &con, u16 peer_id, u8 hp);
+       static void SendAccessDenied(con::Connection &con, u16 peer_id);
        
        /*
                Non-static send methods
@@ -476,11 +477,12 @@ private:
        /*
                Get a player from memory or creates one.
                If player is already connected, return NULL
+               The password is not checked here - it is only used to
+               set the password if a new player is created.
 
                Call with env and con locked.
        */
-       Player *emergePlayer(const char *name, const char *password,
-                       u16 peer_id);
+       Player *emergePlayer(const char *name, const char *password, u16 peer_id);
 
        /*
                Update water pressure.
diff --git a/src/sha1.cpp b/src/sha1.cpp
new file mode 100644 (file)
index 0000000..93df109
--- /dev/null
@@ -0,0 +1,191 @@
+/* sha1.cpp
+
+Copyright (c) 2005 Michael D. Leonhard
+
+http://tamale.net/
+
+This file is licensed under the terms described in the
+accompanying LICENSE file.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "sha1.h"
+
+// print out memory in hexadecimal
+void SHA1::hexPrinter( unsigned char* c, int l )
+{
+       assert( c );
+       assert( l > 0 );
+       while( l > 0 )
+       {
+               printf( " %02x", *c );
+               l--;
+               c++;
+       }
+}
+
+// circular left bit rotation.  MSB wraps around to LSB
+Uint32 SHA1::lrot( Uint32 x, int bits )
+{
+       return (x<<bits) | (x>>(32 - bits));
+};
+
+// Save a 32-bit unsigned integer to memory, in big-endian order
+void SHA1::storeBigEndianUint32( unsigned char* byte, Uint32 num )
+{
+       assert( byte );
+       byte[0] = (unsigned char)(num>>24);
+       byte[1] = (unsigned char)(num>>16);
+       byte[2] = (unsigned char)(num>>8);
+       byte[3] = (unsigned char)num;
+}
+
+
+// Constructor *******************************************************
+SHA1::SHA1()
+{
+       // make sure that the data type is the right size
+       assert( sizeof( Uint32 ) * 5 == 20 );
+       
+       // initialize
+       H0 = 0x67452301;
+       H1 = 0xefcdab89;
+       H2 = 0x98badcfe;
+       H3 = 0x10325476;
+       H4 = 0xc3d2e1f0;
+       unprocessedBytes = 0;
+       size = 0;
+}
+
+// Destructor ********************************************************
+SHA1::~SHA1()
+{
+       // erase data
+       H0 = H1 = H2 = H3 = H4 = 0;
+       for( int c = 0; c < 64; c++ ) bytes[c] = 0;
+       unprocessedBytes = size = 0;
+}
+
+// process ***********************************************************
+void SHA1::process()
+{
+       assert( unprocessedBytes == 64 );
+       //printf( "process: " ); hexPrinter( bytes, 64 ); printf( "\n" );
+       int t;
+       Uint32 a, b, c, d, e, K, f, W[80];
+       // starting values
+       a = H0;
+       b = H1;
+       c = H2;
+       d = H3;
+       e = H4;
+       // copy and expand the message block
+       for( t = 0; t < 16; t++ ) W[t] = (bytes[t*4] << 24)
+                                                                       +(bytes[t*4 + 1] << 16)
+                                                                       +(bytes[t*4 + 2] << 8)
+                                                                       + bytes[t*4 + 3];
+       for(; t< 80; t++ ) W[t] = lrot( W[t-3]^W[t-8]^W[t-14]^W[t-16], 1 );
+       
+       /* main loop */
+       Uint32 temp;
+       for( t = 0; t < 80; t++ )
+       {
+               if( t < 20 ) {
+                       K = 0x5a827999;
+                       f = (b & c) | ((b ^ 0xFFFFFFFF) & d);//TODO: try using ~
+               } else if( t < 40 ) {
+                       K = 0x6ed9eba1;
+                       f = b ^ c ^ d;
+               } else if( t < 60 ) {
+                       K = 0x8f1bbcdc;
+                       f = (b & c) | (b & d) | (c & d);
+               } else {
+                       K = 0xca62c1d6;
+                       f = b ^ c ^ d;
+               }
+               temp = lrot(a,5) + f + e + W[t] + K;
+               e = d;
+               d = c;
+               c = lrot(b,30);
+               b = a;
+               a = temp;
+               //printf( "t=%d %08x %08x %08x %08x %08x\n",t,a,b,c,d,e );
+       }
+       /* add variables */
+       H0 += a;
+       H1 += b;
+       H2 += c;
+       H3 += d;
+       H4 += e;
+       //printf( "Current: %08x %08x %08x %08x %08x\n",H0,H1,H2,H3,H4 );
+       /* all bytes have been processed */
+       unprocessedBytes = 0;
+}
+
+// addBytes **********************************************************
+void SHA1::addBytes( const char* data, int num )
+{
+       assert( data );
+       assert( num > 0 );
+       // add these bytes to the running total
+       size += num;
+       // repeat until all data is processed
+       while( num > 0 )
+       {
+               // number of bytes required to complete block
+               int needed = 64 - unprocessedBytes;
+               assert( needed > 0 );
+               // number of bytes to copy (use smaller of two)
+               int toCopy = (num < needed) ? num : needed;
+               // Copy the bytes
+               memcpy( bytes + unprocessedBytes, data, toCopy );
+               // Bytes have been copied
+               num -= toCopy;
+               data += toCopy;
+               unprocessedBytes += toCopy;
+               
+               // there is a full block
+               if( unprocessedBytes == 64 ) process();
+       }
+}
+
+// digest ************************************************************
+unsigned char* SHA1::getDigest()
+{
+       // save the message size
+       Uint32 totalBitsL = size << 3;
+       Uint32 totalBitsH = size >> 29;
+       // add 0x80 to the message
+       addBytes( "\x80", 1 );
+       
+       unsigned char footer[64] = {
+               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+       // block has no room for 8-byte filesize, so finish it
+       if( unprocessedBytes > 56 )
+               addBytes( (char*)footer, 64 - unprocessedBytes);
+       assert( unprocessedBytes <= 56 );
+       // how many zeros do we need
+       int neededZeros = 56 - unprocessedBytes;
+       // store file size (in bits) in big-endian format
+       storeBigEndianUint32( footer + neededZeros    , totalBitsH );
+       storeBigEndianUint32( footer + neededZeros + 4, totalBitsL );
+       // finish the final block
+       addBytes( (char*)footer, neededZeros + 8 );
+       // allocate memory for the digest bytes
+       unsigned char* digest = (unsigned char*)malloc( 20 );
+       // copy the digest bytes
+       storeBigEndianUint32( digest, H0 );
+       storeBigEndianUint32( digest + 4, H1 );
+       storeBigEndianUint32( digest + 8, H2 );
+       storeBigEndianUint32( digest + 12, H3 );
+       storeBigEndianUint32( digest + 16, H4 );
+       // return the digest
+       return digest;
+}
diff --git a/src/sha1.h b/src/sha1.h
new file mode 100644 (file)
index 0000000..2f92fe8
--- /dev/null
@@ -0,0 +1,35 @@
+/* sha1.h
+
+Copyright (c) 2005 Michael D. Leonhard
+
+http://tamale.net/
+
+This file is licensed under the terms described in the
+accompanying LICENSE file.
+*/
+
+#ifndef SHA1_HEADER
+typedef unsigned int Uint32;
+
+class SHA1
+{
+       private:
+               // fields
+               Uint32 H0, H1, H2, H3, H4;
+               unsigned char bytes[64];
+               int unprocessedBytes;
+               Uint32 size;
+               void process();
+       public:
+               SHA1();
+               ~SHA1();
+               void addBytes( const char* data, int num );
+               unsigned char* getDigest();
+               // utility methods
+               static Uint32 lrot( Uint32 x, int bits );
+               static void storeBigEndianUint32( unsigned char* byte, Uint32 num );
+               static void hexPrinter( unsigned char* c, int l );
+};
+
+#define SHA1_HEADER
+#endif