Merge: New map directory structure and player passwords

This commit is contained in:
Perttu Ahola 2011-05-21 01:11:58 +03:00
commit 76e241392d
21 changed files with 680 additions and 82 deletions

@ -95,6 +95,8 @@ set(minetest_SRCS
tile.cpp
game.cpp
main.cpp
sha1.cpp
base64.cpp
)
# Server sources

123
src/base64.cpp Normal file

@ -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;
}

4
src/base64.h Normal file

@ -0,0 +1,4 @@
#include <string>
std::string base64_encode(unsigned char const* , unsigned int len);
std::string base64_decode(std::string const& s);

@ -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"

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

@ -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,

@ -290,5 +290,24 @@ bool RecursiveDeleteContent(std::string path)
return true;
}
bool CreateAllDirs(std::string path)
{
size_t pos;
std::vector<std::string> tocreate;
std::string basepath = path;
while(!PathExists(basepath))
{
tocreate.push_back(basepath);
pos = basepath.rfind('/');
if(pos == std::string::npos)
return false;
basepath = basepath.substr(0,pos);
}
for(int i=tocreate.size()-1;i>=0;i--)
CreateDir(tocreate[i]);
return true;
}
} // namespace fs

@ -38,6 +38,9 @@ std::vector<DirListNode> GetDirListing(std::string path);
// Returns true if already exists
bool CreateDir(std::string path);
// Create all directories on the given path that don't already exist.
bool CreateAllDirs(std::string path);
bool PathExists(std::string path);
// Only pass full paths to this one. True on success.

@ -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
@ -672,7 +673,6 @@ void the_game(
guienv->drawAll();
driver->endScene();
std::cout<<DTIME<<"Creating server and client"<<std::endl;
/*
Create server.
@ -680,6 +680,7 @@ void the_game(
*/
SharedPtr<Server> server;
if(address == ""){
std::cout<<DTIME<<"Creating server"<<std::endl;
server = new Server(map_dir);
server->start(port);
}
@ -688,7 +689,8 @@ void the_game(
Create client
*/
Client client(device, playername.c_str(), draw_control);
std::cout<<DTIME<<"Creating client"<<std::endl;
Client client(device, playername.c_str(), password, draw_control);
Address connect_address(0,0,0,0, port);
try{
@ -727,6 +729,10 @@ void the_game(
could_connect = true;
break;
}
if(client.accessDenied())
{
break;
}
// Wait for 10 seconds
if(time_counter >= 10.0)
{
@ -755,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;
}

@ -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

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

@ -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

@ -325,6 +325,8 @@ Making it more portable:
#include "materials.h"
#include "game.h"
#include "keycode.h"
#include "sha1.h"
#include "base64.h"
// This makes textures
ITextureSource *g_texturesource = NULL;
@ -1170,6 +1172,7 @@ int main(int argc, char *argv[])
return 0;
}
/*
More parameters
*/
@ -1324,11 +1327,15 @@ int main(int argc, char *argv[])
*/
std::wstring error_message = L"";
// The password entered during the menu screen,
std::string password;
/*
Menu-game loop
*/
while(device->run() && kill == false)
{
// This is used for catching disconnects
try
{
@ -1428,6 +1435,26 @@ int main(int argc, char *argv[])
}
playername = wide_to_narrow(menudata.name);
// Get an sha-1 hash of the player's name combined with
// the password entered. That's what the server uses as
// their password. (Exception : if the password field is
// blank, we send a blank password - this is for backwards
// compatibility with password-less players).
if(menudata.password.length() > 0)
{
std::string slt=playername + wide_to_narrow(menudata.password);
SHA1 *sha1 = new SHA1();
sha1->addBytes(slt.c_str(), slt.length());
unsigned char *digest = sha1->getDigest();
password = base64_encode(digest, 20);
free(digest);
}
else
{
password = "";
}
address = wide_to_narrow(menudata.address);
int newport = stoi(wide_to_narrow(menudata.port));
if(newport != 0)
@ -1474,6 +1501,7 @@ int main(int argc, char *argv[])
font,
map_dir,
playername,
password,
address,
port,
error_message

@ -4875,9 +4875,9 @@ plan_b:
return (s16)level;
}
void ServerMap::createDir(std::string path)
void ServerMap::createDirs(std::string path)
{
if(fs::CreateDir(path) == false)
if(fs::CreateAllDirs(path) == false)
{
m_dout<<DTIME<<"ServerMap: Failed to create directory "
<<"\""<<path<<"\""<<std::endl;
@ -4885,29 +4885,52 @@ void ServerMap::createDir(std::string path)
}
}
std::string ServerMap::getSectorSubDir(v2s16 pos)
std::string ServerMap::getSectorDir(v2s16 pos, int layout)
{
char cc[9];
snprintf(cc, 9, "%.4x%.4x",
(unsigned int)pos.X&0xffff,
(unsigned int)pos.Y&0xffff);
switch(layout)
{
case 1:
snprintf(cc, 9, "%.4x%.4x",
(unsigned int)pos.X&0xffff,
(unsigned int)pos.Y&0xffff);
return std::string(cc);
}
return m_savedir + "/sectors/" + cc;
case 2:
snprintf(cc, 9, "%.3x/%.3x",
(unsigned int)pos.X&0xfff,
(unsigned int)pos.Y&0xfff);
std::string ServerMap::getSectorDir(v2s16 pos)
{
return m_savedir + "/sectors/" + getSectorSubDir(pos);
return m_savedir + "/sectors2/" + cc;
default:
assert(false);
}
}
v2s16 ServerMap::getSectorPos(std::string dirname)
{
if(dirname.size() != 8)
throw InvalidFilenameException("Invalid sector directory name");
unsigned int x, y;
int r = sscanf(dirname.c_str(), "%4x%4x", &x, &y);
if(r != 2)
throw InvalidFilenameException("Invalid sector directory name");
int r;
size_t spos = dirname.rfind('/') + 1;
assert(spos != std::string::npos);
if(dirname.size() - spos == 8)
{
// Old layout
r = sscanf(dirname.substr(spos).c_str(), "%4x%4x", &x, &y);
}
else if(dirname.size() - spos == 3)
{
// New layout
r = sscanf(dirname.substr(spos-4).c_str(), "%3x/%3x", &x, &y);
// Sign-extend the 12 bit values up to 16 bits...
if(x&0x800) x|=0xF000;
if(y&0x800) y|=0xF000;
}
else
{
assert(false);
}
assert(r == 2);
v2s16 pos((s16)x, (s16)y);
return pos;
}
@ -5106,7 +5129,7 @@ void ServerMap::saveMapMeta()
<<"seed="<<m_seed<<", chunksize="<<m_chunksize
<<std::endl;
createDir(m_savedir);
createDirs(m_savedir);
std::string fullpath = m_savedir + "/map_meta.txt";
std::ofstream os(fullpath.c_str(), std::ios_base::binary);
@ -5179,7 +5202,7 @@ void ServerMap::saveChunkMeta()
dstream<<"INFO: ServerMap::saveChunkMeta(): Saving metadata of "
<<count<<" chunks"<<std::endl;
createDir(m_savedir);
createDirs(m_savedir);
std::string fullpath = m_savedir + "/chunk_meta";
std::ofstream os(fullpath.c_str(), std::ios_base::binary);
@ -5267,10 +5290,8 @@ void ServerMap::saveSectorMeta(ServerMapSector *sector)
u8 version = SER_FMT_VER_HIGHEST;
// Get destination
v2s16 pos = sector->getPos();
createDir(m_savedir);
createDir(m_savedir+"/sectors");
std::string dir = getSectorDir(pos);
createDir(dir);
createDirs(dir);
std::string fullpath = dir + "/meta";
std::ofstream o(fullpath.c_str(), std::ios_base::binary);
@ -5282,22 +5303,21 @@ void ServerMap::saveSectorMeta(ServerMapSector *sector)
sector->differs_from_disk = false;
}
MapSector* ServerMap::loadSectorMeta(std::string dirname)
MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
{
DSTACK(__FUNCTION_NAME);
// Get destination
v2s16 p2d = getSectorPos(dirname);
std::string dir = m_savedir + "/sectors/" + dirname;
v2s16 p2d = getSectorPos(sectordir);
ServerMapSector *sector = NULL;
std::string fullpath = dir + "/meta";
std::string fullpath = sectordir + "/meta";
std::ifstream is(fullpath.c_str(), std::ios_base::binary);
if(is.good() == false)
{
// If the directory exists anyway, it probably is in some old
// format. Just go ahead and create the sector.
if(fs::PathExists(dir))
if(fs::PathExists(sectordir))
{
dstream<<"ServerMap::loadSectorMeta(): Sector metafile "
<<fullpath<<" doesn't exist but directory does."
@ -5307,12 +5327,16 @@ MapSector* ServerMap::loadSectorMeta(std::string dirname)
m_sectors.insert(p2d, sector);
}
else
{
throw FileNotGoodException("Cannot open sector metafile");
}
}
else
{
sector = ServerMapSector::deSerialize
(is, this, p2d, m_sectors);
if(save_after_load)
saveSectorMeta(sector);
}
sector->differs_from_disk = false;
@ -5323,14 +5347,31 @@ MapSector* ServerMap::loadSectorMeta(std::string dirname)
bool ServerMap::loadSectorFull(v2s16 p2d)
{
DSTACK(__FUNCTION_NAME);
std::string sectorsubdir = getSectorSubDir(p2d);
MapSector *sector = NULL;
// The directory layout we're going to load from.
// 1 - original sectors/xxxxzzzz/
// 2 - new sectors2/xxx/zzz/
// If we load from anything but the latest structure, we will
// immediately save to the new one, and remove the old.
int loadlayout = 1;
std::string sectordir1 = getSectorDir(p2d, 1);
std::string sectordir;
if(fs::PathExists(sectordir1))
{
sectordir = sectordir1;
}
else
{
loadlayout = 2;
sectordir = getSectorDir(p2d, 2);
}
//JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
try{
sector = loadSectorMeta(sectorsubdir);
sector = loadSectorMeta(sectordir, loadlayout != 2);
}
catch(InvalidFilenameException &e)
{
@ -5349,7 +5390,7 @@ bool ServerMap::loadSectorFull(v2s16 p2d)
Load blocks
*/
std::vector<fs::DirListNode> list2 = fs::GetDirListing
(m_savedir+"/sectors/"+sectorsubdir);
(sectordir);
std::vector<fs::DirListNode>::iterator i2;
for(i2=list2.begin(); i2!=list2.end(); i2++)
{
@ -5357,16 +5398,25 @@ bool ServerMap::loadSectorFull(v2s16 p2d)
if(i2->dir)
continue;
try{
loadBlock(sectorsubdir, i2->name, sector);
loadBlock(sectordir, i2->name, sector, loadlayout != 2);
}
catch(InvalidFilenameException &e)
{
// This catches unknown crap in directory
}
}
if(loadlayout != 2)
{
dstream<<"Sector converted to new layout - deleting "<<
sectordir1<<std::endl;
fs::RecursiveDelete(sectordir1);
}
return true;
}
void ServerMap::saveBlock(MapBlock *block)
{
DSTACK(__FUNCTION_NAME);
@ -5386,12 +5436,9 @@ void ServerMap::saveBlock(MapBlock *block)
// Get destination
v3s16 p3d = block->getPos();
v2s16 p2d(p3d.X, p3d.Z);
createDir(m_savedir);
createDir(m_savedir+"/sectors");
std::string dir = getSectorDir(p2d);
createDir(dir);
createDirs(dir);
// Block file is map/sectors/xxxxxxxx/xxxx
char cc[5];
snprintf(cc, 5, "%.4x", (unsigned int)p3d.Y&0xffff);
std::string fullpath = dir + "/" + cc;
@ -5427,12 +5474,11 @@ void ServerMap::saveBlock(MapBlock *block)
block->resetChangedFlag();
}
void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector)
void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load)
{
DSTACK(__FUNCTION_NAME);
// Block file is map/sectors/xxxxxxxx/xxxx
std::string fullpath = m_savedir+"/sectors/"+sectordir+"/"+blockfile;
std::string fullpath = sectordir+"/"+blockfile;
try{
std::ifstream is(fullpath.c_str(), std::ios_base::binary);
@ -5496,7 +5542,7 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto
*/
// Save old format blocks in new format
if(version < SER_FMT_VER_HIGHEST)
if(version < SER_FMT_VER_HIGHEST || save_after_load)
{
saveBlock(block);
}

@ -545,13 +545,9 @@ public:
Misc. helper functions for fiddling with directory and file
names when saving
*/
void createDir(std::string path);
void createSaveDir();
// returns something like "xxxxxxxx"
std::string getSectorSubDir(v2s16 pos);
void createDirs(std::string path);
// returns something like "map/sectors/xxxxxxxx"
std::string getSectorDir(v2s16 pos);
std::string createSectorDir(v2s16 pos);
std::string getSectorDir(v2s16 pos, int layout = 2);
// dirname: final directory name
v2s16 getSectorPos(std::string dirname);
v3s16 getBlockPos(std::string sectordir, std::string blockfile);
@ -572,7 +568,7 @@ public:
// (no MapBlocks)
// DEPRECATED? Sectors have no metadata anymore.
void saveSectorMeta(ServerMapSector *sector);
MapSector* loadSectorMeta(std::string dirname);
MapSector* loadSectorMeta(std::string dirname, bool save_after_load);
// Full load of a sector including all blocks.
// returns true on success, false on failure.
@ -583,7 +579,7 @@ public:
void saveBlock(MapBlock *block);
// This will generate a sector with getSector if not found.
void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector);
void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load=false);
// For debug printing
virtual void PrintInfo(std::ostream &out);

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

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

@ -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] = 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

@ -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.

207
src/sha1.cpp Normal file

@ -0,0 +1,207 @@
/* sha1.cpp
Copyright (c) 2005 Michael D. Leonhard
http://tamale.net/
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#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;
}

51
src/sha1.h Normal file

@ -0,0 +1,51 @@
/* sha1.h
Copyright (c) 2005 Michael D. Leonhard
http://tamale.net/
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#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