Return to connection_client.cpp CVS log | Up to Nevrax / code / nelns / login_service |
File: Nevrax / code / nelns / login_service / connection_client.cpp (download) Revision 1.11, Mon Mar 25 09:29:24 2002 UTC (4 months ago) by lecroart Branch: MAIN CVS Tags: HEAD Changes since 1.10: +3 -3 lines CHANGED: use new service functions |
/** \file login_service.cpp * Login Service (LS) * * $Id: connection_client.cpp,v 1.11 2002/03/25 09:29:24 lecroart Exp $ * */ /* Copyright, 2000 Nevrax Ltd. * * This file is part of NEVRAX NeL Network Services. * NEVRAX NeL Network Services is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * NEVRAX NeL Network Services is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with NEVRAX NeL Network Services; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. */ #include "nel/misc/types_nl.h" #include <stdio.h> #include <ctype.h> #include <math.h> #include <vector> #include <map> #include "nel/misc/debug.h" #include "nel/misc/config_file.h" #include "nel/misc/displayer.h" #include "nel/misc/log.h" #include "nel/net/service.h" #include "nel/net/net_manager.h" #include "nel/net/login_cookie.h" #include "login_service.h" #define CRYPT_PASSWORD 1 #if defined(NL_OS_UNIX) && CRYPT_PASSWORD extern "C" char *crypt (const char *__key, const char *__salt); #endif using namespace std; using namespace NLMISC; using namespace NLNET; // These functions enable crypting password, work only on unix const uint32 EncryptedSize = 13; // Get a number between 0 and 64, used by cryptPassword static uint32 rand64 () { return (uint32) floor(64.0*(double)rand()/((double)RAND_MAX+1.0)); } // Crypt a password string cryptPassword (const string &password) { #if defined(NL_OS_UNIX) && CRYPT_PASSWORD if (CryptPassword) { char Salt[3]; static char SaltString[65] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"; Salt[0] = SaltString[rand64()]; Salt[1] = SaltString[rand64()]; Salt[2] = '\0'; return string (crypt (password.c_str(), Salt)); } else return password; #else return password; #endif } // Check if a password is valid bool checkPassword (const string &password, const string &encrypted) { #if defined(NL_OS_UNIX) && CRYPT_PASSWORD if (CryptPassword) { char Salt[3]; if (encrypted.size() != EncryptedSize) { nlwarning ("checkPassword(): \"%s\" is not a valid encrypted password", encrypted.c_str()); return false; } Salt[0] = encrypted[0]; Salt[1] = encrypted[1]; Salt[2] = '\0'; return encrypted == crypt (password.c_str(), Salt); } else { return encrypted == password; } #else return encrypted == password; #endif } sint findUser (string &login) { for (sint i = 0; i < (sint) Users.size (); i++) { if (Users[i].Login == login) { return i; } } // user not found return -1; } void addUser (string &login, string &password) { if (findUser (login) == -1) { Users.push_back (CUser (login, cryptPassword(password))); writePlayerDatabase (); } else { nlwarning ("user '%s' already exists in the base", login.c_str ()); } } sint userToLog(sint userPos) { if (userPos == -1) return userPos; else return Users[userPos].Id; } bool stringIsStandard(const string &str) { for (sint i = 0; i < (sint) str.size(); i++) { if (!isalnum (str[i])) return false; } return true; } bool havePrivilege (string userPriv, string shardPriv) { if (userPriv == "::") { return shardPriv == "::"; } else { if (shardPriv == "::") return true; else return userPriv.find (shardPriv) != string::npos; } } //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// /////////////// CONNECTION TO THE CLIENTS ////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// /** * Callback for service unregistration. * * Message expected : * - nothing */ static void cbClientVerifyLoginPassword (CMessage &msgin, TSockId from, CCallbackNetBase &netbase) { // reason is empty if everything goes right or contains the reason of the failure string reason = ""; // // S03: check the validity of the client login/password and send "VLP" message to client // string Login, Password; msgin.serial (Login); msgin.serial (Password); sint userPos = findUser (Login); const CInetAddress &ia = netbase.hostAddress (from); Output.displayNL ("***: %3d Login '%s' Ip '%s'", userToLog(userPos), Login.c_str(), ia.asString().c_str()); // recv the client version and check it uint32 ClientVersion; msgin.serial (ClientVersion); if (ClientVersion < ServerVersion || ClientVersion > ServerVersion) { // reject the use, bad version if (ClientVersion < ServerVersion) reason = "Your client is out of date. You have to download the last version."; else reason = "Your client is too new compare to the server. You have to get an older version of the client."; Output.displayNL ("---: %3d Bad Version, ClientVersion: %d ServerVersion: %d", userToLog(userPos), ClientVersion, ServerVersion); } // recv client hardware info string OS, Proc, Mem, Gfx; msgin.serial (OS); msgin.serial (Proc); msgin.serial (Mem); msgin.serial (Gfx); if (!OS.empty()) Output.displayNL ("OS : %3d %s", userToLog(userPos), OS.c_str()); if (!Proc.empty()) Output.displayNL ("PRC: %3d %s", userToLog(userPos), Proc.c_str()); if (!Mem.empty()) Output.displayNL ("MEM: %3d %s", userToLog(userPos), Mem.c_str()); if (!Gfx.empty()) Output.displayNL ("GFX: %3d %s", userToLog(userPos), Gfx.c_str()); // check the login & pass if (reason.empty() && !stringIsStandard (Login)) { // reject the new user, bad login format reason = "Bad login format, only alphanumeric character"; Output.displayNL ("---: %3d Bad Login Format", userToLog(userPos)); } if (reason.empty() && !stringIsStandard (Password)) { // reject the new user, bad password format reason = "Bad password format, only alphanumeric character"; Output.displayNL ("---: %3d Bad Password Format", userToLog(userPos)); } if (reason.empty()) { if (userPos == -1) { // unknown user if (AcceptNewUser) { // add the new user addUser (Login, Password); // take the new user entry userPos = findUser (Login); Output.displayNL ("---: %3d New User (new id:%d)", -1, userToLog(userPos)); } else { // reject the new user reason = "Bad login"; Output.displayNL ("---: %3d Bad Login", userToLog(userPos)); } } else { // check id the account is active if (!Users[userPos].Active) { reason = "Your account was disactivated"; Output.displayNL ("---: %3d Your account was disactivated", userToLog(userPos)); } else if (!checkPassword (Password, Users[userPos].Password)) { // error reason reason = "Bad password"; Output.displayNL ("---: %3d Bad Password", userToLog(userPos)); } else { Output.displayNL ("---: %3d Ok", userToLog(userPos)); } } } if (reason.empty()) { reason = Users[userPos].Authorize (from, netbase); } uint32 nbshard = 0; if (reason.empty()) { // count online shards for (uint i = 0; i < Shards.size (); i++) { // add it only if the shard is on line and the user can go to this shard if (Shards[i].Online && havePrivilege(Users[userPos].ShardPrivilege, Shards[i].ShardName)) { nbshard++; } } if (nbshard==0) { reason = "No shards available"; } } CMessage msgout (netbase.getSIDA (), "VLP"); if (reason.empty()) { uint8 ok = 1; msgout.serial (ok); // send number of online shard msgout.serial (nbshard); // send address and name of all online shards for (uint i = 0; i < Shards.size (); i++) { if (Shards[i].Online && havePrivilege (Users[userPos].ShardPrivilege, Shards[i].ShardName)) { // serial the name of the shard string shardname; shardname = Shards[i].Name; if (Shards[i].NbPlayers == 0) { shardname += " (no users)"; } else { char num[1024]; smprintf(num, 1024, "%d", Shards[i].NbPlayers); shardname += " ("; shardname += num; if (Shards[i].NbPlayers == 1) shardname += " user)"; else shardname += " users)"; } msgout.serial (shardname); // serial the address of the WS service msgout.serial (Shards[i].WSAddr); } } netbase.send (msgout, from); netbase.authorizeOnly ("CS", from); } else { // put the error message uint8 ok = 0; msgout.serial (ok); msgout.serial (reason); netbase.send (msgout, from); // FIX: On linux, when we disconnect now, sometime the other side doesnt receive the message sent just before. // So it's the other side to disconnect // netbase.disconnect (from); } } static void cbClientChooseShard (CMessage &msgin, TSockId from, CCallbackNetBase &netbase) { // // S06: receive "CS" message from client // // first find if the user is authorized for (vector<CUser>::iterator it = Users.begin (); it != Users.end (); it++) { if ((*it).Authorized && (*it).SockId == from) { // it's ok, so we found the wanted shard string WSAddr; msgin.serial (WSAddr); for (sint32 i = 0; i < (sint32) Shards.size (); i++) { if (Shards[i].Online && Shards[i].WSAddr == WSAddr && havePrivilege ((*it).ShardPrivilege, Shards[i].ShardName)) { CMessage msgout (CNetManager::getNetBase("WSLS")->getSIDA (), "CS"); const CInetAddress &ia = netbase.hostAddress ((*it).SockId); msgout.serial ((*it).Cookie); CNetManager::send("WSLS", msgout, Shards[i].SockId); beep (1000, 1, 100, 100); return; } } // the shard is not available, denied the user nlwarning("User try to choose a shard without authorization"); CMessage msgout (netbase.getSIDA (), "SCS"); uint8 ok = false; string reason = "Selected shard is not available"; msgout.serial (ok); msgout.serial (reason); netbase.send (msgout, from); // FIX: On linux, when we disconnect now, sometime the other side doesnt receive the message sent just before. // So it's the other side to disconnect // netbase.disconnect (from); return; } } // the user isn t authorized nlwarning("User try to choose a shard without authorization"); // disconnect him netbase.disconnect (from); } static void cbClientConnection (const string &serviceName, TSockId from, void *arg) { CCallbackNetBase *cnb = CNetManager::getNetBase("LS"); const CInetAddress &ia = cnb->hostAddress (from); nldebug("new client connection: %s", ia.asString ().c_str ()); Output.displayNL ("CCC: Connection from %s", ia.asString ().c_str ()); if (ia.asString().find ("nevrax") != string::npos) { // internal connection beep (); } else { // external connection beep (1000, 2, 100, 100); } cnb->authorizeOnly ("VLP", from); } static void cbClientDisconnection (const string &serviceName, TSockId from, void *arg) { CCallbackNetBase *cnb = CNetManager::getNetBase("LS"); const CInetAddress &ia = cnb->hostAddress (from); nldebug("new client disconnection: %s", ia.asString ().c_str ()); // remove the user if necessary for (vector<CUser>::iterator it = Users.begin (); it != Users.end (); it++) { if ((*it).SockId == from) { if ((*it).State == CUser::Awaiting) { // the user is disconnected from me because he have to connect to the front end right now, so we wait... } else { // prematurated disconnection, clean everything disconnectClient (*it, false, false); } (*it).SockId = NULL; return; } } } const TCallbackItem ClientCallbackArray[] = { { "VLP", cbClientVerifyLoginPassword }, { "CS", cbClientChooseShard }, }; // if you add callback in the client side, don't forget to add it here!!! static const char *OtherSideAssociations[] = { "AA", "RA", "RAA", "VLP", "SCS", }; void connectionClientInit () { CNetManager::addCallbackArray ("LS", ClientCallbackArray, sizeof(ClientCallbackArray)/sizeof(ClientCallbackArray[0])); CNetManager::setConnectionCallback ("LS", cbClientConnection, NULL); CNetManager::setDisconnectionCallback ("LS", cbClientDisconnection, NULL); CNetManager::getNetBase("LS")->setOtherSideAssociations(OtherSideAssociations, sizeof(OtherSideAssociations)/sizeof(OtherSideAssociations[0])); }