Fix processing of the default_password setting. It is now actually used as the plaintext password for new users. Also add /setpassword and /clearpassword server commands that can be used by admins with the PRIV_PASSWORD privilege, and update the /help message.

This commit is contained in:
Kahrl 2011-11-20 20:16:15 +01:00 committed by Perttu Ahola
parent 1901158b3e
commit 2ca00fa585
5 changed files with 109 additions and 36 deletions

@ -42,6 +42,8 @@ std::set<std::string> privsToSet(u64 privs)
s.insert("ban"); s.insert("ban");
if(privs & PRIV_GIVE) if(privs & PRIV_GIVE)
s.insert("give"); s.insert("give");
if(privs & PRIV_PASSWORD)
s.insert("password");
return s; return s;
} }
@ -64,6 +66,8 @@ std::string privsToString(u64 privs)
os<<"ban,"; os<<"ban,";
if(privs & PRIV_GIVE) if(privs & PRIV_GIVE)
os<<"give,"; os<<"give,";
if(privs & PRIV_PASSWORD)
os<<"password,";
if(os.tellp()) if(os.tellp())
{ {
// Drop the trailing comma. (Why on earth can't // Drop the trailing comma. (Why on earth can't
@ -98,6 +102,8 @@ u64 stringToPrivs(std::string str)
privs |= PRIV_BAN; privs |= PRIV_BAN;
else if(s == "give") else if(s == "give")
privs |= PRIV_GIVE; privs |= PRIV_GIVE;
else if(s == "password")
privs |= PRIV_PASSWORD;
else else
return PRIV_INVALID; return PRIV_INVALID;
} }

@ -41,6 +41,7 @@ const u64 PRIV_SHOUT = 32; // Can broadcast chat messages to all
// players // players
const u64 PRIV_BAN = 64; // Can ban players const u64 PRIV_BAN = 64; // Can ban players
const u64 PRIV_GIVE = 128; // Can give stuff const u64 PRIV_GIVE = 128; // Can give stuff
const u64 PRIV_PASSWORD = 256; // Can set other players' passwords
// Default privileges - these can be overriden for new players using the // Default privileges - these can be overriden for new players using the
// config option "default_privs" - however, this value still applies for // config option "default_privs" - however, this value still applies for

@ -2171,20 +2171,33 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
password[PASSWORD_SIZE-1] = 0; password[PASSWORD_SIZE-1] = 0;
} }
std::string checkpwd; // Add player to auth manager
if(m_authmanager.exists(playername)) if(m_authmanager.exists(playername) == false)
{ {
checkpwd = m_authmanager.getPassword(playername); std::wstring default_password =
narrow_to_wide(g_settings->get("default_password"));
std::string translated_default_password =
translatePassword(playername, default_password);
// If default_password is empty, allow any initial password
if (default_password.length() == 0)
translated_default_password = password;
infostream<<"Server: adding player "<<playername
<<" to auth manager"<<std::endl;
m_authmanager.add(playername);
m_authmanager.setPassword(playername, translated_default_password);
m_authmanager.setPrivs(playername,
stringToPrivs(g_settings->get("default_privs")));
m_authmanager.save();
} }
else
{ std::string checkpwd = m_authmanager.getPassword(playername);
checkpwd = g_settings->get("default_password");
}
/*infostream<<"Server: Client gave password '"<<password /*infostream<<"Server: Client gave password '"<<password
<<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/ <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
if(password != checkpwd && m_authmanager.exists(playername)) if(password != checkpwd)
{ {
infostream<<"Server: peer_id="<<peer_id infostream<<"Server: peer_id="<<peer_id
<<": supplied invalid password for " <<": supplied invalid password for "
@ -2193,23 +2206,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
return; return;
} }
// Add player to auth manager
if(m_authmanager.exists(playername) == false)
{
infostream<<"Server: adding player "<<playername
<<" to auth manager"<<std::endl;
m_authmanager.add(playername);
m_authmanager.setPassword(playername, checkpwd);
m_authmanager.setPrivs(playername,
stringToPrivs(g_settings->get("default_privs")));
m_authmanager.save();
}
// Enforce user limit. // Enforce user limit.
// Don't enforce for users that have some admin right // Don't enforce for users that have some admin right
if(m_clients.size() >= g_settings->getU16("max_users") && if(m_clients.size() >= g_settings->getU16("max_users") &&
(m_authmanager.getPrivs(playername) (m_authmanager.getPrivs(playername)
& (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS)) == 0 && & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS|PRIV_PASSWORD)) == 0 &&
playername != g_settings->get("name")) playername != g_settings->get("name"))
{ {
SendAccessDenied(m_con, peer_id, L"Too many users."); SendAccessDenied(m_con, peer_id, L"Too many users.");
@ -2217,7 +2218,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
} }
// Get player // Get player
Player *player = emergePlayer(playername, password, peer_id); Player *player = emergePlayer(playername, peer_id);
// If failed, cancel // If failed, cancel
if(player == NULL) if(player == NULL)
@ -4678,6 +4679,22 @@ std::wstring Server::getStatusString()
return os.str(); return os.str();
} }
void Server::setPlayerPassword(const std::string &name, const std::wstring &password)
{
// Add player to auth manager
if(m_authmanager.exists(name) == false)
{
infostream<<"Server: adding player "<<name
<<" to auth manager"<<std::endl;
m_authmanager.add(name);
m_authmanager.setPrivs(name,
stringToPrivs(g_settings->get("default_privs")));
}
// Change password and save
m_authmanager.setPassword(name, translatePassword(name, password));
m_authmanager.save();
}
// Saves g_settings to configpath given at initialization // Saves g_settings to configpath given at initialization
void Server::saveConfig() void Server::saveConfig()
{ {
@ -4813,7 +4830,7 @@ v3f findSpawnPos(ServerMap &map)
return intToFloat(nodepos, BS); return intToFloat(nodepos, BS);
} }
Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id) Player *Server::emergePlayer(const char *name, u16 peer_id)
{ {
/* /*
Try to get an existing player Try to get an existing player
@ -4859,12 +4876,6 @@ Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id
Create a new player Create a new player
*/ */
{ {
// Add authentication stuff
m_authmanager.add(name);
m_authmanager.setPassword(name, password);
m_authmanager.setPrivs(name,
stringToPrivs(g_settings->get("default_privs")));
/* Set player position */ /* Set player position */
infostream<<"Server: Finding spawn place for player \"" infostream<<"Server: Finding spawn place for player \""

@ -456,6 +456,10 @@ public:
dstream<<"WARNING: Auth not found for "<<name<<std::endl; dstream<<"WARNING: Auth not found for "<<name<<std::endl;
} }
} }
// Changes a player's password, password must be given as plaintext
// If the player doesn't exist, a new entry is added to the auth manager
void setPlayerPassword(const std::string &name, const std::wstring &password);
// Saves g_settings to configpath given at initialization // Saves g_settings to configpath given at initialization
void saveConfig(); void saveConfig();
@ -591,12 +595,11 @@ private:
/* /*
Get a player from memory or creates one. Get a player from memory or creates one.
If player is already connected, return NULL If player is already connected, return NULL
The password is not checked here - it is only used to Does not verify/modify auth info and password.
set the password if a new player is created.
Call with env and con locked. Call with env and con locked.
*/ */
Player *emergePlayer(const char *name, const char *password, u16 peer_id); Player *emergePlayer(const char *name, u16 peer_id);
// Locks environment and connection by its own // Locks environment and connection by its own
struct PeerChange; struct PeerChange;

@ -281,6 +281,54 @@ void cmd_banunban(std::wostringstream &os, ServerCommandContext *ctx)
} }
} }
void cmd_setclearpassword(std::wostringstream &os,
ServerCommandContext *ctx)
{
if((ctx->privs & PRIV_PASSWORD) == 0)
{
os<<L"-!- You don't have permission to do that";
return;
}
std::string playername;
std::wstring password;
if(ctx->parms[0] == L"setpassword")
{
if(ctx->parms.size() != 3)
{
os<<L"-!- Missing parameter";
return;
}
playername = wide_to_narrow(ctx->parms[1]);
password = ctx->parms[2];
actionstream<<ctx->player->getName()<<" sets password of "
<<playername<<std::endl;
}
else
{
// clearpassword
if(ctx->parms.size() != 2)
{
os<<L"-!- Missing parameter";
return;
}
playername = wide_to_narrow(ctx->parms[1]);
password = L"";
actionstream<<ctx->player->getName()<<" clears password of"
<<playername<<std::endl;
}
ctx->server->setPlayerPassword(playername, password);
os<<L"-!- Password change for "<<narrow_to_wide(playername)<<" successful";
}
void cmd_clearobjects(std::wostringstream &os, void cmd_clearobjects(std::wostringstream &os,
ServerCommandContext *ctx) ServerCommandContext *ctx)
{ {
@ -322,9 +370,9 @@ std::wstring processServerCommand(ServerCommandContext *ctx)
if(ctx->parms.size() == 0 || ctx->parms[0] == L"help") if(ctx->parms.size() == 0 || ctx->parms[0] == L"help")
{ {
os<<L"-!- Available commands: "; os<<L"-!- Available commands: ";
os<<L"status privs "; os<<L"me status privs";
if(privs & PRIV_SERVER) if(privs & PRIV_SERVER)
os<<L"shutdown setting "; os<<L" shutdown setting clearobjects";
if(privs & PRIV_SETTIME) if(privs & PRIV_SETTIME)
os<<L" time"; os<<L" time";
if(privs & PRIV_TELEPORT) if(privs & PRIV_TELEPORT)
@ -333,6 +381,8 @@ std::wstring processServerCommand(ServerCommandContext *ctx)
os<<L" grant revoke"; os<<L" grant revoke";
if(privs & PRIV_BAN) if(privs & PRIV_BAN)
os<<L" ban unban"; os<<L" ban unban";
if(privs & PRIV_PASSWORD)
os<<L" setpassword clearpassword";
} }
else if(ctx->parms[0] == L"status") else if(ctx->parms[0] == L"status")
cmd_status(os, ctx); cmd_status(os, ctx);
@ -350,6 +400,8 @@ std::wstring processServerCommand(ServerCommandContext *ctx)
cmd_teleport(os, ctx); cmd_teleport(os, ctx);
else if(ctx->parms[0] == L"ban" || ctx->parms[0] == L"unban") else if(ctx->parms[0] == L"ban" || ctx->parms[0] == L"unban")
cmd_banunban(os, ctx); cmd_banunban(os, ctx);
else if(ctx->parms[0] == L"setpassword" || ctx->parms[0] == L"clearpassword")
cmd_setclearpassword(os, ctx);
else if(ctx->parms[0] == L"me") else if(ctx->parms[0] == L"me")
cmd_me(os, ctx); cmd_me(os, ctx);
else if(ctx->parms[0] == L"clearobjects") else if(ctx->parms[0] == L"clearobjects")