From: <z-...@us...> - 2008-01-21 10:36:46
|
Revision: 7559 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7559&view=rev Author: z-man Date: 2008-01-21 02:36:51 -0800 (Mon, 21 Jan 2008) Log Message: ----------- Commited patch 0.4, basically. Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/configure.ac armagetronad/branches/0.2.8-auth/armagetronad/language/deutsch.txt armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.h armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.h armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/network/nServerInfo.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tMemManager.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tToDo.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gAIBase.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gCycle.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gGame.cpp Modified: armagetronad/branches/0.2.8-auth/armagetronad/configure.ac =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/configure.ac 2008-01-21 10:34:14 UTC (rev 7558) +++ armagetronad/branches/0.2.8-auth/armagetronad/configure.ac 2008-01-21 10:36:51 UTC (rev 7559) @@ -127,12 +127,12 @@ AC_ARG_ENABLE(krawall, AC_HELP_STRING([--enable-krawall], - [enable special code for the krawall gaming network (user authentification...) (default=disabled)]),, + [enable special visuals for the krawall gaming network (default=disabled)]),, enable_krawall=no) AC_ARG_ENABLE(krawallserver, AC_HELP_STRING([--enable-krawallserver], - [enable special code for the krawall gaming network SERVER (user database query...). dont't touch this! (default=disabled)]),, + [enable special code for the krawall style user authentication (default=disabled)]),, enable_krawallserver=no) AC_ARG_ENABLE(automakedefaults, @@ -505,8 +505,25 @@ ) # fi +dnl ************************************************* +dnl ZThread +dnl ************************************************* + +test -z "$ZTHREAD_CONFIG" && ZTHREAD_CONFIG=zthread-config + +if $ZTHREAD_CONFIG --libs > /dev/null; then + CPPFLAGS="$CPPFLAGS `$ZTHREAD_CONFIG --cflags`" + LIBS="`$ZTHREAD_CONFIG --libs` $LIBS" + AC_CHECK_LIB(ZThread,xmlParseMemory, + AC_DEFINE(HAVE_LIBZTHREAD,,[Define if you have the ZThread library]), + AC_MSG_WARN([ZThread library not found; $ZRHREAD_CONFIG gave non-working linker flags.]) + ,) +else + AC_MSG_WARN([ZThread library not found; $ZRHREAD_CONFIG does not work/exist.]) fi +fi # armamainx + dnl ************************************************* dnl math dnl ************************************************* Modified: armagetronad/branches/0.2.8-auth/armagetronad/language/deutsch.txt =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/language/deutsch.txt 2008-01-21 10:34:14 UTC (rev 7558) +++ armagetronad/branches/0.2.8-auth/armagetronad/language/deutsch.txt 2008-01-21 10:36:51 UTC (rev 7559) @@ -2452,13 +2452,13 @@ #login texts login_password_title Passwort : -login_password_help Trage hier Dein Krawall-Passwort ein (zu erhalten unter www.krawall.de). Zum Login hier einfach Return dr\xFCcken. +login_password_help Trage hier Dein Passwort ein. Zum Login hier einfach Return dr\xFCcken. login_cancel Login abbrechen login_cancel_help Hiermit wird die Loginprozedur beendet und zum Netzwerk-Menu zur\xFCckgekehrt. login_username Kennung : -login_username_help Trage hier Deine Krawall-Benutzerkennung ein (zu erhalten unter www.krawall.de). +login_username_help Trage hier Deine Benutzerkennung ein. login_storepw_text Passw\xF6rter speichern : login_storepw_help Bestimmt, was mit einmal eingegebenen Passw\xF6rtern geschiet Modified: armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-21 10:34:14 UTC (rev 7558) +++ armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-21 10:36:51 UTC (rev 7559) @@ -2445,13 +2445,13 @@ #login texts login_password_title Password -login_password_help Enter your Krawall-Password here. If you don't have one yet, get it at www.krawall.de (only available for players in Germany and neighbouring countries.). Pressing Enter here will log you in. +login_password_help Enter your login password here. Pressing Enter here will log you in. login_cancel Cancel Login login_cancel_help This will abort the login procedure. login_username Username -login_username_help Enter your Krawall-Username here. If you don't have one yet, get it at www.krawall.de (only available for players in Germany and neighbouring countries.) +login_username_help Enter your login username here. login_storepw_text Store Passwords: login_storepw_help Determines the password security policy. @@ -2472,6 +2472,34 @@ login_request_namechange Name changed. Login required. login_request_master Master server requires Login. +login_message \1 has been logged in by the power of authority \2.\n +logout_message \1 has been logged out of authority \2.\n + +chatcommand_requires_player \1 requires a player username as additional paramenter. + +authentication_required_help Controls how authentication influences your right to play. If set to 0, authentication has no influence. If set to 2, you are always required to authenticate to play. If set to 1, you need to be authenticated if only one other player is already authenticated. + +pickup_teamleader You need to be logged in as team leader or admin to use the /pickup or /putdown command.\n +pickup_authorized \1 is already authorized and does not need to be picked up.\n +pickup_putdown_unauthorized You did not pick up \1, you have no right to put him down. + +md5_password_admin_help Adds an admin account over the md5-hash based login system. +md5_password_admin_syntax Usage: MD5_PASSWORD_ADMIN <user name> <password>\n + +md5_password_user_help Adds an user account over the md5-hash based login system. +md5_password_user_syntax Usage: MD5_PASSWORD_USER <user name> <password>\n + +md5_password_team_help Adds an account over the md5-hash based login system for an entire team (team tags are compared). +md5_password_team_syntax Usage: MD5_PASSWORD_TEAM <team tag> <password>\n + +md5_password_teamleader_help Adds an account over the md5-hash based login system for a team leader. Team leaders can pick up players into the game. +md5_password_teamleader_syntax Usage: MD5_PASSWORD_TEAMLEADER <user name> <password>\n + +md5_password_remove_help Removes an MD5 password account. +md5_password_remove_syntax Usage: MD5_PASSWORD_REMOVE <user name/team tag>\n +md5_password_removed User name/team tag \1 removed.\n +md5_password_remove_notfound User name/team tag \1 to remove not found.\n + # items that should not be translated include english_base_notranslate.txt Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-21 10:34:14 UTC (rev 7558) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-21 10:36:51 UTC (rev 7559) @@ -282,9 +282,8 @@ // password storage; tString password; - eMenuItemPassword pw(&login, password); - uMenuItemString us(&login, "$login_username","$login_username_help", p->name); + uMenuItemString us(&login, "$login_username","$login_username_help", username); uMenuItemSelection<int> storepw(&login, "$login_storepw_text", @@ -313,7 +312,7 @@ // return username/scrambled password if (S_login) { - username = p->name; + // username = p->name; nKrawall::ScramblePassword(password, scrambled); // clear the PW from memory @@ -322,7 +321,7 @@ if (se_PasswordStorageMode >= 0) { - storage->username = p->name; + storage->username = username; memcpy(storage->password, scrambled, sizeof(nKrawall::nScrambledPassword)); storage->save = (se_PasswordStorageMode > 0); } @@ -333,14 +332,56 @@ S_login = NULL; } +#ifdef DEDICATED +static void se_AdminLogin( ePlayerNetID * p ) +{ + p->beLoggedIn(); + p->setAccessLevel(1); + sn_ConsoleOut("You have been logged in!\n",p->Owner()); + tString serverLoginMessage; + serverLoginMessage << "Remote admin login for user \"" << p->GetUserName() << "\" accepted.\n"; + sn_ConsoleOut(serverLoginMessage, 0); +} +#endif +#ifdef KRAWALL_SERVER +static int se_authenticationRequiredToPlay = 0; +static tSettingItem< int > se_authenticationRequiredToPlayConf( "AUTHENTICATION_REQUIRED", se_authenticationRequiredToPlay ); +bool ePlayerNetID::AuthenticationRequiredToPlay() +{ + // strict settings + if ( se_authenticationRequiredToPlay >= 2 ) + { + return true; + } + if ( se_authenticationRequiredToPlay == 0 ) + { + return false; + } + + // AUTHENTICATION_REQUIRED 1 means that as soon as a single player is authenticated, it is required + for ( int i = se_PlayerNetIDs.Len()-1; i>=0; --i ) + { + ePlayerNetID* player = se_PlayerNetIDs(i); + if ( player->auth && player->IsHuman() ) + { + return true; + } + } + + return false; +} + static void ResultCallback(const tString& usernameUnfiltered, const tString& origUsername, + const tString& authority_, int user, bool success) { int i; + tString authority = authority_; + // filter the user name tString username; ePlayerNetID::FilterName( usernameUnfiltered, username ); @@ -351,65 +392,77 @@ // stored in the incoming network stream has an unknown salt value. ) static char const * section = "AUTH"; tRecorder::Playback( section, success ); + tRecorder::Playback( section, authority ); tRecorder::Record( section, success ); + tRecorder::Record( section, authority ); - if (success) + ePlayerNetID * player = NULL; + + // authenticate the user that logged in and change his name + for (i = se_PlayerNetIDs.Len()-1; i>=0 && !player; i--) { - bool found = false; - - // authenticate the user that logged in and change his name - for (i = se_PlayerNetIDs.Len()-1; i>=0 && !found; i--) + ePlayerNetID *p = se_PlayerNetIDs(i); + if (p->Owner() == user && p->GetUserName() == origUsername) { - ePlayerNetID *p = se_PlayerNetIDs(i); - if (p->Owner() == user && p->GetUserName() == origUsername) + player = p; + if ( username != origUsername ) { - p->SetUserName(username); - // right now, user name and player name should match. Take care of that. - // the next line is scheduled to be removed for real authentication. - p->SetName(username); - p->Auth(); - found = true; + player->SetUserName( username ); } } + } - // if the first step was not successful, - // authenticate the player from that client with the new user name (maybe he renamed?) - for (i = se_PlayerNetIDs.Len()-1; i>=0 && !found; i--) + // if the first step was not successful, + // authenticate the player from that client with the new user name (maybe he renamed?) + for (i = se_PlayerNetIDs.Len()-1; i>=0 && !player; i--) + { + ePlayerNetID *p = se_PlayerNetIDs(i); + if (p->Owner() == user && p->GetUserName() == username) { - ePlayerNetID *p = se_PlayerNetIDs(i); - if (p->Owner() == user && p->GetUserName() == username) - { - p->Auth(); - found = true; - } + player = p; } + } - // last attempt: authenticate any player from that client. - //!TODO: think about whether we actually want that. - for (i = se_PlayerNetIDs.Len()-1; i>=0 && !found; i--) + // last attempt: authenticate any player from that client. + for (i = se_PlayerNetIDs.Len()-1; i>=0 && !player; i--) + { + ePlayerNetID *p = se_PlayerNetIDs(i); + if (p->Owner() == user) { - ePlayerNetID *p = se_PlayerNetIDs(i); - if (p->Owner() == user) - { - p->SetUserName( username ); - p->Auth(); - found = true; - } + player = p; + p->SetUserName( username ); } + } - // request other logins - for (i = se_PlayerNetIDs.Len()-1; i>=0; i--) + if (success && player) + { + player->IsAuth(); + player->SetUserName(username); + player->Auth(authority); + +#ifdef DEDICATED + if ( authority == "admin" ) { - ePlayerNetID *p = se_PlayerNetIDs(i); - p->IsAuth(); + se_AdminLogin( player ); } +#endif } else { - if (sn_GetNetState() == nSERVER && user != sn_myNetID ) - nAuthentification::RequestLogin(username, user, "$login_request_failed", true); + if ( sn_GetNetState() == nSERVER && user != sn_myNetID ) + { + tOutput out( "$login_request_failed" ); + out << '\n'; + sn_ConsoleOut( out, user ); + } + + + if ( player ) + { + } } } +#endif @@ -564,7 +617,9 @@ ePlayer::ePlayer(){ nAuthentification::SetUserPasswordCallback(&PasswordCallback); +#ifdef KRAWALL_SERVER nAuthentification::SetLoginResultCallback (&ResultCallback); +#endif nameTeamAfterMe = false; favoriteNumberOfPlayersPerTeam = 3; @@ -765,6 +820,104 @@ void handle_chat( nMessage& ); static nDescriptor chat_handler(200,handle_chat,"Chat"); +// checks whether text_to_search contains search_for_text +bool Contains( const tString & search_for_text, const tString & text_to_search ) { + int m = strlen(search_for_text); + int n = strlen(text_to_search); + int a, b; + for (b=0; b<=n-m; ++b) { + for (a=0; a<m && search_for_text[a] == text_to_search[a+b]; ++a) + ; + if (a>=m) + // a match has been found + return true; + } + return false; +} + +ePlayerNetID * CompareBufferToPlayerNames( const tString & current_buffer, int & num_matches ) { + num_matches = 0; + ePlayerNetID * match = 0; + + // run through all players and look for a match + for ( int a = se_PlayerNetIDs.Len()-1; a>=0; --a ) { + ePlayerNetID* toMessage = se_PlayerNetIDs(a); + + // exact match? + if ( current_buffer == toMessage->GetUserName() ) + { + num_matches = 1; + return toMessage; + } + + if ( Contains(current_buffer, toMessage->GetUserName())) { + match= toMessage; // Doesn't matter that this is wrote over everytime, when we only have one match it will be there. + num_matches+=1; + } + } + + // return result + return match; +} + +ePlayerNetID * se_FindPlayerByName( tString const & username, ePlayerNetID * requester = 0 ) +{ + int num_matches = 0; + + ePlayerNetID * ret = CompareBufferToPlayerNames( username, num_matches ); + + if ( ret && num_matches == 1 ) + { + return ret; + } + + // More than than one match for the current buffer. Complain about that. + else if (num_matches > 1) { + tOutput toSender( "$msg_toomanymatches", username ); + if ( requester ) + { + sn_ConsoleOut(toSender,requester->Owner() ); + } + else + { + con << toSender; + } + return NULL; + } + // 0 matches. The user can't spell. Complain about that, too. + else { + tOutput toSender( "$msg_nomatch", username ); + if ( requester ) + { + sn_ConsoleOut(toSender,requester->Owner() ); + } + else + { + con << toSender; + } + return NULL; + } +} + +#ifdef DEDICATED +#ifdef KRAWALL_SERVER +static ePlayerNetID * se_FindPlayerInChatCommand( ePlayerNetID * sender, char const * command, tString const & say ) +{ + tString params(""); + if (say.StrPos(" ") == -1) + { + sn_ConsoleOut( tOutput( "$chatcommand_requires_player", command ), sender->Owner() ); + } + else + { + params = say.SubStr(say.StrPos(" ") + 1); + } + + return se_FindPlayerByName( params, sender ); +} +#endif +#endif + // chat message from server to client void handle_chat_client( nMessage & ); static nDescriptor chat_handler_client(203,handle_chat_client,"Chat Client"); @@ -1042,46 +1195,6 @@ } } -// checks whether text_to_search contains search_for_text -bool Contains( const tString & search_for_text, const tString & text_to_search ) { - int m = strlen(search_for_text); - int n = strlen(text_to_search); - int a, b; - for (b=0; b<=n-m; ++b) { - for (a=0; a<m && search_for_text[a] == text_to_search[a+b]; ++a) - ; - if (a>=m) - // a match has been found - return true; - } - return false; -} - -ePlayerNetID * CompareBufferToPlayerNames( const tString & current_buffer, int & num_matches ) { - num_matches = 0; - ePlayerNetID * match = 0; - - // run through all players and look for a match - for ( int a = se_PlayerNetIDs.Len()-1; a>=0; --a ) { - ePlayerNetID* toMessage = se_PlayerNetIDs(a); - - // exact match? - if ( current_buffer == toMessage->GetUserName() ) - { - num_matches = 1; - return toMessage; - } - - if ( Contains(current_buffer, toMessage->GetUserName())) { - match= toMessage; // Doesn't matter that this is wrote over everytime, when we only have one match it will be there. - num_matches+=1; - } - } - - // return result - return match; -} - // returns a player ( not THE player, there may be more ) belonging to a user ID /* static ePlayerNetID * se_GetPlayerFromUserID( int uid ) @@ -1171,10 +1284,17 @@ if (say.StartsWith("/login")) { tString params(""); if (say.StrPos(" ") == -1) + { +#ifndef KRAWALL_SERVER return; +#endif + } else + { params = say.SubStr(say.StrPos(" ") + 1); + } +#ifndef KRAWALL_SERVER // the password is not stored in the recording, hence we have to store the // result of the password test bool accept = true; @@ -1186,12 +1306,7 @@ //change this later to read from a password file or something... //or integrate it with auth if we ever get that done... if ( accept ) { - p->beLoggedIn(); - p->setAccessLevel(1); - sn_ConsoleOut("You have been logged in!\n",p->Owner()); - tString serverLoginMessage; - serverLoginMessage << "Remote admin login for user \"" << p->GetUserName() << "\" accepted.\n"; - sn_ConsoleOut(serverLoginMessage, 0); + se_AdminLogin( p ); } else { @@ -1201,6 +1316,19 @@ failedLogin << "\" using password \"" << params << "\" rejected.\n"; sn_ConsoleOut(failedLogin, 0); } +#else + if ( sn_GetNetState() == nSERVER && p->Owner() != sn_myNetID ) + { +#ifndef HAVE_LIBZTHREAD + if ( params.Len() > 1 ) + { + sn_ConsoleOut( "Sorry, distributed authentication not supported on this server.", p->Owner() ); + return; + } +#endif + nAuthentification::RequestLogin(params,p->GetUserName(), p->Owner(), "$login_request_first"); + } +#endif } else if (say.StartsWith("/logout")) { if ( p->isLoggedIn() ) @@ -1209,7 +1337,61 @@ } p->beNotLoggedIn(); p->setAccessLevel(0); + +#ifdef KRAWALL_SERVER + // revoke the other kind of authentication as well + if ( se_authenticationRequiredToPlay < 2 && p->IsAuth() ) + { + p->DeAuth(); + } +#endif } +#ifdef KRAWALL_SERVER + else if (say.StartsWith("/pickup")) + { + tString const & auth = p->GetAuthority(); + if ( !auth.StartsWith( "teamleader" ) && auth != "admin" ) + { + sn_ConsoleOut( "$pickup_teamleader", p->Owner() ); + return; + } + + ePlayerNetID * pickup = se_FindPlayerInChatCommand( p, "/pickup", say ); + if ( pickup ) + { + if ( pickup->IsAuth() ) + { + pickup->Auth( tString( "pickup_" ) + auth ); + } + else + { + sn_ConsoleOut( tOutput( "$pickup_authorized", pickup->GetUserName() ), p->Owner() ); + } + } + } + else if (say.StartsWith("/putdown")) + { + tString const & auth = p->GetAuthority(); + if ( !auth.StartsWith( "teamleader" ) && auth != "admin" ) + { + sn_ConsoleOut( "$pickup_teamleader", p->Owner() ); + return; + } + + ePlayerNetID * pickup = se_FindPlayerInChatCommand( p, "/pickup", say ); + if ( pickup ) + { + if ( pickup->GetAuthority() == tString( "pickup_" ) + auth ) + { + pickup->DeAuth(); + } + else + { + sn_ConsoleOut( tOutput( "$pickup_putdown_unauthorized", pickup->GetUserName() ), p->Owner() ); + } + } + } +#endif else if (say.StartsWith("/admin")) { if (!p->isLoggedIn()) { @@ -1497,11 +1679,10 @@ buffer_name = ePlayerNetID::FilterName(buffer_name); // Check for match - int num_matches=-1; - ePlayerNetID * receiver = CompareBufferToPlayerNames(buffer_name, num_matches); + ePlayerNetID * receiver = se_FindPlayerByName(buffer_name); // One match, send it. - if (num_matches == 1) { + if ( receiver ) { // extract rest of message: it is the true message to send tString msg_core; while (current_place < msg.Len()-1) { @@ -1528,22 +1709,6 @@ return; } - // More than than one match for the current buffer. Complain about that. - else if (num_matches > 1) { - tOutput toSender; - toSender.SetTemplateParameter(1, buffer_name); - toSender << "$msg_toomanymatches"; - sn_ConsoleOut(toSender,p->Owner()); - return; - } - // 0 matches. The user can't spell. Complain about that, too. - else { - tOutput toSender; - toSender.SetTemplateParameter(1, buffer_name); - toSender << "$msg_nomatch"; - sn_ConsoleOut(toSender, p->Owner()); - return; - } } #ifdef DEDICATED else if (command == "/players") { @@ -2359,17 +2524,31 @@ return true; } -void ePlayerNetID::Auth(){ - auth = true; - GetScoreFromDisconnectedCopy(); +void ePlayerNetID::Auth( tString const & authority ){ + if ( !auth && IsHuman() ) + { + sn_ConsoleOut( tOutput( "$login_message", GetUserName(), authority ) ); + } + if ( !auth ) + { + auth = true; + authority_ = authority; + GetScoreFromDisconnectedCopy(); + } } -bool ePlayerNetID::IsAuth() const{ -#ifdef KRAWALL_SERVER - if (!auth && sn_GetNetState() == nSERVER && Owner() != sn_myNetID ) - nAuthentification::RequestLogin(GetUserName(), Owner(), "$login_request_first"); -#endif +void ePlayerNetID::DeAuth(){ + if ( auth ) + { + sn_ConsoleOut( tOutput( "$logout_message", GetUserName(), authority_ ) ); + } + auth = false; + authority_ = ""; +} + +bool ePlayerNetID::IsAuth() const +{ return auth; } @@ -3575,7 +3754,7 @@ // find a copy for(i=se_PlayerNetIDs.Len()-1;i>=0;i--){ ePlayerNetID *pni=se_PlayerNetIDs(i); - if (pni->disconnected && pni->GetName() == GetName() && pni->Owner() == 0) + if (pni->disconnected && pni->GetName() == GetName() && pni->GetAuthority() == GetAuthority() && pni->Owner() == 0) { #ifdef DEBUG con << GetName() << " reconnected.\n"; @@ -4495,15 +4674,6 @@ mess.SetTemplateParameter(2, oldprintname); if (oldUserName.Len()<=1 && GetUserName().Len()>=1){ - -#ifdef KRAWALL_SERVER - if (sn_GetNetState() == nSERVER && Owner() != sn_myNetID ) - { - auth = false; - nAuthentification::RequestLogin(GetUserName(), Owner(), "$login_request_first"); - } -#endif - // print spectating join message (regular join messages are handled by eTeam) if ( IsSpectating() || !se_assignTeamAutomatically ) { @@ -4525,9 +4695,7 @@ #ifdef KRAWALL_SERVER if (sn_GetNetState() == nSERVER && Owner() != sn_myNetID ) { - nAuthentification::RequestLogin(GetUserName(), Owner(), "$login_request_namechange"); - auth = false; - userName_ = oldUserName; // restore the old name until the new one is authenticated + userName_ = oldUserName; // restore the old username } #endif mess << "$player_renamed"; Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h 2008-01-21 10:34:14 UTC (rev 7558) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h 2008-01-21 10:36:51 UTC (rev 7559) @@ -231,7 +231,8 @@ void ClearObject(); void Greet(); - void Auth(); // make the authentification valid + void Auth( tString const & authority ); // make the authentification valid + void DeAuth(); // make the authentification invalid bool IsAuth() const; // is the authentification valid? bool IsActive() const { return !disconnected; } @@ -271,6 +272,10 @@ static void Update(); // creates ePlayerNetIDs for new players // and destroys those of players that have left +#ifdef KRAWALL_SERVER + static bool AuthenticationRequiredToPlay(); // is authentication required to play on this server? +#endif + static bool WaitToLeaveChat(); //!< waits for players to leave chat state. Returns true if the caller should wait to proceed with whatever he wants to do. static void RemoveChatbots(); //!< removes chatbots and idling players from the game @@ -304,6 +309,7 @@ tColoredString coloredName_; //! this player's name, cleared by the server. Use this for onscreen screen display. tString name_; //! this player's name without colors. tString userName_; //! this player's name, cleared for system logs. Use for writing to files or comparing with admin input. + tString authority_; //!< the authority the player is authenticated with REAL wait_; //! time in seconds WaitToLeaveChat() will wait for this player @@ -324,6 +330,9 @@ inline ePlayerNetID const & GetColoredName( tColoredString & coloredName ) const; //!< Gets this player's name, cleared by the server. Use this for onscreen screen display. inline tString const & GetName( void ) const; //!< Gets this player's name without colors. inline ePlayerNetID const & GetName( tString & name ) const; //!< Gets this player's name without colors. + + inline tString const & GetAuthority( void ) const; //!< Gets this player's authority. + inline ePlayerNetID const & GetAuthority( tString & authority ) const; //!< Gets this player's authority. inline tString const & GetUserName( void ) const; //!< Gets this player's name, cleared for system logs. Use for writing to files or comparing with admin input. inline ePlayerNetID const & GetUserName( tString & userName ) const; //!< Gets this player's name, cleared for system logs. Use for writing to files or comparing with admin input. @@ -506,6 +515,38 @@ // ****************************************************************************************** // * +// * GetAuthority +// * +// ****************************************************************************************** +//! +//! @return this player's authority. +//! +// ****************************************************************************************** + +tString const & ePlayerNetID::GetAuthority( void ) const +{ + return this->authority_; +} + +// ****************************************************************************************** +// * +// * GetAuthority +// * +// ****************************************************************************************** +//! +//! @param authority this player's authority to fill +//! @return A reference to this to allow chaining +//! +// ****************************************************************************************** + +ePlayerNetID const & ePlayerNetID::GetAuthority( tString & authority ) const +{ + authority = this->authority_; + return *this; +} + +// ****************************************************************************************** +// * // * GetUserName // * // ****************************************************************************************** Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp 2008-01-21 10:34:14 UTC (rev 7558) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp 2008-01-21 10:36:51 UTC (rev 7559) @@ -37,6 +37,13 @@ #include <string> #include <string.h> +#ifdef HAVE_LIBZTHREAD +#include <zthread/Thread.h> +#include <zthread/LockedQueue.h> +//#include <zthread/ClassLockable.h> +#include <zthread/FastMutex.h> +#endif + static nAuthentification::UserPasswordCallback* S_UserPasswordCallback = NULL; static nAuthentification::LoginResultCallback* S_LoginResultCallback = NULL; @@ -57,6 +64,7 @@ static bool S_UserAuthActive [MAXCLIENTS+2]; static tString S_UserAuthName [MAXCLIENTS+2]; +static tString S_UserAuthURL [MAXCLIENTS+2]; #ifdef KRAWALL_SERVER static nKrawall::nSalt S_UserAuthSalt [MAXCLIENTS+2]; @@ -79,7 +87,7 @@ // on the server: request user authentification from login slot -void nAuthentification::RequestLogin(const tString& username, int user, const tOutput& message, bool failureOnLastTry) +void nAuthentification::RequestLogin(const tString & url, const tString& username, int user, const tOutput& message, bool failureOnLastTry) { #ifdef KRAWALL_SERVER @@ -96,6 +104,7 @@ S_UserAuthActive[user] = true; S_UserAuthStarted[user] = tSysTimeFloat(); S_UserAuthName[user] = username; + S_UserAuthURL[user] = url; // send the salt value and the username to the nMessage *m = tNEW(nMessage)(nPasswordRequest); @@ -163,7 +172,86 @@ st_ToDo(&FinishHandlePasswordRequest); } +#ifdef KRAWALL_SERVER +struct nPasswordCheckResult +{ + tString username; // username as sent from client + tString oldUserName; // user name the client initiated authentication with + tString authority; // authority + int userID; // user ID + bool success; // was the operation successful? + void finish() + { + if (S_LoginResultCallback) + (*S_LoginResultCallback)(username, + oldUserName, + authority, + userID, + success ); + } +}; + + +class nPasswordCheck : public nPasswordCheckResult +#ifdef HAVE_LIBZTHREAD + , public ZThread::Runnable +#endif +{ + nKrawall::nScrambledPassword hash; // hash as sent from client + nKrawall::nSalt salt; // salt the hash was scrambled with + tString url; // authority url + +#ifdef HAVE_LIBZTHREAD + static ZThread::LockedQueue< nPasswordCheckResult, ZThread::FastMutex > pending; + + static void FinishAll() + { + // finish all pending tasks + while( pending.size() > 0 ) + { + nPasswordCheckResult next = pending.next(); + next.finish(); + } + } +#endif + +public: + void run() + { + success = nKrawall::CheckScrambledPassword(url,username, hash, salt, authority); + +#ifdef HAVE_LIBZTHREAD + // add result to queue + pending.add( *this ); + + // schedule call to FinishAll + st_ToDo( FinishAll ); +#endif + } + + nPasswordCheck( nMessage & m ) + { + success = false; + + // read password and username from remote + nKrawall::ReadScrambledPassword(m, hash); + m >> username; + username = tColoredString::RemoveColors( username ); + userID = m.SenderID(); + + // fill other members from static data + url = S_UserAuthURL[userID]; + oldUserName = S_UserAuthName[userID]; + memcpy( &salt, &S_UserAuthSalt[userID], sizeof(nKrawall::nSalt) ); + } +}; + +#ifdef HAVE_LIBZTHREAD +ZThread::LockedQueue< nPasswordCheckResult, ZThread::FastMutex > nPasswordCheck::pending; +#endif +#endif + void nAuthentification::HandlePasswordAnswer(nMessage& m) { #ifdef KRAWALL_SERVER @@ -173,23 +261,14 @@ S_UserAuthActive[m.SenderID()] = false; - // read password and username from remote - nScrambledPassword scrambledRemote; - tString username; - ReadScrambledPassword(m, scrambledRemote); - m >> username; - - // get the password from the user database - nScrambledPassword temp, scrambledDatabase; - GetScrambledPassword(username, temp); - ScrambleWithSalt(temp, S_UserAuthSalt[m.SenderID()], scrambledDatabase); - - if (S_LoginResultCallback) - (*S_LoginResultCallback)(username, - S_UserAuthName[m.SenderID()], - m.SenderID(), - ArePasswordsEqual(scrambledRemote, scrambledDatabase)); +#ifdef HAVE_LIBZTHREAD + ZThread::Thread t( new nPasswordCheck( m ) ); +#else + nPasswordCheck c(m); + c.run(); + c.finish(); #endif +#endif } Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.h =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.h 2008-01-21 10:34:14 UTC (rev 7558) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.h 2008-01-21 10:36:51 UTC (rev 7559) @@ -46,6 +46,7 @@ // lookup typedef void LoginResultCallback(const tString& username, const tString& origUsername, + const tString& authority, int user, bool success); @@ -58,7 +59,7 @@ static void HandlePasswordAnswer (nMessage& m); // on the server: request user authentification from login slot - static void RequestLogin(const tString& username, int user, const tOutput& message, bool failureOnLastTry = false); + static void RequestLogin(const tString& url, const tString& username, int user, const tOutput& message, bool failureOnLastTry = false); }; #endif Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.cpp 2008-01-21 10:34:14 UTC (rev 7558) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.cpp 2008-01-21 10:36:51 UTC (rev 7559) @@ -46,6 +46,7 @@ #include <string> #include <string.h> +#ifdef KRAWALL_SERVER_LEAGUE bool nKrawall::MayRequirePassword(tString& adress, unsigned int port) { return true; @@ -59,6 +60,7 @@ return false; } +#endif bool nKrawall::ArePasswordsEqual(const nScrambledPassword& a, const nScrambledPassword& b) @@ -70,7 +72,21 @@ return true; } +// encode scrambled passwords and salts as hexcode strings +tString nKrawall::EncodeScrambledPassword( nScrambledPassword const & scrambled ) +{ + std::ostringstream s; + s << std::hex; + for( int i = 0; i < 16; ++i ) + { + unsigned int val = scrambled[i]; + // don't want to rely on filling type iomanip things, never learned how to use them reliably + s << ( val & 0xF0 ) / 0x10; + s << ( val & 0x0F ); + } + return tString( s.str().c_str() ); +}; // network read/write operations of these data types void nKrawall::WriteScrambledPassword(const nScrambledPassword& scrambled, @@ -149,6 +165,18 @@ #ifdef KRAWALL_SERVER +// get a random salt value +void nKrawall::RandomSalt(nSalt& salt) +{ + // oh dear. getting a random salt value with this method is EVIL... + tRandomizer & randomizer = tRandomizer::GetInstance(); + for (int i=15; i>=0; i--) + salt[i] = randomizer.Get( 256 ); + // salt[i] = (int)(256.0 * rand() / (RAND_MAX + 1.0)); +} + +#ifdef KRAWALL_SERVER_LEAGUE + // called on the master server when the league message is received void nKrawall::ReceiveLeagueMessage(const tString& message) { @@ -200,17 +228,6 @@ -// get a random salt value -void nKrawall::RandomSalt(nSalt& salt) -{ - // oh dear. getting a random salt value with this method is EVIL... - tRandomizer & randomizer = tRandomizer::GetInstance(); - for (int i=15; i>=0; i--) - salt[i] = randomizer.Get( 256 ); - // salt[i] = (int)(256.0 * rand() / (RAND_MAX + 1.0)); -} - - // called ON THE SERVER when victim drives against killer's wall void nKrawall::ServerFrag(const tString &killer, const tString& victim) { @@ -465,5 +482,6 @@ } #endif +#endif Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.h =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.h 2008-01-21 10:34:14 UTC (rev 7558) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.h 2008-01-21 10:36:51 UTC (rev 7559) @@ -57,6 +57,9 @@ typedef md5_byte_t nScrambledPassword[16]; // (freely changable) typedef nScrambledPassword nSalt; // (freely changable) + // encode scrambled passwords and salts as hexcode strings + static tString EncodeScrambledPassword( nScrambledPassword const & scrambled ); + // network read/write operations of these data types static void WriteScrambledPassword(const nScrambledPassword& scrambled, nMessage &m); @@ -103,14 +106,17 @@ // get a random salt value static void RandomSalt(nSalt& salt); + // check whether username's password, when run through ScrambleWithSalt( ScramblePassword(password), salt ), equals scrambledRemote. + static bool CheckScrambledPassword(const tString& url, + const tString& username, + nScrambledPassword const & hash, + nSalt const & salt, + tString & authority); + +#ifdef KRAWALL_SERVER_LEAGUE // secret key to encrypt server->master server league transfer static const nScrambledPassword& SecretLeagueKey(); - - // fetch the scrambled password of username from the users database - static void GetScrambledPassword(const tString& username, - nScrambledPassword &scrambled); - // called on the servers to create a league message static void SendLeagueMessage(const tString& message = *reinterpret_cast<tString *>(0)); @@ -142,7 +148,6 @@ // players[numPlayers-1], the first death in players[0] static void MasterRoundEnd(const tString* players, int numPlayers); - // Adress checking functions // first validity check for the league messages @@ -151,12 +156,12 @@ // check if a user is from germany (so the master server will require // a password check) static bool RequireMasterLogin(tString& adress, unsigned int port); -#endif // only servers acknowledged by this funktion are from Krawall and // are allowed to request logins static bool MayRequirePassword(tString& adress, unsigned int port); - +#endif +#endif }; #endif Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp 2008-01-21 10:34:14 UTC (rev 7558) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp 2008-01-21 10:36:51 UTC (rev 7559) @@ -35,13 +35,250 @@ #include "nKrawall.h" #include "tString.h" #include "tConsole.h" +#include "tConfiguration.h" #include "tArray.h" #include <string> +#include <vector> +#include <map> - #ifdef KRAWALL_SERVER +#include <libxml/nanohttp.h> + +// crude login structure with not too many feathres +struct nLogin +{ + tString authority_; + nKrawall::nScrambledPassword scrambledPassword_; + + nLogin( char const * authority, tString const & password ) + : authority_( authority ) + { + // scramble the password before storing it (in case an evil attacker can read our memory, + // but not the configuration file where they are stored in plain text :) ) + nKrawall::ScramblePassword( password, scrambledPassword_ ); + } + + nLogin() + { + } +}; + +typedef std::map< tString, nLogin > nLoginMap; + +// database of exact logins +static nLoginMap sn_exactLogins; + +// database of inprecise logins +static nLoginMap sn_partialLogins; + +// add an admin account +static void sn_ReadAdminPassword( std::istream & s ) +{ + tString username, password; + s >> username; + if ( !s.good() ) + { + con << tOutput( "$md5_password_admin_syntax" ); + return; + } + tConfItemBase::EatWhitespace(s); + password.ReadLine(s); + + sn_exactLogins[ username ] = nLogin( "admin", password ); +} + +static tConfItemFunc sn_kpa( "MD5_PASSWORD_ADMIN", sn_ReadAdminPassword ); + +// add an admin account +static void sn_ReadUserPassword( std::istream & s ) +{ + tString username, password; + s >> username; + if ( !s.good() ) + { + con << tOutput( "$md5_password_user_syntax" ); + return; + } + tConfItemBase::EatWhitespace(s); + password.ReadLine(s); + + sn_exactLogins[ username ] = nLogin( "user", password ); +} + +static tConfItemFunc sn_kpu( "MD5_PASSWORD_USER", sn_ReadUserPassword ); + +// add team account +static void sn_ReadTeamPassword( std::istream & s ) +{ + tString username, password; + s >> username; + if ( !s.good() ) + { + con << tOutput( "$md5_password_team_syntax" ); + return; + } + tConfItemBase::EatWhitespace(s); + password.ReadLine(s); + + sn_partialLogins[ username ] = nLogin( tString("team_") + username, password ); +} + +static tConfItemFunc sn_kta( "MD5_PASSWORD_TEAM", sn_ReadTeamPassword ); + +// add teamleader leader account +static void sn_ReadTeamleaderPassword( std::istream & s ) +{ + tString username, password; + s >> username; + if ( !s.good() ) + { + con << tOutput( "$md5_password_teamleader_syntax" ); + return; + } + tConfItemBase::EatWhitespace(s); + password.ReadLine(s); + + sn_exactLogins[ username ] = nLogin( tString("teamleader_") + username, password ); +} + +static tConfItemFunc sn_ktla( "MD5_PASSWORD_TEAMLEADER", sn_ReadTeamleaderPassword ); + +// finds a login element as iterator +nLoginMap::iterator sn_FindLoginIterator( tString const & username, nLoginMap * & map, bool exact = false ) +{ + // find exact login + map = &sn_exactLogins; + nLoginMap::iterator found = sn_exactLogins.find( username ); + if ( found != sn_exactLogins.end() ) + { + return found; + } + + map = &sn_partialLogins; + for( int i = username.Len(); i >= 1; --i ) + { + tString partial = username.SubStr( 0, i ); + nLoginMap::iterator found = map->find( partial ); + if ( found != map->end() ) + { + return found; + } + + if ( exact ) + { + return map->end(); + } + } + + return map->end(); +} + +// finds login pointer +nLogin const * sn_FindLogin( tString const & username ) +{ + // find login + nLoginMap * map; + nLoginMap::iterator found = sn_FindLoginIterator( username, map ); + if ( found != map->end() ) + { + return &found->second; + } + + return 0; +} + +// remove an account +static void sn_ReadPasswordRemove( std::istream & s ) +{ + tString username; + s >> username; + nLoginMap * map; + nLoginMap::iterator found = sn_FindLoginIterator( username, map, true ); + if ( found != map->end() ) + { + map->erase( found ); + con << tOutput( "$md5_password_removed", username ); + } + else + { + con << tOutput( "$md5_password_remove_notfound", username ); + } +} + +static tConfItemFunc sn_kpr( "MD5_PASSWORD_REMOVE", sn_ReadPasswordRemove ); + +// fetch the scrambled password of username from the users database +bool nKrawall::CheckScrambledPassword(const tString& url, + const tString& username, + nScrambledPassword const & scrambledRemote, + nSalt const & salt, + tString & authority ) +{ + // local users + if ( url.Len() <= 1 ) + { + // fetch login data + nLogin const * login = sn_FindLogin( username ); + if ( !login ) + { + return false; + } + + // store relevant authority + authority = login->authority_; + + // compare passwords + nScrambledPassword scrambledCorrect; + ScrambleWithSalt( login->scrambledPassword_, salt, scrambledCorrect ); + return ArePasswordsEqual( scrambledRemote, scrambledCorrect ); + } + else + { + // remote users: build md5 query URL + authority = url; + std::ostringstream fullURL; + fullURL << "http://" << url << "/armaauth/md5"; + // fullURL << "?query=password"; + // fullURL << "http://authentication.armagetronad.net/hashauth.php"; + fullURL << "?user=" << username; + fullURL << "&salt=" << EncodeScrambledPassword( salt ); + fullURL << "&hash=" << EncodeScrambledPassword( scrambledRemote ); + + // fetch the URL's content (TODO: unblock it) + void *ctxt = NULL; + int rc; + + con << "Fetching authentication URL " << fullURL.str() << "\n"; + + ctxt = xmlNanoHTTPOpen(fullURL.str().c_str(), NULL); + if (ctxt == NULL) { + con << "ERROR: ctxt is NULL\n"; + return false; + } + + if ( (rc = xmlNanoHTTPReturnCode(ctxt)) != 200 ) { + con << tOutput( rc == 404 ? "$resource_fetcherror_404" : "$resource_fetcherror", rc ); + return false; + } + + // read content + char buf[100]; + buf[0] = 0; + unsigned int len = xmlNanoHTTPRead( ctxt, &buf, sizeof(buf) ); + xmlNanoHTTPClose(ctxt); + if ( len >= sizeof(buf) ) + len = sizeof(buf) - 1; + buf[len] = 0; + con << "Answer: " << buf << "\n"; + + return ( strncmp( "PASSWORD_OK", buf, sizeof(buf)-1 ) == 0 ); + } +} + + +#ifdef KRAWALL_SERVER_LEAGUE // TODO: REALLY change this!! static nKrawall::nScrambledPassword key = { @@ -55,18 +292,6 @@ return key; } -// fetch the scrambled password of username from the users database -void nKrawall::GetScrambledPassword(const tString& username, - nScrambledPassword &scrambled) -{ - // TODO: REAL password retrieval - const char *password = username; - - // this part may stay - ScramblePassword(tString(password), scrambled); -} - - // called ON THE MASTER when victim drives against killer's wall void nKrawall::MasterFrag(const tString &killer, const tString& victim) { @@ -111,3 +336,4 @@ } #endif +#endif Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nServerInfo.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nServerInfo.cpp 2008-01-21 10:34:14 UTC (rev 7558) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nServerInfo.cpp 2008-01-21 10:36:51 UTC (rev 7559) @@ -121,7 +121,7 @@ } // authentification stuff -#ifdef KRAWALL_SERVER +#ifdef KRAWALL_SERVER_LEAGUE void ResultCallback(const tString& username, const tString& origUsername, int user, bool success) @@ -134,7 +134,7 @@ else nAuthentification::RequestLogin(username, user, tOutput("$login_request_failed"), true); } -#endif // KRAWALL_SERVER +#endif // KRAWALL_SERVER_LEAGUE @@ -1080,7 +1080,7 @@ con << "Giving server info to user " << m.SenderID() << "\n"; sn_Requested[m.SenderID()] = true; -#ifdef KRAWALL_SERVER +#ifdef KRAWALL_SERVER_LEAGUE // one moment! check if we need authentification tString adr; unsigned int port = sn_GetPort(m.SenderID()); Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tMemManager.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tMemManager.cpp 2008-01-21 10:34:14 UTC (rev 7558) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tMemManager.cpp 2008-01-21 10:36:51 UTC (rev 7559) @@ -86,6 +86,35 @@ static bool reported=false; +#ifdef HAVE_LIBZTHREAD +#include <zthread/FastRecursiveMutex.h> + +static ZThread::FastRecursiveMutex st_mutex; +#else +class tMockMutex +{ +public: + void acquire(){}; + void release(){}; +}; + +static tMockMutex st_mutex; +#endif + +class tBottleNeck +{ +public: + tBottleNeck() + { + st_mutex.acquire(); + } + + ~tBottleNeck() + { + st_mutex.release(); + } +}; + // replacement for wmemset function #ifndef HAVE_WMEMSET static inline wchar_t *wmemset(wchar_t *wcs, wchar_t wc, size_t n) throw() @@ -1030,8 +1059,12 @@ #endif void *ret; if (inited && s < (MAX_SIZE << 2)) + { + tBottleNeck neck; ret=memman[((s+3)>>2)].Alloc(); - else{ + } + else + { ret=tMemManager::AllocDefault(s); } #ifdef MEM_DEB @@ -1049,6 +1082,7 @@ } void tMemMan::DisposeButKeep(void *p){ + tBottleNeck neck; #ifndef DONTUSEMEMMANAGER #ifdef MEM_DEB #ifdef WIN32 @@ -1067,6 +1101,7 @@ } void tMemMan::Dispose(void *p){ + tBottleNeck neck; #ifndef DONTUSEMEMMANAGER #ifdef MEM_DEB #ifdef WIN32 @@ -1090,6 +1125,7 @@ void tMemMan::Check(){ if (!inited) return; + #ifdef WIN32 EnterCriticalSection(&mutex); #endif @@ -1337,6 +1373,7 @@ #endif void tMemMan::Profile(){ + tBottleNeck neck; #ifdef PROFILER int sort_checksum[MAXCHECKSUM]; Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tToDo.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tToDo.cpp 2008-01-21 10:34:14 UTC (rev 7558) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tToDo.cpp 2008-01-21 10:36:51 UTC (rev 7559) @@ -28,16 +28,35 @@ #include "tToDo.h" #include "tArray.h" +#ifdef HAVE_LIBZTHREAD +#include <zthread/FastMutex.h> + +static ZThread::FastMutex st_mutex; +#else +class tMockMutex +{ +public: + void acquire(){}; + void release(){}; +}; + +static tMockMutex st_mutex; +#endif + tArray<tTODO_FUNC *> tToDos; void st_ToDo(tTODO_FUNC *td){ // postpone something + st_mutex.acquire(); tToDos[tToDos.Len()]=td; + st_mutex.release(); } void st_DoToDo(){ // do the things that have been postponed + st_mutex.acquire(); while (tToDos.Len()){ tTODO_FUNC *td=tToDos[tToDos.Len()-1]; tToDos.SetLen(tToDos.Len()-1); (*td)(); } + st_mutex.release(); } Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gAIBase.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gAIBase.cpp 2008-01-21 10:34:14 UTC (rev 7558) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gAIBase.cpp 2008-01-21 10:36:51 UTC (rev 7559) @@ -1157,7 +1157,7 @@ NewObject(); // AI players don't need to log in - Auth(); + Auth( tString("ai") ); } void gAIPlayer::ConfigureAIs() // ai configuration menu Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gCycle.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gCycle.cpp 2008-01-21 10:34:14 UTC (rev 7558) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gCycle.cpp 2008-01-21 10:36:51 UTC (rev 7559) @@ -3081,7 +3081,7 @@ if (!Alive() || sn_GetNetState()==nCLIENT) return; -#ifdef KRAWALL_SERVER +#ifdef KRAWALL_SERVER_LEAGUE if ( hunter && Player() && !dynamic_cast<gAIPlayer*>(hunter) && !dynamic_cast<gAIPlayer*>(Player()) && Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gGame.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gGame.cpp 2008-01-21 10:34:14 UTC (rev 7558) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gGame.cpp 2008-01-21 10:36:51 UTC (rev 7559) @@ -1506,7 +1506,7 @@ #ifdef KRAWALL_SERVER // don't allow unknown players to play - if (!pni->IsAuth()) + if ( ePlayerNetID::AuthenticationRequiredToPlay() && !pni->IsAuth() ) continue; #endif @@ -3719,7 +3719,7 @@ // check if the win was legitimate: at least one enemy team needs to bo online if ( sg_EnemyExists( winner-1 ) ) { -#ifdef KRAWALL_SERVER +#ifdef KRAWALL_SERVER_LEAGUE // send the result to the master server if (!dynamic_cast<gAIPlayer*>(eTeam::teams(winner-1))) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <z-...@us...> - 2008-01-21 19:46:21
|
Revision: 7574 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7574&view=rev Author: z-man Date: 2008-01-21 11:46:06 -0800 (Mon, 21 Jan 2008) Log Message: ----------- Refactoring, clientside support for good md5 format (not yet final), better error messages for the user. Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.h armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.h armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/network/nNetwork.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/network/nNetwork.h Modified: armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-21 19:35:28 UTC (rev 7573) +++ armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-21 19:46:06 UTC (rev 7574) @@ -2474,7 +2474,16 @@ login_message \1 has been logged in by the power of authority \2.\n logout_message \1 has been logged out of authority \2.\n +login_failed_message 0xff7f7fLogin failed, reason: \1\n +# various reasons for logins to fail +login_error_aborted Login aborted. +login_error_invalidurl Authentication URL \1 invalid. +login_error_nouser User does not exist. +login_error_password Wrong password supplied. +login_error_unknown Unknown error \1 returned. +login_error_unexpected_answer Answer PASSWORD_OK expected from server, but got \1 instead. + chatcommand_requires_player \1 requires a player username as additional paramenter. authentication_required_help Controls how authentication influences your right to play. If set to 0, authentication has no influence. If set to 2, you are always required to authenticate to play. If set to 1, you need to be authenticated if only one other player is already authenticated. Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-21 19:35:28 UTC (rev 7573) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-21 19:46:06 UTC (rev 7574) @@ -73,7 +73,10 @@ class PasswordStorage { public: - tString username; + tString username; // name of the user the password belongs to + tString method; // method of scrambling + tString prefix; // scramble prefix + tString suffix; // scramble suffix nKrawall::nScrambledPassword password; bool save; @@ -130,7 +133,7 @@ for (i = S_passwords.Len()-1; i>=0; i--) { PasswordStorage &storage = S_passwords[i]; - if (storage.save) + if (storage.save && storage.suffix.Len() <= 1 && storage.prefix.Len() <= 1 ) { if (!first) s << "\nPASSWORD\t"; @@ -138,6 +141,7 @@ s << "1 "; nKrawall::WriteScrambledPassword(storage.password, s); + s << '\t' << storage.method; s << '\t' << storage.username; } } @@ -154,6 +158,7 @@ { PasswordStorage &storage = S_passwords[S_passwords.Len()]; nKrawall::ReadScrambledPassword(s, storage.password); + s >> storage.method; storage.username.ReadLine(s); storage.save = true; } @@ -216,13 +221,23 @@ "$password_storage_help", se_PasswordStorageMode); -static void PasswordCallback(tString& username, - const tString& message, - nKrawall::nScrambledPassword& scrambled, - bool failure) +static void PasswordCallback( nKrawall::nPasswordRequest const & request, + nKrawall::nPasswordAnswer & answer ) { int i; + tString& username = answer.username; + const tString& message = request.message; + nKrawall::nScrambledPassword& scrambled = answer.scrambled; + bool failure = request.failureOnLastTry; + + if ( request.method != "md5" && request.method != "bmd5" ) + { + con << "Unknown password scrambling method requested."; + answer.aborted = true; + return; + } + // find the player with the given username: ePlayer* p = NULL; for (i = MAX_PLAYERS-1; i>=0 && !p; i--) @@ -249,8 +264,15 @@ // try to find the username in the saved passwords: PasswordStorage *storage = NULL; for (i = S_passwords.Len()-1; i>=0; i--) - if (p->name == S_passwords(i).username) - storage = &S_passwords(i); + { + PasswordStorage & candidate = S_passwords(i); + if (p->name == candidate.username && + request.prefix == candidate.prefix && + request.suffix == candidate.suffix && + request.method == candidate.method + ) + storage = &candidate; + } if (!storage) { @@ -310,11 +332,13 @@ login.Enter(); // return username/scrambled password - if (S_login) { - // username = p->name; - nKrawall::ScramblePassword(password, scrambled); + // scramble password + request.Scramble( password, scrambled ); + // if S_login still exists, we were not canceled + answer.aborted = ( S_login == 0 ); + // clear the PW from memory for (i = password.Len()-2; i>=0; i--) password(i) = 'a'; @@ -322,12 +346,13 @@ if (se_PasswordStorageMode >= 0) { storage->username = username; + storage->prefix = request.prefix; + storage->suffix = request.suffix; + storage->method = request.method; memcpy(storage->password, scrambled, sizeof(nKrawall::nScrambledPassword)); storage->save = (se_PasswordStorageMode > 0); } } - else // or log out - sn_SetNetState(nSTANDALONE); S_login = NULL; } @@ -373,15 +398,12 @@ return false; } -static void ResultCallback(const tString& usernameUnfiltered, - const tString& origUsername, - const tString& authority_, - int user, bool success) +static void ResultCallback( nKrawall::nCheckResult const & result ) { - int i; + tString const & usernameUnfiltered = result.username; + tString authority = result.authority; + bool success = result.success; - tString authority = authority_; - // filter the user name tString username; ePlayerNetID::FilterName( usernameUnfiltered, username ); @@ -396,46 +418,15 @@ tRecorder::Record( section, success ); tRecorder::Record( section, authority ); - ePlayerNetID * player = NULL; - - // authenticate the user that logged in and change his name - for (i = se_PlayerNetIDs.Len()-1; i>=0 && !player; i--) + ePlayerNetID * player = dynamic_cast< ePlayerNetID * >( static_cast< nNetObject * >( result.user ) ); + if ( !player || player->Owner() <= 0 ) { - ePlayerNetID *p = se_PlayerNetIDs(i); - if (p->Owner() == user && p->GetUserName() == origUsername) - { - player = p; - if ( username != origUsername ) - { - player->SetUserName( username ); - } - } + // nobody to authenticate + return; } - // if the first step was not successful, - // authenticate the player from that client with the new user name (maybe he renamed?) - for (i = se_PlayerNetIDs.Len()-1; i>=0 && !player; i--) + if (success) { - ePlayerNetID *p = se_PlayerNetIDs(i); - if (p->Owner() == user && p->GetUserName() == username) - { - player = p; - } - } - - // last attempt: authenticate any player from that client. - for (i = se_PlayerNetIDs.Len()-1; i>=0 && !player; i--) - { - ePlayerNetID *p = se_PlayerNetIDs(i); - if (p->Owner() == user) - { - player = p; - p->SetUserName( username ); - } - } - - if (success && player) - { player->IsAuth(); player->SetUserName(username); player->Auth(authority); @@ -449,17 +440,11 @@ } else { - if ( sn_GetNetState() == nSERVER && user != sn_myNetID ) + if ( sn_GetNetState() == nSERVER ) { - tOutput out( "$login_request_failed" ); - out << '\n'; - sn_ConsoleOut( out, user ); + tOutput out( tOutput("$login_failed_message", result.error ) ); + sn_ConsoleOut( out, player->Owner() ); } - - - if ( player ) - { - } } } #endif @@ -1326,7 +1311,7 @@ return; } #endif - nAuthentification::RequestLogin(params,p->GetUserName(), p->Owner(), "$login_request_first"); + nAuthentification::RequestLogin(params,p->GetUserName(), *p, "$login_request_first"); } #endif } Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h 2008-01-21 19:35:28 UTC (rev 7573) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h 2008-01-21 19:46:06 UTC (rev 7574) @@ -133,7 +133,7 @@ int favoriteNumberOfPlayersPerTeam; // join team if number of players on it is less than this; create new team otherwise bool nameTeamAfterMe; // player prefers to call his team after his name - bool auth; // is this user valid? + bool auth; // is this user authenticated? bool greeted; // did the server already greet him? bool disconnected; // did he disconnect from the game? Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp 2008-01-21 19:35:28 UTC (rev 7573) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp 2008-01-21 19:46:06 UTC (rev 7574) @@ -62,10 +62,13 @@ +static bool S_UserAuthFailedLastTime [MAXCLIENTS+2]; static bool S_UserAuthActive [MAXCLIENTS+2]; -static tString S_UserAuthName [MAXCLIENTS+2]; static tString S_UserAuthURL [MAXCLIENTS+2]; +static tJUST_CONTROLLED_PTR<nNetObject> S_UserObject [MAXCLIENTS+2]; +static nKrawall::nMethod S_UserAuthMethod [MAXCLIENTS+2]; + #ifdef KRAWALL_SERVER static nKrawall::nSalt S_UserAuthSalt [MAXCLIENTS+2]; static REAL S_UserAuthStarted[MAXCLIENTS+2]; @@ -73,7 +76,10 @@ static void Reset() { - S_UserAuthActive[nCallbackLoginLogout::User()] = false; + int user = nCallbackLoginLogout::User(); + S_UserAuthActive[ user ] = false; + S_UserAuthFailedLastTime[ user ] = false; + S_UserObject[ user ] = 0; } static nCallbackLoginLogout resetter(Reset); @@ -87,12 +93,18 @@ // on the server: request user authentification from login slot -void nAuthentification::RequestLogin(const tString & url, const tString& username, int user, const tOutput& message, bool failureOnLastTry) +void nAuthentification::RequestLogin(const tString & url, const tString& username, nNetObject & user, const tOutput& message ) { #ifdef KRAWALL_SERVER + int userID = user.Owner(); + if ( userID <= 0 ) + { + return; + } + S_UserObject[userID] = &user; // do nothing if there is another login in process for that client - if (S_UserAuthActive[user]) + if (S_UserAuthActive[userID]) return; // create a random salt value @@ -100,50 +112,62 @@ RandomSalt(salt); // save the login information - memcpy(S_UserAuthSalt[user],salt, sizeof(nSalt)); - S_UserAuthActive[user] = true; - S_UserAuthStarted[user] = tSysTimeFloat(); - S_UserAuthName[user] = username; - S_UserAuthURL[user] = url; - + memcpy(S_UserAuthSalt[userID],salt, sizeof(nSalt)); + S_UserAuthActive[userID] = true; + S_UserAuthStarted[userID] = tSysTimeFloat(); + S_UserAuthURL[userID] = url; + // send the salt value and the username to the - nMessage *m = tNEW(nMessage)(nPasswordRequest); + nMessage *m = tNEW(nMessage)(::nPasswordRequest); WriteSalt(salt, *m); *m << username; *m << static_cast<tString>(message); - *m << failureOnLastTry; - m->Send(user); + *m << S_UserAuthFailedLastTime[userID]; + + // write extra info + nMethod & method = S_UserAuthMethod[userID]; + method.method = "bmd5"; + method.prefix = ""; + method.suffix = ""; + *m << method.method; + *m << method.prefix; + *m << method.suffix; + + m->Send(userID); #endif } -static tString S_username; -static tString S_message; -static nKrawall::nSalt S_salt; -static int S_user = -1; -static bool S_failureOnLastTry = false; +// password request and answer +static nKrawall::nPasswordRequest sn_request; +static nKrawall::nPasswordAnswer sn_answer; +static nKrawall::nSalt sn_salt; +static int s_inUse = false; // finish the request for username and password static void FinishHandlePasswordRequest() { - nKrawall::nScrambledPassword scrambled, egg; + nKrawall::nScrambledPassword egg; + sn_answer.aborted = false; + // if the callback exists, get the scrambled password of the wanted user if (S_UserPasswordCallback) - (*S_UserPasswordCallback)(S_username, S_message, scrambled, S_failureOnLastTry); + (*S_UserPasswordCallback)( sn_request, sn_answer ); // scramble it with the given salt - nKrawall::ScrambleWithSalt(scrambled, S_salt, egg); + nKrawall::ScrambleWithSalt(sn_answer.scrambled, sn_salt, egg); // destroy the original password - memset(scrambled, 0, sizeof(nKrawall::nScrambledPassword)); + memset(sn_answer.scrambled, 0, sizeof(nKrawall::nScrambledPassword)); // and send it back nMessage *ret = tNEW(nMessage)(nPasswordAnswer); nKrawall::WriteScrambledPassword(egg, *ret); - *ret << S_username; - ret->Send(S_user); + *ret << sn_answer.username; + *ret << sn_answer.aborted; + ret->Send(0); - S_user = -1; + s_inUse = false; } // receive a password request @@ -153,18 +177,36 @@ Cheater(m.SenderID()); // already in the process: return without answer - if (S_user >= 0) + if ( s_inUse ) return; + s_inUse = true; // read salt and username from the message - ReadSalt(m, S_salt); - m >> S_username; - m >> S_message; + ReadSalt(m, sn_salt); + m >> sn_answer.username; + m >> sn_request.message; if (!m.End()) - m >> S_failureOnLastTry; + { + m >> sn_request.failureOnLastTry; + } else - S_failureOnLastTry = true; - S_user = m.SenderID(); + { + sn_request.failureOnLastTry = true; + } + if (!m.End()) + { + // read method, prefix and suffiox + m >> sn_request.method; + m >> sn_request.prefix; + m >> sn_request.suffix; + } + else + { + // clear them + sn_request.method = "bmd5"; + sn_request.prefix = ""; + sn_request.suffix = ""; + } // postpone the answer for a better opportunity since it // most likely involves opening a menu and waiting a while (and we @@ -173,22 +215,18 @@ } #ifdef KRAWALL_SERVER -struct nPasswordCheckResult +struct nPasswordCheckResult: public nKrawall::nCheckResult { - tString username; // username as sent from client - tString oldUserName; // user name the client initiated authentication with - tString authority; // authority int userID; // user ID - bool success; // was the operation successful? void finish() { + user = S_UserObject[userID]; + S_UserObject[userID] = 0; + S_UserAuthFailedLastTime[userID] = !success; + if (S_LoginResultCallback) - (*S_LoginResultCallback)(username, - oldUserName, - authority, - userID, - success ); + (*S_LoginResultCallback)( *this ); } }; @@ -200,7 +238,6 @@ { nKrawall::nScrambledPassword hash; // hash as sent from client nKrawall::nSalt salt; // salt the hash was scrambled with - tString url; // authority url #ifdef HAVE_LIBZTHREAD static ZThread::LockedQueue< nPasswordCheckResult, ZThread::FastMutex > pending; @@ -219,8 +256,17 @@ public: void run() { - success = nKrawall::CheckScrambledPassword(url,username, hash, salt, authority); + if ( aborted ) + { + success = false; + error = tOutput("$login_error_aborted"); + } + else + { + nKrawall::CheckScrambledPassword( *this, hash, salt, S_UserAuthMethod[ userID ] ); + } + #ifdef HAVE_LIBZTHREAD // add result to queue pending.add( *this ); @@ -237,12 +283,18 @@ // read password and username from remote nKrawall::ReadScrambledPassword(m, hash); m >> username; + + aborted = false; + if ( !m.End() ) + { + m >> aborted; + } + username = tColoredString::RemoveColors( username ); userID = m.SenderID(); // fill other members from static data - url = S_UserAuthURL[userID]; - oldUserName = S_UserAuthName[userID]; + authority = S_UserAuthURL[userID]; memcpy( &salt, &S_UserAuthSalt[userID], sizeof(nKrawall::nSalt) ); } }; Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.h =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.h 2008-01-21 19:35:28 UTC (rev 7573) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.h 2008-01-21 19:46:06 UTC (rev 7574) @@ -37,19 +37,13 @@ public: // callback where the game can register the password request/ // lookup - typedef void UserPasswordCallback(tString& username, - const tString& message, - nScrambledPassword &scrambled, - bool failureOnLastTry); + typedef void UserPasswordCallback( nPasswordRequest const & request, + nPasswordAnswer & answer ); // callback where the game can register the login success // lookup - typedef void LoginResultCallback(const tString& username, - const tString& origUsername, - const tString& authority, - int user, bool success); + typedef void LoginResultCallback( nCheckResult const & result ); - // let the game register the callbacks static void SetUserPasswordCallback(UserPasswordCallback* callback); static void SetLoginResultCallback (LoginResultCallback* callback); @@ -59,7 +53,7 @@ static void HandlePasswordAnswer (nMessage& m); // on the server: request user authentification from login slot - static void RequestLogin(const tString& url, const tString& username, int user, const tOutput& message, bool failureOnLastTry = false); + static void RequestLogin(const tString& authority, const tString& username, nNetObject & user, const tOutput& message ); }; #endif Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.cpp 2008-01-21 19:35:28 UTC (rev 7573) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.cpp 2008-01-21 19:46:06 UTC (rev 7574) @@ -46,6 +46,38 @@ #include <string> #include <string.h> +// supported authentication methods of this client in a comma separated list ending in an additional comma (for lazy parsing) +tString const & nKrawall::nMethod::SupportedMethods() +{ + static tString sn_supportedAuthenticationMethods( + "md5," + "bmd5," + ); + + return sn_supportedAuthenticationMethods; +} + +void nKrawall::nMethod::Scramble( tString const & password, nScrambledPassword & scramble ) const +{ + if ( method == "bmd5" ) + { + nKrawall::BrokenScramblePassword( password, scramble ); + } + else // must be "md5" + { + tASSERT( method == "md5" ); + nKrawall::ScramblePassword( prefix + password + suffix, scramble ); + } +} + +nKrawall::nMethod::nMethod( char const * method_, char const * prefix_, char const * suffix_) + + : method( method_ ), + prefix( prefix_ ), + suffix( suffix_ ) +{ +} + #ifdef KRAWALL_SERVER_LEAGUE bool nKrawall::MayRequirePassword(tString& adress, unsigned int port) { @@ -133,16 +165,26 @@ // scramble a password locally (so it does not have to be stored on disk) -void nKrawall::ScramblePassword(const tString& username, +void nKrawall::ScramblePassword(const tString& password, nScrambledPassword &scrambled) { md5_state_t state; md5_init(&state); - md5_append(&state, (md5_byte_t const *)(&username[0]), username.Len()); + md5_append(&state, (md5_byte_t const *)(&password[0]), password.Len() - 1); md5_finish(&state, scrambled); } +// scramble a password locally (so it does not have to be stored on disk) +void nKrawall::BrokenScramblePassword(const tString& password, + nScrambledPassword &scrambled) +{ + md5_state_t state; + md5_init(&state); + md5_append(&state, (md5_byte_t const *)(&password[0]), password.Len()); + md5_finish(&state, scrambled); +} + // scramble it again before transfering it over the network void nKrawall::ScrambleWithSalt(const nScrambledPassword& source, const nSalt& salt, Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.h =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.h 2008-01-21 19:35:28 UTC (rev 7573) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.h 2008-01-21 19:46:06 UTC (rev 7574) @@ -40,7 +40,12 @@ #include "defs.h" #include "config.h" #include "md5.h" +#include "tSafePTR.h" +#include "tString.h" +#include "nNetObject.h" +// class nNetObject; + #ifndef _IOSFWD_ #endif @@ -57,6 +62,68 @@ typedef md5_byte_t nScrambledPassword[16]; // (freely changable) typedef nScrambledPassword nSalt; // (freely changable) + // authentication method information + struct nMethod + { + tString method; // scrambling method; "bmd5" for old school + tString prefix; // thing to prepend the password before hashing it + tString suffix; // thing to append to the password before hashing it + + // returns a comma separated comma terminated list of supported methods + static tString const & SupportedMethods(); + + // scramble a password using this + void Scramble( tString const & password, nScrambledPassword & scrambled ) const; + + nMethod(){} + + nMethod( char const * method_, char const * prefix_ = "", char const * suffix_ = ""); + }; + + // structure for a password request to the user + struct nPasswordRequest: public nMethod + { + tString message; // message to show to the user + bool failureOnLastTry; // did the last attempt fail? + + nPasswordRequest() + : failureOnLastTry ( false ){} + }; + + // structure for read-write data for password requests + struct nPasswordAnswer + { + tString username; // username, read-write property + nScrambledPassword scrambled; // the scrambled password + bool aborted; // did the user abort the operation? + + nPasswordAnswer() + : aborted( false ){} + }; + + + // return structure for an authentication request + // return structure for an authentication request + struct nCheckResultBase + { + tString username; // username as sent from client + tString authority; // authority; authenticated name is username@authority (with 0: prefix in log files) + bool success; // was the operation successful? + tString error; // potential error message + + nCheckResultBase() + : success( false ){} + }; + + struct nCheckResult: public nCheckResultBase + { + tJUST_CONTROLLED_PTR< nNetObject > user; // net object identifying the user (will be ePlayerNetID, but we don't know about that here) + bool aborted; // did the user abort the operation? + + nCheckResult() + : aborted( false ){} + }; + // encode scrambled passwords and salts as hexcode strings static tString EncodeScrambledPassword( nScrambledPassword const & scrambled ); @@ -93,9 +160,13 @@ // scramble a password locally (so it does not have to be stored on disk) - static void ScramblePassword(const tString& username, + static void ScramblePassword(const tString& password, nScrambledPassword &scrambled); + // scramble a password locally (so it does not have to be stored on disk), old broken method that includes the trailing \0. + static void BrokenScramblePassword(const tString& password, + nScrambledPassword &scrambled); + // scramble it again before transfering it over the network static void ScrambleWithSalt(const nScrambledPassword& source, const nSalt& salt, @@ -106,12 +177,11 @@ // get a random salt value static void RandomSalt(nSalt& salt); - // check whether username's password, when run through ScrambleWithSalt( ScramblePassword(password), salt ), equals scrambledRemote. - static bool CheckScrambledPassword(const tString& url, - const tString& username, - nScrambledPassword const & hash, - nSalt const & salt, - tString & authority); + // check whether username's password, when run through ScrambleWithSalt( ScramblePassword(password), salt ), equals scrambledRemote. result.userName and result.authority need to be set by the caller, success and error are filled by this function, and authority may be modified. + static void CheckScrambledPassword( nCheckResultBase & result, + nScrambledPassword const & hash, + nSalt const & salt, + nMethod const & method ); #ifdef KRAWALL_SERVER_LEAGUE // secret key to encrypt server->master server league transfer Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp 2008-01-21 19:35:28 UTC (rev 7573) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp 2008-01-21 19:46:06 UTC (rev 7574) @@ -46,10 +46,14 @@ #include <libxml/nanohttp.h> +static nKrawall::nMethod sn_bmd5("bmd5"), md5("md5"); + // crude login structure with not too many feathres struct nLogin { tString authority_; + tString password_; + nKrawall::nScrambledPassword brokenScrambledPassword_; nKrawall::nScrambledPassword scrambledPassword_; nLogin( char const * authority, tString const & password ) @@ -57,6 +61,7 @@ { // scramble the password before storing it (in case an evil attacker can read our memory, // but not the configuration file where they are stored in plain text :) ) + nKrawall::BrokenScramblePassword( password, brokenScrambledPassword_ ); nKrawall::ScramblePassword( password, scrambledPassword_ ); } @@ -210,57 +215,74 @@ static tConfItemFunc sn_kpr( "MD5_PASSWORD_REMOVE", sn_ReadPasswordRemove ); // fetch the scrambled password of username from the users database -bool nKrawall::CheckScrambledPassword(const tString& url, - const tString& username, - nScrambledPassword const & scrambledRemote, - nSalt const & salt, - tString & authority ) +void nKrawall::CheckScrambledPassword( nCheckResultBase & result, + nScrambledPassword const & hash, + nSalt const & salt, + nMethod const & method ) { // local users - if ( url.Len() <= 1 ) + if ( result.authority.Len() <= 1 ) { // fetch login data - nLogin const * login = sn_FindLogin( username ); + nLogin const * login = sn_FindLogin( result.username ); if ( !login ) { - return false; + result.success = false; + result.error = tString( "Local user " ) + result.username + " not found."; + return; } // store relevant authority - authority = login->authority_; + result.authority = login->authority_; // compare passwords nScrambledPassword scrambledCorrect; ScrambleWithSalt( login->scrambledPassword_, salt, scrambledCorrect ); - return ArePasswordsEqual( scrambledRemote, scrambledCorrect ); + result.success = ArePasswordsEqual( hash, scrambledCorrect ); + return; } else { // remote users: build md5 query URL - authority = url; std::ostringstream fullURL; - fullURL << "http://" << url << "/hashauth/bmd5"; + fullURL << "http://" << result.authority << "/hashauth/bmd5"; // fullURL << "?query=password"; // fullURL << "http://authentication.armagetronad.net/hashauth.php"; - fullURL << "?user=" << username; + fullURL << "?method=bmd5"; + fullURL << "&user=" << result.username; fullURL << "&salt=" << EncodeScrambledPassword( salt ); - fullURL << "&hash=" << EncodeScrambledPassword( scrambledRemote ); + fullURL << "&hash=" << EncodeScrambledPassword( hash ); // fetch the URL's content (TODO: unblock it) void *ctxt = NULL; int rc; - con << "Fetching authentication URL " << fullURL.str() << "\n"; + // better not. output is not thread safe. + // con << "Fetching authentication URL " << fullURL.str() << "\n"; ctxt = xmlNanoHTTPOpen(fullURL.str().c_str(), NULL); - if (ctxt == NULL) { - con << "ERROR: ctxt is NULL\n"; - return false; + if (ctxt == NULL) + { + result.error = tOutput( "$login_error_invalidurl", result.authority ); + result.success = false; + return; } + // catch various error codes if ( (rc = xmlNanoHTTPReturnCode(ctxt)) != 200 ) { - con << tOutput( rc == 404 ? "$resource_fetcherror_404" : "$resource_fetcherror", rc ); - return false; + result.success = false; + switch ( rc ) + { + case 404: + result.error = tOutput( "$login_error_nouser" ); + break; + case 401: + result.error = tOutput( "$login_error_password" ); + break; + default: + result.error = tOutput( "$login_error_unknown", rc ); + } + return; } // read content @@ -271,9 +293,15 @@ if ( len >= sizeof(buf) ) len = sizeof(buf) - 1; buf[len] = 0; - con << "Answer: " << buf << "\n"; - return ( strncmp( "PASSWORD_OK", buf, sizeof(buf)-1 ) == 0 ); + char const * expected = "PASSWORD_OK"; + result.success = ( strncmp( expected , buf, strlen(expected) ) == 0 ); + if ( !result.success ) + { + result.error << tOutput( "$login_error_unexpected_answer", buf ); + } + + return; } } Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nNetwork.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nNetwork.cpp 2008-01-21 19:35:28 UTC (rev 7573) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nNetwork.cpp 2008-01-21 19:46:06 UTC (rev 7574) @@ -35,6 +35,7 @@ #include "tDirectories.h" #include "nSocket.h" #include "nConfig.h" +#include "nKrawall.h" #include "tSysTime.h" #include "tRecorder.h" #include "tRandom.h" @@ -1522,7 +1523,7 @@ static bool sn_lockOut028tTest = true; static tSettingItem< bool > sn_lockOut028TestConf( "NETWORK_LOCK_OUT_028_TEST", sn_lockOut028tTest ); -int login_handler(const nMessage &m, const nVersion& version, unsigned short rate ){ +int login_handler(const nMessage &m, const nVersion& version, unsigned short rate, tString & supportedAuthenticationMethods ){ nCurrentSenderID senderID; // don't accept logins in client mode @@ -1609,6 +1610,8 @@ // peers [ MAXCLIENTS+1 ].sa_family = 0; // nCallbackLoginLogout::UserLoggedIn(i); + sn_Connections [ new_id ].supportedAuthenticationMethods_ = supportedAuthenticationMethods; + // recount doublicate IPs CountSameIP( new_id, true ); } @@ -1689,13 +1692,18 @@ m >> rem_bb; } + // clients this old don't support any authentication method. + tString supportedAuthenticationMethods(""); if ( !m.End() ) { // version! m >> version; + + // ok, clients that send a version do have authentication. + supportedAuthenticationMethods = "bmd5,"; } - login_handler( m, version, rate ); + login_handler( m, version, rate, supportedAuthenticationMethods ); } void login_handler_2(nMessage& m) @@ -1712,11 +1720,19 @@ m >> rem_bb; } + // read peer network protocol version nVersion ver; m >> ver; - int new_ID = login_handler( m, ver , rate ); + // read peer supported authentication methods (fallback to broken md5) + tString supportedAuthenticationMethods("bmd5,"); + if ( !m.End() ) + { + m >> supportedAuthenticationMethods; + } + int new_ID = login_handler( m, ver , rate, supportedAuthenticationMethods ); + if ( new_ID > 0 ) { nMessage* m = tNEW( nMessage )( versionControl ); @@ -2564,7 +2580,11 @@ big_brother=false; } + // write our version (*mess) << sn_MyVersion(); + + // write our supported authentication methods + (*mess) << nKrawall::nMethod::SupportedMethods(); } else { @@ -3237,15 +3257,17 @@ socket = NULL; ackPending = 0; ping.Reset(); - crypt = NULL; + // crypt = NULL; + supportedAuthenticationMethods_ = ""; + sendBuffer_.Clear(); bandwidthControl_.Reset(); ackMess = NULL; - userName.SetLen(0); + // userName.SetLen(0); // start with 10% packet loss with low statistical weight packetLoss_.Reset(); Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nNetwork.h =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nNetwork.h 2008-01-21 19:35:28 UTC (rev 7573) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nNetwork.h 2008-01-21 19:46:06 UTC (rev 7574) @@ -281,7 +281,7 @@ nPingAverager ping; - tCrypt* crypt; + // tCrypt* crypt; // rate control nBandwidthControl bandwidthControl_; @@ -296,8 +296,11 @@ tJUST_CONTROLLED_PTR< nMessage > ackMess; // authentication - tString userName; + // tString userName; + // supported authentication methods of the client in a comma separated list ending in an additional comma (for lazy parsing) + tString supportedAuthenticationMethods_; + nConnectionInfo(); ~nConnectionInfo(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <z-...@us...> - 2008-01-22 02:05:48
|
Revision: 7578 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7578&view=rev Author: z-man Date: 2008-01-21 18:05:53 -0800 (Mon, 21 Jan 2008) Log Message: ----------- Leakfix and even better error messages. Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp Modified: armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-22 02:05:08 UTC (rev 7577) +++ armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-22 02:05:53 UTC (rev 7578) @@ -2474,14 +2474,14 @@ login_message \1 has been logged in by the power of authority \2.\n logout_message \1 has been logged out of authority \2.\n -login_failed_message 0xff7f7fLogin failed, reason: \1\n +login_failed_message 0xff7f7fLogin failed,0xffffff reason: \1\n # various reasons for logins to fail login_error_aborted Login aborted. login_error_invalidurl Authentication URL \1 invalid. -login_error_nouser User does not exist. -login_error_password Wrong password supplied. -login_error_unknown Unknown error \1 returned. +login_error_nouser User does not exist, authentication server returned "\1". +login_error_password Wrong password supplied, authentication server returned "\1". +login_error_unknown Unknown error code \1 returned, content "\2". login_error_unexpected_answer Answer PASSWORD_OK expected from server, but got \1 instead. chatcommand_requires_player \1 requires a player username as additional paramenter. Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp 2008-01-22 02:05:08 UTC (rev 7577) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp 2008-01-22 02:05:53 UTC (rev 7578) @@ -253,14 +253,11 @@ fullURL << "&salt=" << EncodeScrambledPassword( salt ); fullURL << "&hash=" << EncodeScrambledPassword( hash ); - // fetch the URL's content (TODO: unblock it) - void *ctxt = NULL; - int rc; - // better not. output is not thread safe. // con << "Fetching authentication URL " << fullURL.str() << "\n"; - ctxt = xmlNanoHTTPOpen(fullURL.str().c_str(), NULL); + // fetch URL + void * ctxt = xmlNanoHTTPOpen(fullURL.str().c_str(), NULL); if (ctxt == NULL) { result.error = tOutput( "$login_error_invalidurl", result.authority ); @@ -268,28 +265,52 @@ return; } + int rc = xmlNanoHTTPReturnCode(ctxt); + + // read content + char buf[1000]; + buf[0] = 0; + unsigned int len = xmlNanoHTTPRead( ctxt, &buf, sizeof(buf) ); + if ( len >= sizeof(buf) ) + { + len = sizeof(buf)-1; + } + xmlNanoHTTPClose(ctxt); + + // get rid of newlines + for ( unsigned int i = 0; i < len; ++i ) + { + if ( buf[i] == '\n' ) + { + buf[i] = ' '; + } + } + + // trailing spaces are ugly + while ( len > 0 && buf[len-1] == ' ' ) + { + buf[len-1] = 0; + --len; + } + // catch various error codes - if ( (rc = xmlNanoHTTPReturnCode(ctxt)) != 200 ) { + if ( rc != 200 ) { result.success = false; switch ( rc ) { case 404: - result.error = tOutput( "$login_error_nouser" ); + result.error = tOutput( "$login_error_nouser", buf ); break; case 401: - result.error = tOutput( "$login_error_password" ); + result.error = tOutput( "$login_error_password", buf ); break; default: - result.error = tOutput( "$login_error_unknown", rc ); + result.error = tOutput( "$login_error_unknown", rc, buf ); } + return; } - // read content - char buf[100]; - buf[0] = 0; - unsigned int len = xmlNanoHTTPRead( ctxt, &buf, sizeof(buf) ); - xmlNanoHTTPClose(ctxt); if ( len >= sizeof(buf) ) len = sizeof(buf) - 1; buf[len] = 0; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <z-...@us...> - 2008-01-22 15:34:29
|
Revision: 7587 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7587&view=rev Author: z-man Date: 2008-01-22 07:33:47 -0800 (Tue, 22 Jan 2008) Log Message: ----------- Added authentication hash method query; the server now picks a method client, server and authority support (or gives up). Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.h armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/network/nNetwork.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/network/nNetwork.h Modified: armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-22 15:19:52 UTC (rev 7586) +++ armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-22 15:33:47 UTC (rev 7587) @@ -2479,11 +2479,18 @@ # various reasons for logins to fail login_error_aborted Login aborted. login_error_invalidurl Authentication URL \1 invalid. +login_error_methodmismatch The local method used for auhtentication has been modified since your password was set. In the server's config files, put all commands that define authentication methods before all local password definitions. +login_error_nomethod No authentication method could be found. Your client supports \1, this server supports \2, and the authentication server supports \3. +login_error_nomethodlist Authentication URL \1 does not return a list of supported methods. +login_error_nomethodproperties Authentication URL \1 does not return a list of methods properties. login_error_nouser User does not exist, authentication server returned "\1". login_error_password Wrong password supplied, authentication server returned "\1". login_error_unknown Unknown error code \1 returned, content "\2". login_error_unexpected_answer Answer PASSWORD_OK expected from server, but got \1 instead. +login_error_local_nouser Local user \1 not found. +login_error_local_password Supplied password for local user \1 incorrect. + chatcommand_requires_player \1 requires a player username as additional paramenter. authentication_required_help Controls how authentication influences your right to play. If set to 0, authentication has no influence. If set to 2, you are always required to authenticate to play. If set to 1, you need to be authenticated if only one other player is already authenticated. Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-22 15:19:52 UTC (rev 7586) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-22 15:33:47 UTC (rev 7587) @@ -291,7 +291,7 @@ if (!failure) { username = storage->username; - memcpy(scrambled, storage->password, sizeof(nKrawall::nScrambledPassword)); + scrambled = storage->password; return; } else @@ -334,7 +334,7 @@ // return username/scrambled password { // scramble password - request.Scramble( password, scrambled ); + request.ScramblePassword( nKrawall::nScrambleInfo( username), password, scrambled ); // if S_login still exists, we were not canceled answer.aborted = ( S_login == 0 ); @@ -349,7 +349,7 @@ storage->prefix = request.prefix; storage->suffix = request.suffix; storage->method = request.method; - memcpy(storage->password, scrambled, sizeof(nKrawall::nScrambledPassword)); + storage->password = scrambled; storage->save = (se_PasswordStorageMode > 0); } } Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp 2008-01-22 15:19:52 UTC (rev 7586) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp 2008-01-22 15:33:47 UTC (rev 7587) @@ -92,131 +92,6 @@ static nDescriptor nPasswordAnswer(41, &nAuthentification::HandlePasswordAnswer, "password_answer"); -#ifdef KRAWALL_SERVER -// checks for the methods an authentication server provides -struct nMethodCheckResult -{ - int userID; - tString username; - tString authority; - tString message; - - void finish() - { - // create a random salt value - nKrawall::RandomSalt(S_UserAuthSalt[userID]); - // save the login information - - // send the salt value and the username to the - nMessage *m = tNEW(nMessage)(::nPasswordRequest); - nKrawall::WriteSalt(S_UserAuthSalt[userID], *m); - *m << username; - *m << static_cast<tString>(message); - *m << S_UserAuthFailedLastTime[userID]; - - // write method info - nKrawall::nMethod & method = S_UserAuthMethod[userID]; - *m << method.method; - *m << method.prefix; - *m << method.suffix; - - m->Send(userID); - } -}; - -class nMethodCheck : public nMethodCheckResult -#ifdef HAVE_LIBZTHREAD - , public ZThread::Runnable -#endif -{ -#ifdef HAVE_LIBZTHREAD - static ZThread::LockedQueue< nMethodCheckResult, ZThread::FastMutex > pending; - - static void FinishAll() - { - // finish all pending tasks - while( pending.size() > 0 ) - { - nMethodCheckResult next = pending.next(); - next.finish(); - } - } -#endif - -public: - void run() - { - // set method to defaults - nKrawall::nMethod & method = S_UserAuthMethod[userID]; - method.method = "bmd5"; - method.prefix = ""; - method.suffix = ""; - - // try yo find a better method, fetch method list - std::ostringstream methods; - nKrawall::FetchURL( authority, "", methods ); - - // fetch md5 prefix - std::ostringstream query; - query << "?method=md5&user=" << username; - std::ostringstream md5data; - nKrawall::FetchURL( authority, query.str().c_str(), md5data ); - - -#ifdef HAVE_LIBZTHREAD - // add result to queue - pending.add( *this ); - - // schedule call to FinishAll - st_ToDo( FinishAll ); -#endif - } - - nMethodCheck( tString const & authority, tString const & username, int userID, tString const & message ) - { - this->userID = userID; - this->username = username; - this->message = message; - this->authority = authority; - } -}; - -#ifdef HAVE_LIBZTHREAD -ZThread::LockedQueue< nMethodCheckResult, ZThread::FastMutex > nMethodCheck::pending; -#endif -#endif - -// on the server: request user authentification from login slot -void nAuthentification::RequestLogin(const tString & authority, const tString& username, nNetObject & user, const tOutput& message ) -{ -#ifdef KRAWALL_SERVER - int userID = user.Owner(); - if ( userID <= 0 ) - { - return; - } - - // do nothing if there is another login in process for that client - if (S_UserAuthActive[userID]) - return; - - S_UserAuthActive[userID] = true; - S_UserObject[userID] = &user; - - S_UserAuthStarted[userID] = tSysTimeFloat(); - S_UserAuthURL[userID] = authority; - -#ifdef HAVE_LIBZTHREAD - static ZThread::ThreadedExecutor executor; - executor.execute( ZThread::Task( new nMethodCheck( authority, username, userID, tString(message) ) ) ); -#else - nMethodCheck c( userID ); - c.run(); - c.finish(); -#endif -#endif -} - // password request and answer static nKrawall::nPasswordRequest sn_request; static nKrawall::nPasswordAnswer sn_answer; @@ -235,10 +110,10 @@ (*S_UserPasswordCallback)( sn_request, sn_answer ); // scramble it with the given salt - nKrawall::ScrambleWithSalt(sn_answer.scrambled, sn_salt, egg); + sn_request.ScrambleWithSalt( nKrawall::nScrambleInfo(sn_answer.username), sn_answer.scrambled, sn_salt, egg); // destroy the original password - memset(sn_answer.scrambled, 0, sizeof(nKrawall::nScrambledPassword)); + sn_answer.scrambled.Clear(); // and send it back nMessage *ret = tNEW(nMessage)(nPasswordAnswer); @@ -334,8 +209,22 @@ } } #endif + +public: + static void ReportResult( nPasswordCheckResult const & result ) + { +#ifdef HAVE_LIBZTHREAD + // add result to queue + pending.add( result ); -public: + // schedule call to FinishAll + st_ToDo( FinishAll ); +#else + // finish it immedeately + result.finish(); +#endif + } + void run() { if ( aborted ) @@ -349,13 +238,7 @@ nKrawall::CheckScrambledPassword( *this, hash, salt, S_UserAuthMethod[ userID ] ); } -#ifdef HAVE_LIBZTHREAD - // add result to queue - pending.add( *this ); - - // schedule call to FinishAll - st_ToDo( FinishAll ); -#endif + ReportResult( * this ); } nPasswordCheck( nMessage & m ) @@ -400,9 +283,244 @@ #else nPasswordCheck c(m); c.run(); +#endif +#endif +} + +#ifdef KRAWALL_SERVER +// checks for the methods an authentication server provides +struct nMethodCheckResult +{ + int userID; + tString username; + tString authority; + tString message; + + void finish() + { + // create a random salt value + nKrawall::RandomSalt(S_UserAuthSalt[userID]); + // save the login information + + // send the salt value and the username to the + nMessage *m = tNEW(nMessage)(::nPasswordRequest); + nKrawall::WriteSalt(S_UserAuthSalt[userID], *m); + *m << username; + *m << static_cast<tString>(message); + *m << S_UserAuthFailedLastTime[userID]; + + // write method info + nKrawall::nMethod & method = S_UserAuthMethod[userID]; + *m << method.method; + *m << method.prefix; + *m << method.suffix; + + m->Send(userID); + } +}; + +class nMethodCheck : public nMethodCheckResult +#ifdef HAVE_LIBZTHREAD + , public ZThread::Runnable +#endif +{ +#ifdef HAVE_LIBZTHREAD + static ZThread::LockedQueue< nMethodCheckResult, ZThread::FastMutex > pending; + + static void FinishAll() + { + // finish all pending tasks + while( pending.size() > 0 ) + { + nMethodCheckResult next = pending.next(); + next.finish(); + } + } +#endif + +public: + // report an error to the higher level system + bool ReportError( tOutput const & error ) + { + // well, the public scripts don't support this yet, so let's fake it + nKrawall::nMethod & method = S_UserAuthMethod[userID]; + method.method = "bmd5"; + method.prefix = ""; + method.suffix = ""; + return true; + + // true code follows: + + // prepare failure report + nPasswordCheckResult result; + result.userID = userID; + result.username = username; + result.authority = authority; + result.success = false; + result.error = error; + + nPasswordCheck::ReportResult( result ); + + return false; + } + + // handle local logins + bool runLocal() + { + // fetch method + nKrawall::nMethod & method = S_UserAuthMethod[userID]; + + // try yo find a better method + if ( !nKrawall::nMethod::BestLocalMethod( + sn_Connections[userID].supportedAuthenticationMethods_, + method + ) + ) + { + return ReportError( + tOutput( "$login_error_nomethod", + sn_Connections[userID].supportedAuthenticationMethods_, + nKrawall::nMethod::SupportedMethods(), + nKrawall::nMethod::SupportedMethods() ) + ); + } + + return true; + } + + bool runRemote() + { + // fetch method + nKrawall::nMethod & method = S_UserAuthMethod[userID]; + + { + // try yo find a better method, fetch method list + std::ostringstream methods; + int rc = nKrawall::FetchURL( authority, "", methods ); + + if ( rc == -1 ) + { + return ReportError( tOutput( "$login_error_invalidurl", authority ) ); + } + + method.method = nKrawall::nMethod::BestMethod( + methods.str().c_str(), + sn_Connections[userID].supportedAuthenticationMethods_ + ); + if ( rc != 200 ) + { + return ReportError( tOutput( "$login_error_nomethodlist", authority ) ); + } + + // check whether a method can be found + if ( method.method.Len() <= 1 ) + { + return ReportError( + tOutput( "$login_error_nomethod", + sn_Connections[userID].supportedAuthenticationMethods_, + nKrawall::nMethod::SupportedMethods(), + methods.str().c_str() ) + ); + } + } + + // fetch md5 prefix and suffix + { + std::ostringstream query; + query << "?method=" << method.method; + std::ostringstream data; + int rc = nKrawall::FetchURL( authority, query.str().c_str(), data ); + + if ( rc != 200 ) + { + if ( rc == -1 ) + { + return ReportError( tOutput( "$login_error_invalidurl", authority ) ); + } + + return ReportError( tOutput( "$login_error_nomethodproperties", authority ) ); + } + + // read the properties + std::istringstream read( data.str() ); + method = nKrawall::nMethod( static_cast< char const * >( method.method ), read ); + } + + return true; + } + + + void run() + { + // set method to defaults + nKrawall::nMethod & method = S_UserAuthMethod[userID]; + method.method = "bmd5"; + method.prefix = ""; + method.suffix = ""; + + // local logins are easy, handle them first + if ( authority.Len() <= 1 ) + { + if ( !runLocal() ) + return; + } + else + { + if ( !runRemote() ) + return; + } + +#ifdef HAVE_LIBZTHREAD + // add result to queue + pending.add( *this ); + + // schedule call to FinishAll + st_ToDo( FinishAll ); +#endif + } + + nMethodCheck( tString const & authority, tString const & username, int userID, tString const & message ) + { + this->userID = userID; + this->username = username; + this->message = message; + this->authority = authority; + } +}; + +#ifdef HAVE_LIBZTHREAD +ZThread::LockedQueue< nMethodCheckResult, ZThread::FastMutex > nMethodCheck::pending; +#endif +#endif + +// on the server: request user authentification from login slot +void nAuthentification::RequestLogin(const tString & authority, const tString& username, nNetObject & user, const tOutput& message ) +{ +#ifdef KRAWALL_SERVER + int userID = user.Owner(); + if ( userID <= 0 ) + { + return; + } + + // do nothing if there is another login in process for that client + if (S_UserAuthActive[userID]) + return; + + S_UserAuthActive[userID] = true; + S_UserObject[userID] = &user; + + S_UserAuthStarted[userID] = tSysTimeFloat(); + S_UserAuthURL[userID] = authority; + +#ifdef HAVE_LIBZTHREAD + static ZThread::ThreadedExecutor executor; + executor.execute( ZThread::Task( new nMethodCheck( authority, username, userID, tString(message) ) ) ); +#else + nMethodCheck c( userID ); + c.run(); c.finish(); #endif #endif } - Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.cpp 2008-01-22 15:19:52 UTC (rev 7586) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.cpp 2008-01-22 15:33:47 UTC (rev 7587) @@ -35,6 +35,7 @@ #include "nKrawall.h" #include "nNetwork.h" #include "nServerInfo.h" +#include "nNetObject.h" #include "tString.h" #include "tArray.h" #include "tConsole.h" @@ -51,14 +52,117 @@ { static tString sn_supportedAuthenticationMethods( "md5," - "bmd5," + "bmd5" ); return sn_supportedAuthenticationMethods; } -void nKrawall::nMethod::Scramble( tString const & password, nScrambledPassword & scramble ) const +// adds commata to the start and end of a string +tString sn_EasyParse( char const * original ) { + std::ostringstream s; + s << "," << original << ","; + + return tString( s.str().c_str() ); +} + +// checks whether both a and b support protocol m +static bool sn_BothHave( char const *a, char const *b, char const * m) +{ + tString search = sn_EasyParse( m ); + return strstr( a, search ) != 0 && strstr( b, search ) != 0; +} + +// from two strings of supported-method-lists, select the best one +tString nKrawall::nMethod::BestMethod( char const * a, char const * b ) +{ + tString ret; + + tString A = sn_EasyParse( a ); + tString B = sn_EasyParse( b ); + + // protocols, best ones first + char const * protocols[] = { + "md5", + "bmd5", + 0 + }; + + // iterate through methods, starting from best, and return the first that fits + char const * const * run = protocols; + while ( *run ) + { + if ( sn_BothHave( A, B, *run ) ) + { + return tString( *run ); + } + ++run; + } + + return tString(""); +}; + +//! fetch best local method supported by the client +bool nKrawall::nMethod::BestLocalMethod( char const * supportedOnClient, nMethod & result ) +{ + tString haystack = sn_EasyParse( supportedOnClient ); + + nMethod const * const * run = LocalMethods(); + + while ( * run ) + { + tString needle = sn_EasyParse( (*run)->method ); + if ( strstr( haystack, needle ) != 0 ) + { + result = **run; + return true; + } + + ++run; + } + + return false; +} + +bool nKrawall::nMethod::Equal( nMethod const & a, nMethod const & b ) +{ + return a.method == b.method && a.prefix == b.prefix && a.suffix == b.suffix; +} + +// does standard replacements to prefix and suffix; +// %u -> username +static tString sn_Replace( nKrawall::nScrambleInfo const & info, tString const & original ) +{ + std::istringstream in( static_cast< char const * >( original ) ); + std::ostringstream out; + + while ( !in.eof() ) + { + char s = in.get(); + if ( s != '%' || in.eof() ) + { + out.put(s); + } + else + { + s = in.get(); + if ( s == 'u' ) + { + out << info.username; + } + else + { + out << '%' << s; + } + } + } + + return tString( out.str().c_str() ); +} + +void nKrawall::nMethod::ScramblePassword( nScrambleInfo const & info, tString const & password, nScrambledPassword & scramble ) const +{ if ( method == "bmd5" ) { nKrawall::BrokenScramblePassword( password, scramble ); @@ -66,10 +170,26 @@ else // must be "md5" { tASSERT( method == "md5" ); - nKrawall::ScramblePassword( prefix + password + suffix, scramble ); + nKrawall::ScramblePassword( sn_Replace(info,prefix) + password + sn_Replace(info,suffix), scramble ); } } +// scramble a password hash with a salt +void nKrawall::nMethod::ScrambleWithSalt( nScrambleInfo const & info, nScrambledPassword const & scrambled, nSalt const & salt, nScrambledPassword & result ) const +{ + // nothing fancy heere + nKrawall::ScrambleWithSalt2( scrambled, salt, result ); +} + +// construct a method from the type and a stream with properties +// the stream is supposed to consist of lines of the "property_name property_value" form. +nKrawall::nMethod::nMethod( char const * method_, std::istream & properties ) +{ + method = method_; + + +} + nKrawall::nMethod::nMethod( char const * method_, char const * prefix_, char const * suffix_) : method( method_ ), @@ -104,6 +224,16 @@ return true; } +nKrawall::nCheckResult::nCheckResult() +: aborted( false ){} + +nKrawall::nCheckResult::~nCheckResult(){} + +nKrawall::nCheckResult::nCheckResult( nCheckResult const & other ) +: nCheckResultBase( other ), user( other.user ), aborted( other.aborted ) +{ +} + // encode scrambled passwords and salts as hexcode strings tString nKrawall::EncodeScrambledPassword( nScrambledPassword const & scrambled ) { @@ -171,7 +301,7 @@ md5_state_t state; md5_init(&state); md5_append(&state, (md5_byte_t const *)(&password[0]), password.Len() - 1); - md5_finish(&state, scrambled); + md5_finish(&state, scrambled.content); } // scramble a password locally (so it does not have to be stored on disk) @@ -181,20 +311,20 @@ md5_state_t state; md5_init(&state); md5_append(&state, (md5_byte_t const *)(&password[0]), password.Len()); - md5_finish(&state, scrambled); + md5_finish(&state, scrambled.content); } // scramble it again before transfering it over the network -void nKrawall::ScrambleWithSalt(const nScrambledPassword& source, +void nKrawall::ScrambleWithSalt2(const nScrambledPassword& source, const nSalt& salt, nScrambledPassword& dest) { md5_state_t state; md5_init(&state); - md5_append(&state, source, 16); - md5_append(&state, salt , 16); - md5_finish(&state, dest); + md5_append(&state, source.content, 16); + md5_append(&state, salt.content , 16); + md5_finish(&state, dest.content); } Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.h =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.h 2008-01-22 15:19:52 UTC (rev 7586) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.h 2008-01-22 15:33:47 UTC (rev 7587) @@ -42,9 +42,9 @@ #include "md5.h" #include "tSafePTR.h" #include "tString.h" -#include "nNetObject.h" +// #include "nNetObject.h" -// class nNetObject; +class nNetObject; #ifndef _IOSFWD_ #endif @@ -54,29 +54,84 @@ class tString; class nMessage; +//! base class for authentication, unaware of armagetron network messages class nKrawall { public: + // the scrambled password data types + class nScrambledPassword + { + friend class nKrawall; - // the scrambled password data types - typedef md5_byte_t nScrambledPassword[16]; // (freely changable) + md5_byte_t content[16]; + public: + md5_byte_t operator[]( int i ) const + { + tASSERT( i >= 0 && i < 16 ); + return content[i]; + } + + md5_byte_t & operator[]( int i ) + { + tASSERT( i >= 0 && i < 16 ); + return content[i]; + } + + void Clear() + { + memset( &content, 0, sizeof(content)); + } + }; + typedef nScrambledPassword nSalt; // (freely changable) - // authentication method information + //! extra information for password scrambling + struct nScrambleInfo + { + // nAddress clientAddress; //!< address of the server + // nAddress serverAddress; //!< address of the client + tString username; //!< the username + + nScrambleInfo( tString const & username_ ) + : username( username_ ) + { + } + }; + + //! authentication method information struct nMethod { - tString method; // scrambling method; "bmd5" for old school - tString prefix; // thing to prepend the password before hashing it - tString suffix; // thing to append to the password before hashing it + tString method; //!< scrambling method; "bmd5" for old school + tString prefix; //!< thing to prepend the password before hashing it + tString suffix; //!< thing to append to the password before hashing it - // returns a comma separated comma terminated list of supported methods + // returns a comma separated list of supported methods static tString const & SupportedMethods(); + // from two strings of supported-method-lists, select the best one + static tString BestMethod( char const * a, char const * b ); + // scramble a password using this - void Scramble( tString const & password, nScrambledPassword & scrambled ) const; + void ScramblePassword( nScrambleInfo const & info, tString const & password, nScrambledPassword & scrambled ) const; + //! scramble a password hash with a salt + void ScrambleWithSalt( nScrambleInfo const & info, nScrambledPassword const & scrambled, nSalt const & salt, nScrambledPassword & result ) const; + + //! fetch NULL-terminated list of locally supported methods + static nMethod const * const * LocalMethods(); + + //! fetch best local method supported by the client + static bool BestLocalMethod( char const * supportedOnClient, nMethod & result ); + + //! compare two methods + static bool Equal( nMethod const & a, nMethod const & b ); + nMethod(){} + // construct a method from the type and a stream with properties + // the stream is supposed to consist of lines of the "property_name property_value" form. + nMethod( char const * method_, std::istream & properties ); + nMethod( char const * method_, char const * prefix_ = "", char const * suffix_ = ""); }; @@ -120,8 +175,9 @@ tJUST_CONTROLLED_PTR< nNetObject > user; // net object identifying the user (will be ePlayerNetID, but we don't know about that here) bool aborted; // did the user abort the operation? - nCheckResult() - : aborted( false ){} + nCheckResult(); + ~nCheckResult(); + nCheckResult( nCheckResult const & other ); }; // encode scrambled passwords and salts as hexcode strings @@ -168,7 +224,7 @@ nScrambledPassword &scrambled); // scramble it again before transfering it over the network - static void ScrambleWithSalt(const nScrambledPassword& source, + static void ScrambleWithSalt2(const nScrambledPassword& source, const nSalt& salt, nScrambledPassword& dest); @@ -183,8 +239,8 @@ nSalt const & salt, nMethod const & method ); - // fetches an URL content, return http return code (-1 if total failure), fill result stream - static int FetchURL( tString const & authority, char const * query, std::ostream & target ); + // fetches an URL content, return http return code (-1 if total failure), fill result stream. + static int FetchURL( tString const & authority, char const * query, std::ostream & target, int maxlen = 10000 ); #ifdef KRAWALL_SERVER_LEAGUE // secret key to encrypt server->master server league transfer Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp 2008-01-22 15:19:52 UTC (rev 7586) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp 2008-01-22 15:33:47 UTC (rev 7587) @@ -42,29 +42,97 @@ #include <vector> #include <map> -#ifdef KRAWALL_SERVER - #include <libxml/nanohttp.h> -static nKrawall::nMethod sn_bmd5("bmd5"), md5("md5"); +static nKrawall::nMethod sn_bmd5("bmd5"), sn_md5("md5"); +//! fetch NULL-terminated list of locally supported methods +nKrawall::nMethod const * const * nKrawall::nMethod::LocalMethods() +{ + static nMethod const * methods[] = + { + &sn_md5, + &sn_bmd5, + NULL + }; + + return methods; +} + +#ifdef KRAWALL_SERVER + // crude login structure with not too many feathres struct nLogin { tString authority_; - tString password_; - nKrawall::nScrambledPassword brokenScrambledPassword_; - nKrawall::nScrambledPassword scrambledPassword_; - nLogin( char const * authority, tString const & password ) + // scrambled passwords according to our various methods + std::map< tString, nKrawall::nScrambledPassword > scrambledPasswords_; + + nLogin( char const * authority, tString const & password, tString const & username ) : authority_( authority ) { // scramble the password before storing it (in case an evil attacker can read our memory, // but not the configuration file where they are stored in plain text :) ) - nKrawall::BrokenScramblePassword( password, brokenScrambledPassword_ ); - nKrawall::ScramblePassword( password, scrambledPassword_ ); + nKrawall::nMethod const * const * run = nKrawall::nMethod::LocalMethods(); + while ( * run ) + { + if ( username.Len() <= 1 && ( (*run)->prefix.Len() > 1 || (*run)->suffix.Len() > 1 ) ) + { + static bool warn = true; + if ( warn ) + { + warn = false; + con << "WARNING: local logins that use prefix or suffix do not work with team accounts.\n"; + } + } + + (*run)->ScramblePassword( nKrawall::nScrambleInfo( username ), password, scrambledPasswords_[ (*run)->method ] ); + + ++run; + } } + // check whether a scrambled password sent by a client is correct + bool CheckPassword( nKrawall::nScrambleInfo const & info, nKrawall::nMethod const & method, nKrawall::nSalt const & salt, nKrawall::nScrambledPassword const & hash, tString & error ) const + { + // find the correct scrambled password + std::map< tString, nKrawall::nScrambledPassword >::const_iterator scrambled = scrambledPasswords_.find( method.method ); + if ( scrambled != scrambledPasswords_.end() ) + { + // check whether methods match exactly + nKrawall::nMethod const * const * run = nKrawall::nMethod::LocalMethods(); + while ( * run ) + { + nKrawall::nMethod const & compare = **run; + if ( compare.method == method.method && !nKrawall::nMethod::Equal(compare, method ) ) + { + error = tOutput( "$login_error_methodmismatch" ); + return false; + } + + ++run; + } + + // compare passwords + nKrawall::nScrambledPassword scrambledCorrect; + method.ScrambleWithSalt( info, (*scrambled).second, salt, scrambledCorrect ); + bool ret = nKrawall::ArePasswordsEqual( hash, scrambledCorrect ); + if ( !ret ) + { + error = tOutput( "$login_error_local_password", info.username ); + } + return ret; + } + else + { + error = "Internal error, local method not found."; + return false; + } + + return false; + } + nLogin() { } @@ -91,7 +159,7 @@ tConfItemBase::EatWhitespace(s); password.ReadLine(s); - sn_exactLogins[ username ] = nLogin( "admin", password ); + sn_exactLogins[ username ] = nLogin( "admin", password, username ); } static tConfItemFunc sn_kpa( "MD5_PASSWORD_ADMIN", sn_ReadAdminPassword ); @@ -109,7 +177,7 @@ tConfItemBase::EatWhitespace(s); password.ReadLine(s); - sn_exactLogins[ username ] = nLogin( "user", password ); + sn_exactLogins[ username ] = nLogin( "user", password, username ); } static tConfItemFunc sn_kpu( "MD5_PASSWORD_USER", sn_ReadUserPassword ); @@ -127,7 +195,7 @@ tConfItemBase::EatWhitespace(s); password.ReadLine(s); - sn_partialLogins[ username ] = nLogin( tString("team_") + username, password ); + sn_partialLogins[ username ] = nLogin( tString("team_") + username, password, tString("") ); } static tConfItemFunc sn_kta( "MD5_PASSWORD_TEAM", sn_ReadTeamPassword ); @@ -145,7 +213,7 @@ tConfItemBase::EatWhitespace(s); password.ReadLine(s); - sn_exactLogins[ username ] = nLogin( tString("teamleader_") + username, password ); + sn_exactLogins[ username ] = nLogin( tString("teamleader_") + username, password, username ); } static tConfItemFunc sn_ktla( "MD5_PASSWORD_TEAMLEADER", sn_ReadTeamleaderPassword ); @@ -228,55 +296,43 @@ if ( !login ) { result.success = false; - result.error = tString( "Local user " ) + result.username + " not found."; + result.error = tOutput( "$login_error_local_nouser", result.username ); return; } // store relevant authority result.authority = login->authority_; - // compare passwords - nScrambledPassword scrambledCorrect; - ScrambleWithSalt( login->scrambledPassword_, salt, scrambledCorrect ); - result.success = ArePasswordsEqual( hash, scrambledCorrect ); + // check password + result.success = login->CheckPassword( nScrambleInfo( result.username ), method, salt, hash, result.error ); + return; } else { - // remote users: build md5 query URL - std::ostringstream fullURL; - fullURL << "http://" << result.authority << "/hashauth/bmd5"; - // fullURL << "?query=password"; - // fullURL << "http://authentication.armagetronad.net/hashauth.php"; - fullURL << "?method=bmd5"; - fullURL << "&user=" << result.username; - fullURL << "&salt=" << EncodeScrambledPassword( salt ); - fullURL << "&hash=" << EncodeScrambledPassword( hash ); + // remote users: build query URL + std::ostringstream request; + + request << "?method=" << method.method; + request << "&user=" << result.username; + request << "&salt=" << EncodeScrambledPassword( salt ); + request << "&hash=" << EncodeScrambledPassword( hash ); - // better not. output is not thread safe. - // con << "Fetching authentication URL " << fullURL.str() << "\n"; + // read URL content + std::ostringstream content; + int rc = FetchURL( result.authority, request.str().c_str(), content ); - // fetch URL - void * ctxt = xmlNanoHTTPOpen(fullURL.str().c_str(), NULL); - if (ctxt == NULL) + if (rc == -1) { result.error = tOutput( "$login_error_invalidurl", result.authority ); result.success = false; return; } + + // evil! + char * buf = const_cast< char * >( content.str().c_str() ); + unsigned int len = strlen(buf); - int rc = xmlNanoHTTPReturnCode(ctxt); - - // read content - char buf[1000]; - buf[0] = 0; - unsigned int len = xmlNanoHTTPRead( ctxt, &buf, sizeof(buf) ); - if ( len >= sizeof(buf) ) - { - len = sizeof(buf)-1; - } - xmlNanoHTTPClose(ctxt); - // get rid of newlines for ( unsigned int i = 0; i < len; ++i ) { @@ -312,10 +368,6 @@ return; } - if ( len >= sizeof(buf) ) - len = sizeof(buf) - 1; - buf[len] = 0; - char const * expected = "PASSWORD_OK"; result.success = ( strncmp( expected , buf, strlen(expected) ) == 0 ); if ( !result.success ) @@ -327,13 +379,16 @@ } } -int nKrawall::FetchURL( tString const & authority, char const * query, std::ostream & target ) +int nKrawall::FetchURL( tString const & authority, char const * query, std::ostream & target, int maxlen ) { // compose real URL std::ostringstream fullURL; fullURL << "http://" << authority << "/hashauth/bmd5"; fullURL << query; + // better not. output is not thread safe. + // con << "Fetching authentication URL " << fullURL.str() << "\n"; + // fetch URL void * ctxt = xmlNanoHTTPOpen( fullURL.str().c_str(), NULL); if (ctxt == NULL) @@ -347,10 +402,14 @@ char buf[1000]; buf[0] = 0; unsigned int len = 1; - while ( len > 0 ) + while ( len > 0 && maxlen > 0 ) { - len = xmlNanoHTTPRead( ctxt, &buf, sizeof(buf) ); + int max = sizeof(buf); + if ( max > maxlen ) + max = maxlen; + len = xmlNanoHTTPRead( ctxt, &buf, max ); target.write( buf, len ); + maxlen -= len; } xmlNanoHTTPClose(ctxt); Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nNetwork.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nNetwork.cpp 2008-01-22 15:19:52 UTC (rev 7586) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nNetwork.cpp 2008-01-22 15:33:47 UTC (rev 7587) @@ -1725,7 +1725,7 @@ m >> ver; // read peer supported authentication methods (fallback to broken md5) - tString supportedAuthenticationMethods("bmd5,"); + tString supportedAuthenticationMethods("bmd5"); if ( !m.End() ) { m >> supportedAuthenticationMethods; Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nNetwork.h =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nNetwork.h 2008-01-22 15:19:52 UTC (rev 7586) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nNetwork.h 2008-01-22 15:33:47 UTC (rev 7587) @@ -298,7 +298,7 @@ // authentication // tString userName; - // supported authentication methods of the client in a comma separated list ending in an additional comma (for lazy parsing) + // supported authentication methods of the client in a comma separated list tString supportedAuthenticationMethods_; nConnectionInfo(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <z-...@us...> - 2008-01-23 16:09:40
|
Revision: 7605 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7605&view=rev Author: z-man Date: 2008-01-23 08:08:21 -0800 (Wed, 23 Jan 2008) Log Message: ----------- Sanity checking authority URL; appending default .armagetronad.net. Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp Modified: armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-23 15:23:04 UTC (rev 7604) +++ armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-23 16:08:21 UTC (rev 7605) @@ -2478,7 +2478,11 @@ # various reasons for logins to fail login_error_aborted Login aborted. -login_error_invalidurl Authentication URL \1 invalid. +login_error_invalidurl_illegal_hostname Authentication URL \1 invalid, illegal characters in hostname part (only ASCII letters, numbers and dots allowed). +login_error_invalidurl_illegal_path Authentication URL \1 invalid, illegal characters in path part (only ASCII letters, numbers, dots and slashes allowed). +login_error_invalidurl_illegal_port Authentication URL \1 invalid, illegal characters in port(only numbers are allowed). +login_error_invalidurl_slash Authentication URL \1 invalid, double slash or ending with slash. +login_error_invalidurl_notfound Authentication URL \1 invalid, it was not found. login_error_methodmismatch The local method used for auhtentication has been modified since your password was set. In the server's config files, put all commands that define authentication methods before all local password definitions. login_error_nomethod No authentication method could be found. Your client supports \1, this server supports \2, and the authentication server supports \3. login_error_nomethodlist Authentication URL \1 does not return a list of supported methods. Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp 2008-01-23 15:23:04 UTC (rev 7604) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp 2008-01-23 16:08:21 UTC (rev 7605) @@ -377,6 +377,8 @@ // fetches info from local authority bool FetchInfoFromAuthorityLocal(); + tString fullAuthority; //!< full authority with maybe armagetronad.net appended. + tString message; //!< message to present to user nKrawall::nMethod method; //!< method of authentication @@ -432,9 +434,103 @@ #endif { + // the hostname part of the authority should not contain uppercase letters + { + std::istringstream in( static_cast< const char * >( authority ) ); + std::ostringstream out; + int c = in.get(); + + // does the authority contain a .? + bool dot = false; + bool inHostName = true; + bool inPort = false; + bool slash = false; + + while( !in.eof() ) + { + if ( inHostName ) + { + // check validity of hostname part + if ( c == '.' ) + { + dot = true; + } + else if ( isalnum(c) ) + { + c = tolower(c); + } + else + { + return ReportAuthorityError( tOutput( "$login_error_invalidurl_illegal_hostname", authority ) ); + } + if ( c == ':' ) + { + inPort = true; + inHostName = false; + } + if ( c == '/' ) + { + slash = true; + inHostName = false; + } + } + else if ( inPort ) + { + if ( c == '/' ) + { + inPort = false; + slash = true; + } + else if ( !isdigit( c ) ) + { + return ReportAuthorityError( tOutput( "$login_error_invalidurl_illegal_port", authority ) ); + } + } + else // must be in path + { + if ( c == '/' ) + { + if ( slash ) + { + return ReportAuthorityError( tOutput( "$login_error_invalidurl_slash", authority ) ); + } + + slash = true; + } + else + { + if (!isalnum(c) && c != '.' ) + { + return ReportAuthorityError( tOutput( "$login_error_invalidurl_illegal_path", authority ) ); + } + + slash = false; + } + } + + out.put(c); + + c = in.get(); + } + if ( slash ) + { + return ReportAuthorityError( tOutput( "$login_error_invalidurl_slash", authority ) ); + } + + authority = out.str().c_str(); + + fullAuthority = authority; + + // append default authority path + if ( authority.Len() > 1 && !dot ) + { + fullAuthority += ".armagetronad.net"; + } + } + // try yo find a better method, fetch method list std::stringstream answer; - int rc = nKrawall::FetchURL( authority, "", answer ); + int rc = nKrawall::FetchURL( fullAuthority, "", answer ); if ( rc == -1 ) { @@ -478,7 +574,7 @@ std::ostringstream query; query << "?method=" << nKrawall::EncodeString( method.method ); std::ostringstream data; - int rc = nKrawall::FetchURL( authority, query.str().c_str(), data ); + int rc = nKrawall::FetchURL( fullAuthority, query.str().c_str(), data ); if ( rc != 200 ) { @@ -590,7 +686,10 @@ } else { + tString shortAuthority = authority; + authority = fullAuthority; nKrawall::CheckScrambledPassword( *this, hash, salt, method ); + authority = shortAuthority; } Abort(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <z-...@us...> - 2008-01-23 16:53:47
|
Revision: 7607 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7607&view=rev Author: z-man Date: 2008-01-23 08:53:46 -0800 (Wed, 23 Jan 2008) Log Message: ----------- Filtering port, only to realize that nanohttp does not handle the port correctly anyway. Lowercasing the file path part of the authority for reference, lookup is done with the original. Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp Modified: armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-23 16:20:57 UTC (rev 7606) +++ armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-23 16:53:46 UTC (rev 7607) @@ -2480,7 +2480,8 @@ login_error_aborted Login aborted. login_error_invalidurl_illegal_hostname Authentication URL \1 invalid, illegal characters in hostname part (only ASCII letters, numbers and dots allowed). login_error_invalidurl_illegal_path Authentication URL \1 invalid, illegal characters in path part (only ASCII letters, numbers, dots and slashes allowed). -login_error_invalidurl_illegal_port Authentication URL \1 invalid, illegal characters in port(only numbers are allowed). +login_error_invalidurl_illegal_port Authentication URL \1 invalid, illegal characters in port (only numbers are allowed). +login_error_invalidurl_defaultport Authentication URL \1 invalid. Just leave away the default port, please :). login_error_invalidurl_slash Authentication URL \1 invalid, double slash or ending with slash. login_error_invalidurl_notfound Authentication URL \1 invalid, it was not found. login_error_methodmismatch The local method used for auhtentication has been modified since your password was set. In the server's config files, put all commands that define authentication methods before all local password definitions. Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp 2008-01-23 16:20:57 UTC (rev 7606) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp 2008-01-23 16:53:46 UTC (rev 7607) @@ -334,11 +334,14 @@ bool ReportAuthorityError( tOutput const & error ) { // well, the public scripts don't support this yet, so let's fake it - method.method = "bmd5"; - method.prefix = ""; - method.suffix = ""; - return true; - + if ( 0 ) + { + method.method = "bmd5"; + method.prefix = ""; + method.suffix = ""; + return true; + } + // true code follows: // prepare failure report @@ -437,7 +440,8 @@ // the hostname part of the authority should not contain uppercase letters { std::istringstream in( static_cast< const char * >( authority ) ); - std::ostringstream out; + std::ostringstream outShort; // stream for shorthand authority + std::ostringstream outFull; // stream for full authority URL that is to be used for lookups int c = in.get(); // does the authority contain a .? @@ -445,6 +449,7 @@ bool inHostName = true; bool inPort = false; bool slash = false; + int port = 0; while( !in.eof() ) { @@ -459,20 +464,20 @@ { c = tolower(c); } - else + else if ( c == ':' ) { - return ReportAuthorityError( tOutput( "$login_error_invalidurl_illegal_hostname", authority ) ); - } - if ( c == ':' ) - { inPort = true; inHostName = false; } - if ( c == '/' ) + else if ( c == '/' ) { slash = true; inHostName = false; } + else + { + return ReportAuthorityError( tOutput( "$login_error_invalidurl_illegal_hostname", authority ) ); + } } else if ( inPort ) { @@ -485,6 +490,11 @@ { return ReportAuthorityError( tOutput( "$login_error_invalidurl_illegal_port", authority ) ); } + else + { + port *= 10; + port += c - '0'; + } } else // must be in path { @@ -508,7 +518,10 @@ } } - out.put(c); + // shorthand authority must consist of lowercase letters only + outShort.put(tolower(c)); + + outFull.put(c); c = in.get(); } @@ -516,11 +529,22 @@ { return ReportAuthorityError( tOutput( "$login_error_invalidurl_slash", authority ) ); } + if ( port == 80 ) + { + return ReportAuthorityError( tOutput( "$login_error_invalidurl_defaultport", authority ) ); + } - authority = out.str().c_str(); + authority = outShort.str().c_str(); + fullAuthority = outFull.str().c_str(); static const char * def = ".authentication.armagetronad.net"; + // append default authority path + if ( authority.Len() > 1 && !dot ) + { + fullAuthority += def; + } + // check if the pased authority contains the default ending if ( dot && authority.Reverse().StartsWith( tString( def ).Reverse() ) ) { @@ -528,14 +552,6 @@ authority = authority.SubStr( 0, authority.Len() - strlen( def ) - 1 ); dot = false; } - - fullAuthority = authority; - - // append default authority path - if ( authority.Len() > 1 && !dot ) - { - fullAuthority += def; - } } // try yo find a better method, fetch method list @@ -544,7 +560,7 @@ if ( rc == -1 ) { - return ReportAuthorityError( tOutput( "$login_error_invalidurl", authority ) ); + return ReportAuthorityError( tOutput( "$login_error_invalidurl_notfound", authority ) ); } std::string id; @@ -590,7 +606,7 @@ { if ( rc == -1 ) { - return ReportAuthorityError( tOutput( "$login_error_invalidurl", authority ) ); + return ReportAuthorityError( tOutput( "$login_error_invalidurl_notfound", authority ) ); } return ReportAuthorityError( tOutput( "$login_error_nomethodproperties", authority ) ); Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp 2008-01-23 16:20:57 UTC (rev 7606) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp 2008-01-23 16:53:46 UTC (rev 7607) @@ -324,7 +324,7 @@ if (rc == -1) { - result.error = tOutput( "$login_error_invalidurl", result.authority ); + result.error = tOutput( "$login_error_invalidurl_notfound", result.authority ); result.success = false; return; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <z-...@us...> - 2008-01-23 19:28:24
|
Revision: 7609 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7609&view=rev Author: z-man Date: 2008-01-23 11:27:20 -0800 (Wed, 23 Jan 2008) Log Message: ----------- Less braindead handling of player names. Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gAIBase.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gGame.cpp Modified: armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-23 17:00:13 UTC (rev 7608) +++ armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-23 19:27:20 UTC (rev 7609) @@ -2472,8 +2472,8 @@ login_request_namechange Name changed. Login required. login_request_master Master server requires Login. -login_message \1 has been logged in by the power of authority \2.\n -logout_message \1 has been logged out of authority \2.\n +login_message \1 has been logged in as \2.\n +logout_message \1 has been logged out as \2.\n login_failed_message 0xff7f7fLogin failed,0xffffff reason: \1\n # various reasons for logins to fail Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-23 17:00:13 UTC (rev 7608) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-23 19:27:20 UTC (rev 7609) @@ -81,9 +81,127 @@ PasswordStorage(): save(false){}; }; - static tArray<PasswordStorage> S_passwords; +// if set, user names of non-authenticated players are left as they are, +// and usernames of authenticated players get a 0: prepended. +// if unsed, usernames of non-authenticated players get all special characters escaped (especially all @) +// and usernames of authenticated players get left as they are (with all special characters except the last +// escaped.) +bool se_legacyLogNames = true; +static tSettingItem<bool> se_llnConf("LEGACY_LOG_NAMES", se_legacyLogNames ); + +// transform special characters in name to escape sequences +static std::string se_EscapeName( tString const & original, bool keepLastAt = true ) +{ + std::ostringstream filter; + + int lastAt = original.Len(); + if ( keepLastAt ) + { + for( int i = original.Len()-2; i >=0 ; --i ) + { + if ( original[i] == '@' ) + { + lastAt = i; + break; + } + } + } + + int lastC = 'x'; + for( int i = 0; i < original.Len()-1; ++i ) + { + int c = original[i]; + + // a valid character + switch (c) + { + // characters to escape + case ' ': + filter << "\\_"; + break; + case '@': + if ( keepLastAt && i == lastAt ) + { + filter << '@'; + } + else + { + filter << "\\@"; + } + break; + case '\\': + case '%': + case ':': + filter.put('\\'); + filter.put(c); + break; + case 'x': + // color codes? + if ( lastC == '0' ) + { + filter << "\\x"; + break; + } + default: + if ( 0x20 < c && 0x7f >= c ) + { + // normal ascii, print + filter.put(c); + } + else + { + // encode as hexcode + filter << std::hex << std::uppercase << std::setfill('0') << std::setw(2) << c; + } + } + + lastC = c; + } + + // done! wrap up stream as string. + return filter.str(); +} + +// generate the user name for an unauthenticated user +static tString se_UnauthenticatedUserName( tString const & name ) +{ + tString ret; + ePlayerNetID::FilterName( name, ret ); + if ( se_legacyLogNames ) + { + return ret; + } + else + { + return tString( se_EscapeName( ret, false ).c_str() ); + } +} + +// split a fully qualified user name in authority and username part +#ifdef DEDICATED +#ifdef KRAWALL_SERVER +static void se_SplitName( tString const & original, tString & username, tString & authority ) +{ + std::ostringstream filter; + + for( int i = original.Len()-2; i >=0 ; --i ) + { + if ( original[i] == '@' ) + { + username = original.SubStr( 0, i ); + authority = original.SubStr( i+1, original.Len() - i -2 ); + return; + } + } + + username = original; + authority = ""; +} +#endif +#endif + void se_DeletePasswords(){ S_passwords.SetLen(0); @@ -255,6 +373,7 @@ } // find the player with the given username: + /* ePlayer* p = NULL; for (i = MAX_PLAYERS-1; i>=0 && !p; i--) { @@ -276,6 +395,7 @@ // or just any player, what the heck. if (!p) p = ePlayer::PlayerConfig(0); + */ // try to find the username in the saved passwords tString methodCongested = request.method + '|' + request.prefix + '|' + request.suffix; @@ -373,8 +493,8 @@ #ifdef DEDICATED static void se_AdminLogin( ePlayerNetID * p ) { - p->beLoggedIn(); - p->setAccessLevel(1); + p->BeLoggedIn(); + sn_ConsoleOut("You have been logged in!\n",p->Owner()); tString serverLoginMessage; serverLoginMessage << "Remote admin login for user \"" << p->GetUserName() << "\" accepted.\n"; @@ -402,7 +522,7 @@ for ( int i = se_PlayerNetIDs.Len()-1; i>=0; --i ) { ePlayerNetID* player = se_PlayerNetIDs(i); - if ( player->auth && player->IsHuman() ) + if ( player->IsAuthenticated() && player->IsHuman() ) { return true; } @@ -440,9 +560,7 @@ if (success) { - player->IsAuth(); - player->SetUserName(username); - player->Auth(authority); + player->Authenticate(username + "@" + authority); #ifdef DEDICATED if ( authority == "admin" ) @@ -904,7 +1022,7 @@ } #ifdef DEDICATED -#ifdef KRAWALL_SERVER +#ifdef KRAWALL_SERVER_BLA static ePlayerNetID * se_FindPlayerInChatCommand( ePlayerNetID * sender, char const * command, tString const & say ) { tString params(""); @@ -1330,27 +1448,33 @@ return; } #endif + tString userName = p->GetUserName(); + if ( p->GetRawAuthenticatedName().Len() > 1 ) + { + tString authority; + se_SplitName( p->GetRawAuthenticatedName(), userName, authority ); + } + nAuthentification::RequestLogin(params,p->GetUserName(), *p, "$login_request_first"); } #endif } else if (say.StartsWith("/logout")) { - if ( p->isLoggedIn() ) +#ifdef KRAWALL_SERVER + // revoke the other kind of authentication as well + if ( se_authenticationRequiredToPlay < 2 && p->IsAuthenticated() ) { - sn_ConsoleOut("You have been logged out!\n",p->Owner()); + p->DeAuthenticate(); } - p->beNotLoggedIn(); - p->setAccessLevel(0); +#endif -#ifdef KRAWALL_SERVER - // revoke the other kind of authentication as well - if ( se_authenticationRequiredToPlay < 2 && p->IsAuth() ) + if ( p->IsLoggedIn() ) { - p->DeAuth(); + sn_ConsoleOut("You have been logged out!\n",p->Owner()); } -#endif + p->BeNotLoggedIn(); } -#ifdef KRAWALL_SERVER +#ifdef KRAWALL_SERVER_BLA else if (say.StartsWith("/pickup")) { tString const & auth = p->GetAuthority(); @@ -1397,7 +1521,7 @@ } #endif else if (say.StartsWith("/admin")) { - if (!p->isLoggedIn()) + if (!p->IsLoggedIn()) { sn_ConsoleOut("You are not logged in.\n",p->Owner()); return; @@ -1453,7 +1577,7 @@ // checks whether a player is silenced, giving him appropriate warnings if he is bool IsSilencedWithWarning( ePlayerNetID const * p ) { - if ( !se_enableChat && ! p->isLoggedIn() ) + if ( !se_enableChat && ! p->IsLoggedIn() ) { // everyone except the admins is silenced sn_ConsoleOut( tOutput( "$spam_protection_silenceall" ), p->Owner() ); @@ -1722,11 +1846,18 @@ tString tos; tos << p2->Owner(); tos << ": "; - tos << p2->GetUserName(); - if (p2->isLoggedIn()) + if ( p2->GetLastAccessLevel() < ePlayerNetID::AccessLevel_Default ) + { + // player username comes from authentication name and may be much different from + // the screen name + tos << p2->GetUserName() << " ( " << p2->GetName() << " )"; + } + else + { + tos << p2->GetUserName(); + } + if ( p2->IsLoggedIn() ) tos << " (logged in)"; - else - tos << " (logged out)"; tos << "\n"; sn_ConsoleOut(tos, p->Owner()); } @@ -2169,6 +2300,9 @@ ePlayerNetID::ePlayerNetID(int p):nNetObject(),listID(-1), teamListID(-1), allowTeamChange_(false), registeredMachine_(0), pID(p),chatSpam_( se_chatSpamSettings ) { + // default access level + lastAccessLevel = accessLevel = AccessLevel_Default; + favoriteNumberOfPlayersPerTeam = 1; nameTeamAfterMe = false; @@ -2176,7 +2310,6 @@ r = g = b = 15; greeted = true; - auth = true; chatting_ = false; spectating_ = false; chatFlags_ = 0; @@ -2218,10 +2351,6 @@ lastScore_=IMPOSSIBLY_LOW_SCORE; // rubberstatus=0; - //Remote Addmin add-ins... - loggedIn = false; - accessLevel = 0; - MyInitAfterCreation(); if(sn_GetNetState()==nSERVER) @@ -2234,6 +2363,9 @@ ePlayerNetID::ePlayerNetID(nMessage &m):nNetObject(m),listID(-1), teamListID(-1) , allowTeamChange_(false), registeredMachine_(0), chatSpam_( se_chatSpamSettings ) { + // default access level + lastAccessLevel = accessLevel = AccessLevel_Default; + greeted =false; chatting_ =false; spectating_ =false; @@ -2256,16 +2388,6 @@ score=0; lastScore_=IMPOSSIBLY_LOW_SCORE; // rubberstatus=0; - - //Remote Addmin add-ins... - loggedIn = false; - accessLevel = 0; - -#ifdef KRAWALL_SERVER - auth=false; -#else - auth=true; -#endif } void ePlayerNetID::Activity() @@ -2528,33 +2650,39 @@ return true; } -void ePlayerNetID::Auth( tString const & authority ){ - if ( !auth && IsHuman() ) +#ifdef KRAWALL_SERVER +void ePlayerNetID::Authenticate( tString const & authName ){ + if ( !IsAuthenticated() && IsHuman() ) { - sn_ConsoleOut( tOutput( "$login_message", GetUserName(), authority ) ); + sn_ConsoleOut( tOutput( "$login_message", GetName(), se_EscapeName( authName ).c_str() ) ); } - if ( !auth ) + + if ( !IsAuthenticated() ) { - auth = true; - authority_ = authority; - GetScoreFromDisconnectedCopy(); + accessLevel = AccessLevel_Authenticated; } + + rawAuthenticatedName_ = authName; + GetScoreFromDisconnectedCopy(); } -void ePlayerNetID::DeAuth(){ - if ( auth ) +void ePlayerNetID::DeAuthenticate(){ + if ( IsAuthenticated() ) { - sn_ConsoleOut( tOutput( "$logout_message", GetUserName(), authority_ ) ); + sn_ConsoleOut( tOutput( "$logout_message", GetName(), se_EscapeName( rawAuthenticatedName_ ).c_str() ) ); } - auth = false; - authority_ = ""; + // force falling back to regular user name on next update + + + accessLevel = AccessLevel_Program; } -bool ePlayerNetID::IsAuth() const +bool ePlayerNetID::IsAuthenticated() const { - return auth; + return int(accessLevel) <= int(AccessLevel_Authenticated); } +#endif // create our voter or find it void ePlayerNetID::CreateVoter() @@ -3267,7 +3395,7 @@ tString line("ONLINE_PLAYER "); - line << p->GetUserName(); + line << p->GetLogName(); if(p->IsActive()) { line << " " << p->ping; @@ -3758,7 +3886,7 @@ // find a copy for(i=se_PlayerNetIDs.Len()-1;i>=0;i--){ ePlayerNetID *pni=se_PlayerNetIDs(i); - if (pni->disconnected && pni->GetName() == GetName() && pni->GetAuthority() == GetAuthority() && pni->Owner() == 0) + if (pni->disconnected && pni->GetUserName() == GetUserName() && pni->Owner() == 0) { #ifdef DEBUG con << GetName() << " reconnected.\n"; @@ -4513,7 +4641,7 @@ tos << p2->Owner(); tos << ": "; tos << p2->GetUserName(); - if (p2->isLoggedIn()) + if (p2->IsLoggedIn()) tos << " (logged in)"; else tos << " (logged out)"; @@ -4569,6 +4697,44 @@ static gServerInfoAdmin sg_serverAdmin; +class eNameMessenger +{ +public: + eNameMessenger( ePlayerNetID & player ) + : player_( player ) + , oldScreenName_( player.GetName() ) + , oldLogName_( player.GetLogName() ) + { + } + + ~eNameMessenger() + { + tString logName = player_.GetLogName(); + tString const & screenName = player_.GetName(); + + if ( oldLogName_.Len() <= 1 && logName.Len() > 0 ) + { + if ( player_.IsHuman() ) + { + tString ladder; + ladder << "PLAYER_ENTERED " << logName << " " << nMachine::GetMachine(player_.Owner()).GetIP() << " " << screenName << "\n"; + se_SaveToLadderLog(ladder); + + player_.Greet(); + } + } + else if ( logName != oldLogName_ || screenName != oldScreenName_ ) + { + tString ladder; + ladder << "PLAYER_RENAMED " << oldLogName_ << " " << logName << " " << nMachine::GetMachine(player_.Owner()).GetIP() << " " << screenName << "\n"; + se_SaveToLadderLog(ladder); + } + } + + ePlayerNetID & player_; + tString oldScreenName_, oldLogName_; +}; + // ****************************************************************************************** // * // * UpdateName @@ -4583,6 +4749,9 @@ // don't do a thing if we're not fully synced if ( this->ID() == 0 && nameFromClient_.Len() <= 1 && sn_GetNetState() == nSERVER ) return; + + // monitor name changes + eNameMessenger messenger( *this ); // store old name for password re-request and name change message tColoredString oldprintname; @@ -4615,8 +4784,7 @@ // remove colors from name tString newName = tColoredString::RemoveColors( nameFromServer_ ); - tString newUserName; - FilterName( newName, newUserName ); + tString newUserName = se_UnauthenticatedUserName( newName ); // test if it is already taken, find an alternative name if so. if ( sn_GetNetState() != nCLIENT && !se_allowImposters && se_IsNameTaken( newUserName, this ) ) @@ -4637,7 +4805,7 @@ if ( testName.Len() > 17 ) testName = testName.SubStr( testName.Len() - 17 ); - FilterName( testName, newUserName ); + newUserName = se_UnauthenticatedUserName( testName ); if ( !se_IsNameTaken( newUserName, this ) ) { @@ -4656,13 +4824,13 @@ Color(r,g,b); coloredName_ << tColoredString::ColorString(r,g,b) << nameFromServer_; - if ( name_ != newName ) + if ( name_ != newName || lastAccessLevel != accessLevel ) { // copy it to the name, removing colors of course name_ = newName; // remove spaces and possibly other nasties for the user name - FilterName( name_, userName_ ); + userName_ = se_UnauthenticatedUserName( name_ ); if (sn_GetNetState()!=nCLIENT) { @@ -4685,23 +4853,9 @@ sn_ConsoleOut(mess); } - if ( IsHuman() ) - { - tString ladder; - ladder << "PLAYER_ENTERED " << userName_ << " " << nMachine::GetMachine(Owner()).GetIP() << "\n"; - se_SaveToLadderLog(ladder); - - Greet(); - } } else if (strcmp(oldUserName,GetUserName())) { -#ifdef KRAWALL_SERVER - if (sn_GetNetState() == nSERVER && Owner() != sn_myNetID ) - { - userName_ = oldUserName; // restore the old username - } -#endif mess << "$player_renamed"; if ( bool(this->voter_) ) @@ -4710,15 +4864,28 @@ } sn_ConsoleOut(mess); - - { - tString ladder; - ladder << "PLAYER_RENAMED " << oldUserName << " " << userName_ << " " << nMachine::GetMachine(Owner()).GetIP() << "\n"; - se_SaveToLadderLog(ladder); - } } } } + + // store access level for next update + lastAccessLevel = accessLevel; + +#ifdef KRAWALL_SERVER + // take the user name to be the authenticated name + if ( IsAuthenticated() ) + { + userName_ = se_EscapeName( rawAuthenticatedName_ ).c_str(); + if ( se_legacyLogNames ) + { + userName_ = tString( "0:" ) + userName_; + } + } + else + { + rawAuthenticatedName_ = ""; + } +#endif } // filters illegal player characters Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h 2008-01-23 17:00:13 UTC (rev 7608) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h 2008-01-23 19:27:20 UTC (rev 7609) @@ -114,7 +114,24 @@ friend class eTeam; friend class eNetGameObject; friend class tControlledPTR< ePlayerNetID >; + // access level. lower numeric values are better. +public: + enum AccessLevel + { + AccessLevel_Owner = 0, // the server owner + AccessLevel_Admin = 1, // one of his admins + AccessLevel_Moderator = 2, // one of the moderators + AccessLevel_TeamLeader = 3, // a team leader + AccessLevel_TeamMember = 4, // a team member + AccessLevel_Local = 5, // any user with a local account + AccessLevel_Authenticated = 6,// any user with a an account anywhere + AccessLevel_Program = 10, // a regular player + AccessLevel_Default = 10 + }; + +private: + int listID; // ID in the list of all players int teamListID; // ID in the list of the team @@ -133,7 +150,6 @@ int favoriteNumberOfPlayersPerTeam; // join team if number of players on it is less than this; create new team otherwise bool nameTeamAfterMe; // player prefers to call his team after his name - bool auth; // is this user authenticated? bool greeted; // did the server already greet him? bool disconnected; // did he disconnect from the game? @@ -147,9 +163,8 @@ bool allowTeamChange_; //!< allow team changes even if ALLOW_TEAM_CHANGE is disabled? //For improved remoteadmin - bool loggedIn; //Is this user logged in? - int accessLevel; //If so, what can they do? 0 is default, aka, guest - //but if they are not logged in, this should never be an issue + AccessLevel accessLevel; //!< admin access level of the current user + AccessLevel lastAccessLevel;//!< access level at the time of the last name update nMachine * registeredMachine_; //!< the machine the player is registered with void RegisterWithMachine(); //!< registers with a machine @@ -231,9 +246,13 @@ void ClearObject(); void Greet(); - void Auth( tString const & authority ); // make the authentification valid - void DeAuth(); // make the authentification invalid - bool IsAuth() const; // is the authentification valid? + +#ifdef KRAWALL_SERVER + void Authenticate( tString const & authName ); // make the authentification valid + void DeAuthenticate(); // make the authentification invalid + bool IsAuthenticated() const; // is the authentification valid? +#endif + bool IsActive() const { return !disconnected; } bool IsSilenced( void ) const { return silenced_; } @@ -294,11 +313,12 @@ virtual void TrailColor( REAL&r, REAL&g, REAL&b ) const; //Remote Admin add-ins... - bool isLoggedIn() const { return loggedIn; } - void beLoggedIn() { loggedIn = true; } - void beNotLoggedIn() { loggedIn = false; } - int getAccessLevel() const { return accessLevel; } - void setAccessLevel(int in) { accessLevel = in; } + bool IsLoggedIn() const { return (int)accessLevel < AccessLevel_Moderator; } + void BeLoggedIn() { accessLevel = AccessLevel_Admin; } + void BeNotLoggedIn() { accessLevel = AccessLevel_Program; } + AccessLevel GetAccessLevel() const { return accessLevel; } + AccessLevel GetLastAccessLevel() const { return lastAccessLevel; } + void SetAccessLevel( AccessLevel level ) { accessLevel = level; } void UpdateName(); //! update the player name from the client's wishes static void FilterName( tString const & in, tString & out ); //! filters a name (removes unprintables, color codes and spaces) @@ -309,8 +329,11 @@ tColoredString coloredName_; //! this player's name, cleared by the server. Use this for onscreen screen display. tString name_; //! this player's name without colors. tString userName_; //! this player's name, cleared for system logs. Use for writing to files or comparing with admin input. - tString authority_; //!< the authority the player is authenticated with +#ifdef KRAWALL_SERVER + tString rawAuthenticatedName_; //! the raw authenticated name in user@authority form. +#endif + REAL wait_; //! time in seconds WaitToLeaveChat() will wait for this player void MyInitAfterCreation(); @@ -331,11 +354,14 @@ inline tString const & GetName( void ) const; //!< Gets this player's name without colors. inline ePlayerNetID const & GetName( tString & name ) const; //!< Gets this player's name without colors. - inline tString const & GetAuthority( void ) const; //!< Gets this player's authority. - inline ePlayerNetID const & GetAuthority( tString & authority ) const; //!< Gets this player's authority. - inline tString const & GetUserName( void ) const; //!< Gets this player's name, cleared for system logs. Use for writing to files or comparing with admin input. + inline tString const & GetUserName( void ) const; //!< Gets this player's full name. Use for writing to files or comparing with admin input. inline ePlayerNetID const & GetUserName( tString & userName ) const; //!< Gets this player's name, cleared for system logs. Use for writing to files or comparing with admin input. + tString const & GetLogName( void ) const{ return GetUserName(); } //!< Gets this player's name, cleared for system logs (with escaped special characters). Use for writing to files. +#ifdef KRAWALL_SERVER + tString const & GetRawAuthenticatedName( void ) const{ return rawAuthenticatedName_; } //!< Gets the raw, unescaped authentication name +#endif + ePlayerNetID & SetName( tString const & name ); //!< Sets this player's name. Sets processed names (colored, username, nameFromCLient) as well. ePlayerNetID & SetName( char const * name ); //!< Sets this player's name. Sets processed names (colored, username, nameFromCLient) as well. inline ePlayerNetID & SetUserName( tString const & userName ); //!< Sets this player's name, cleared for system logs. Use for writing to files or comparing with admin input. The other names stay unaffected. @@ -515,38 +541,6 @@ // ****************************************************************************************** // * -// * GetAuthority -// * -// ****************************************************************************************** -//! -//! @return this player's authority. -//! -// ****************************************************************************************** - -tString const & ePlayerNetID::GetAuthority( void ) const -{ - return this->authority_; -} - -// ****************************************************************************************** -// * -// * GetAuthority -// * -// ****************************************************************************************** -//! -//! @param authority this player's authority to fill -//! @return A reference to this to allow chaining -//! -// ****************************************************************************************** - -ePlayerNetID const & ePlayerNetID::GetAuthority( tString & authority ) const -{ - authority = this->authority_; - return *this; -} - -// ****************************************************************************************** -// * // * GetUserName // * // ****************************************************************************************** Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gAIBase.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gAIBase.cpp 2008-01-23 17:00:13 UTC (rev 7608) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gAIBase.cpp 2008-01-23 19:27:20 UTC (rev 7609) @@ -1157,7 +1157,9 @@ NewObject(); // AI players don't need to log in - Auth( tString("ai") ); +#ifdef KRAWALL_SERVER + Authenticate( GetName() + "@" ); +#endif } void gAIPlayer::ConfigureAIs() // ai configuration menu Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gGame.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gGame.cpp 2008-01-23 17:00:13 UTC (rev 7608) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gGame.cpp 2008-01-23 19:27:20 UTC (rev 7609) @@ -1508,7 +1508,7 @@ #ifdef KRAWALL_SERVER // don't allow unknown players to play - if ( ePlayerNetID::AuthenticationRequiredToPlay() && !pni->IsAuth() ) + if ( ePlayerNetID::AuthenticationRequiredToPlay() && !pni->IsAuthenticated() ) continue; #endif @@ -3567,8 +3567,10 @@ deathTime=dt; } } - else if (p->IsAuth()) +#ifdef KRAWALL_SERVER + else if (p->IsAuthenticated()) notyetloggedin = false; +#endif } } else This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <z-...@us...> - 2008-01-24 02:12:26
|
Revision: 7611 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7611&view=rev Author: z-man Date: 2008-01-23 18:12:16 -0800 (Wed, 23 Jan 2008) Log Message: ----------- Added UI elements and non-chat based authentication initiation: in the player setup, there is a Global ID text item and an Auto Login toggle, and in the game menu, if on supporting servers, an Authenticate trigger. Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.h armagetronad/branches/0.2.8-auth/armagetronad/src/network/nConfig.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gAIBase.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gGame.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gMenus.cpp Modified: armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-23 21:08:39 UTC (rev 7610) +++ armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-24 02:12:16 UTC (rev 7611) @@ -312,6 +312,8 @@ #******************************************** player_name_confitem_help Player name +player_user_confitem_help Global player ID +auto_login_confitem_help Schould this player automatically request authentication? camcenter_help Center internal camera on driving direction start_cam_help Initial Camera start_fov_help Initial field of vision @@ -1501,12 +1503,18 @@ viewport_assign_text Assign Viewports to Players viewport_assign_help Which player's game is seen on which part of the screen? +player_authenticate_text Authentication +player_authenticate_help If you have a global ID, activating this menuitem will make you log in with it. You'll be prompted for a password, naturally. +player_authenticate_action Authentication requests have been sent to the server. You should be prompted for a password shortly.\n #player setup player_name_text Name: player_name_help The ... in "Winner: ... ". Use cursor <left>/<right>, delete, backspace and all the other keys. +player_global_id_text Global ID: +player_global_id_help If you have one, enter your global player ID here. If you have an account on the forums at forums.armagetronad.net, your ID will be your account name, followed by "@forums". Accounts on other community sites may give you a different ID. + player_input_text Input Configuration player_input_help Setup keyboard and mouse controls for this player. @@ -1534,6 +1542,9 @@ player_red_text Red: player_red_help Lets you choose the red component of your colour. +player_autologin_text Auto Login: +player_autologin_help When enabled, you will automatically initiate the (usually completely optional) login procedure as soon as you enter a server. + player_spectator_text Spectator Mode: player_spectator_help In spectator mode, you do not control a cycle; you just watch the game as if you were already dead. The other players will see you on the score table and you can chat with them, but you won't be spawned at the beginng of a round. @@ -2467,8 +2478,10 @@ password_help Password setting +login_request_redundant Already logged in. login_request_failed Login failed. Try again! -login_request_first Login required on this server. +login_request_failed_dup Two logins with the same account are not permitted. +login_request Login with Authority \1 login_request_namechange Name changed. Login required. login_request_master Master server requires Login. Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-23 21:08:39 UTC (rev 7610) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-24 02:12:16 UTC (rev 7611) @@ -167,7 +167,6 @@ } // split a fully qualified user name in authority and username part -#ifdef DEDICATED #ifdef KRAWALL_SERVER static void se_SplitName( tString const & original, tString & username, tString & authority ) { @@ -187,7 +186,6 @@ authority = ""; } #endif -#endif void se_DeletePasswords(){ S_passwords.SetLen(0); @@ -545,9 +543,22 @@ return; } + tString authName = username + "@" + authority; + + // seach for double login + for ( int i = se_PlayerNetIDs.Len()-1; i>=0; --i ) + { + ePlayerNetID* player = se_PlayerNetIDs(i); + if ( player->IsAuthenticated() && player->GetRawAuthenticatedName() == authName ) + { + sn_ConsoleOut( tOutput("$login_failed_message_dup"), player->Owner() ); + return; + } + } + if (success) { - player->Authenticate(username + "@" + authority); + player->Authenticate( authName ); #ifdef DEDICATED if ( authority == "admin" ) @@ -570,6 +581,9 @@ } } } + + // continue with scheduled logon messages + ePlayerNetID::RequestScheduledLogins(); } #endif @@ -753,6 +767,19 @@ name)); confname.Clear(); + confname << "USER_"<< id+1; + StoreConfitem(tNEW(tConfItemLine) (confname, + "$player_user_confitem_help", + globalID)); + + confname.Clear(); + confname << "AUTO_LOGIN_"<< id+1; + StoreConfitem(tNEW(tConfItem<bool>)(confname, + "$auto_login_help", + autoLogin)); + autoLogin = false; + + confname.Clear(); confname << "CAMCENTER_"<< id+1; centerIncamOnTurn=true; StoreConfitem(tNEW(tConfItem<bool>) @@ -890,6 +917,133 @@ } #endif +static void se_RequestLogin( ePlayerNetID * p ); + +// receive a "login wanted" message from client +static void se_LoginWanted( nMessage & m ) +{ +#ifdef KRAWALL_SERVER + + // read player + ePlayerNetID * p; + m >> p; + + if ( p && m.SenderID() == p->Owner() && !p->IsAuthenticated() ) + { + // read wanted flag + m >> p->loginWanted; + tString authName; + + // read authentication name + m >> authName; + p->SetRawAuthenticatedName( authName ); + + se_RequestLogin( p ); + } +#endif +} + +static nDescriptor se_loginWanted(204,se_LoginWanted,"AuthWanted"); + +// request authentication initiation from the client (if p->loginWanted is set) +static void se_WantLogin( ePlayer * lp ) +{ + // only meaningful on client + if( sn_GetNetState() != nCLIENT ) + { + return; + } + + // don't send if the server won't understand anyway + static nVersionFeature authentication( 15 ); + if( !authentication.Supported(0) ) + { + return; + } + + tASSERT(lp); + ePlayerNetID *p = lp->netPlayer; + if ( !p ) + { + return; + } + + nMessage *m = new nMessage( se_loginWanted ); + + // write player + *m << p; + + // write flag and name + *m << p->loginWanted; + + // write authentication name + *m << lp->globalID; + + m->Send( 0 ); + + // reset flag + p->loginWanted = false; +} + +void ePlayer::SendAuthNames() +{ + // only meaningful on client + if( sn_GetNetState() != nCLIENT ) + { + return; + } + for(int i=MAX_PLAYERS-1;i>=0;i--) + { + se_WantLogin( ePlayer::PlayerConfig(i) ); + } +} + +// on the server, this should request logins from all players who registered. +static void se_RequestLogin( ePlayerNetID * p ) +{ + tString userName = p->GetUserName(); + tString authority; + if ( p->Owner() != 0 && p->loginWanted ) + { +#ifdef KRAWALL_SERVER + if ( p->GetRawAuthenticatedName().Len() > 1 ) + { + se_SplitName( p->GetRawAuthenticatedName(), userName, authority ); + } + + p->loginWanted = !nAuthentification::RequestLogin( authority, userName, *p, tOutput( "$login_request", authority ) ); +#endif + } +} + +void ePlayerNetID::RequestScheduledLogins() +{ + for( int i = se_PlayerNetIDs.Len()-1; i>=0; --i ) + { + se_RequestLogin( se_PlayerNetIDs(i) ); + } +} + +void ePlayer::LogIn() +{ + // only meaningful on client + if( sn_GetNetState() != nCLIENT ) + { + return; + } + + // mark all players as wanting to log in + for(int i=MAX_PLAYERS-1;i>=0;i--) + { + ePlayer * lp = ePlayer::PlayerConfig(i); + if ( lp && lp->netPlayer ) + { + lp->netPlayer->loginWanted = true; + se_WantLogin( lp ); + } + } +} + static void se_DisplayChatLocally( ePlayerNetID* p, const tString& say ) { #ifdef DEBUG_X @@ -1435,14 +1589,29 @@ return; } #endif - tString userName = p->GetUserName(); - if ( p->GetRawAuthenticatedName().Len() > 1 ) + if ( p->IsAuthenticated() ) { - tString authority; - se_SplitName( p->GetRawAuthenticatedName(), userName, authority ); + sn_ConsoleOut( "$login_request_reduntant.", p->Owner() ); } + else + { + } - nAuthentification::RequestLogin(params,p->GetUserName(), *p, "$login_request_first"); + if ( p->GetRawAuthenticatedName().Len() <= 1 ) + { + if ( params.StrPos( "@" ) > 0 ) + { + p->SetRawAuthenticatedName( params ); + } + else + { + p->SetRawAuthenticatedName( p->GetUserName() + "@" + params ); + } + } + + p->loginWanted = true; + + se_RequestLogin( p ); } #endif } @@ -2302,6 +2471,9 @@ chatFlags_ = 0; disconnected = false; + loginWanted = false; + + if (p>=0){ ePlayer *P = ePlayer::PlayerConfig(p); if (P){ @@ -2312,6 +2484,8 @@ sg_ClampPingCharity(); pingCharity=::pingCharity; + + loginWanted = P->autoLogin; } } /* @@ -2371,6 +2545,8 @@ object=NULL; ping=sn_Connections[m.SenderID()].ping; lastSync=tSysTimeFloat(); + + loginWanted = false; score=0; lastScore_=IMPOSSIBLY_LOW_SCORE; @@ -2638,12 +2814,14 @@ } #ifdef KRAWALL_SERVER -void ePlayerNetID::Authenticate( tString const & authName ){ +void ePlayerNetID::Authenticate( tString const & authName ) +{ if ( !IsAuthenticated() && IsHuman() ) { sn_ConsoleOut( tOutput( "$login_message", GetName(), se_EscapeName( authName ).c_str() ) ); } + if ( !IsAuthenticated() ) { accessLevel = AccessLevel_Authenticated; Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h 2008-01-23 21:08:39 UTC (rev 7610) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h 2008-01-24 02:12:16 UTC (rev 7611) @@ -61,13 +61,16 @@ void StoreConfitem(tConfItemBase *c); void DeleteConfitems(); public: - tString name; + tString name; // the player's screen name + tString globalID; // the global ID of the player in user@authority form // REAL rubberstatus; bool centerIncamOnTurn; bool wobbleIncam; bool autoSwitchIncam; - bool spectate; + bool spectate; // shall this player always spectate? + bool autoLogin; // should the player always request authentication on servers? + bool nameTeamAfterMe; // player prefers to call his team after his name int favoriteNumberOfPlayersPerTeam; @@ -104,6 +107,9 @@ static rViewport * PlayerViewport(int p); + static void LogIn(); //!< sends authentication login messages for all local players + static void SendAuthNames(); //!< sends authentication names and authentication wishes for all local players + static void Init(); static void Exit(); }; @@ -192,6 +198,8 @@ double lastSync; //!< time of the last sync request double lastActivity_; //!< time of the last activity + bool loginWanted; //!< flag indicating whether this player currently wants to log on + nSpamProtection chatSpam_; ePlayerNetID(int p=-1); @@ -253,6 +261,8 @@ bool IsAuthenticated() const; // is the authentification valid? #endif + static void RequestScheduledLogins(); //!< initiates login processes for all pending wishes + bool IsActive() const { return !disconnected; } bool IsSilenced( void ) const { return silenced_; } @@ -360,6 +370,7 @@ tString const & GetLogName( void ) const{ return GetUserName(); } //!< Gets this player's name, cleared for system logs (with escaped special characters). Use for writing to files. #ifdef KRAWALL_SERVER tString const & GetRawAuthenticatedName( void ) const{ return rawAuthenticatedName_; } //!< Gets the raw, unescaped authentication name + void SetRawAuthenticatedName( tString const & name ){ if ( !IsAuthenticated()) rawAuthenticatedName_ = name; } //!< Sets the raw, unescaped authentication name #endif ePlayerNetID & SetName( tString const & name ); //!< Sets this player's name. Sets processed names (colored, username, nameFromCLient) as well. Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp 2008-01-23 21:08:39 UTC (rev 7610) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp 2008-01-24 02:12:16 UTC (rev 7611) @@ -31,6 +31,7 @@ #include "tMemManager.h" #include "tToDo.h" #include "tLocale.h" +#include "tRecorder.h" #include "tSysTime.h" #include <memory> @@ -221,7 +222,15 @@ #ifdef HAVE_LIBZTHREAD // schedule the task into a background thread static nExecutor executor; - executor.execute( ZThread::Task( new nMemberFunctionRunnerTemplate( object, function ) ) ); + if ( !tRecorder::IsRunning() ) + { + executor.execute( ZThread::Task( new nMemberFunctionRunnerTemplate( object, function ) ) ); + } + else + { + // don't start threads when we're recording, just do the task at the next opportunity + ScheduleForeground( object, function ); + } #else // execute it immedeately (object.*function)(); @@ -780,23 +789,25 @@ } // on the server: request user authentification from login slot -void nAuthentification::RequestLogin(const tString & authority, const tString& username, nNetObject & user, const tOutput& message ) +bool nAuthentification::RequestLogin(const tString & authority, const tString& username, nNetObject & user, const tOutput& message ) { #ifdef KRAWALL_SERVER int userID = user.Owner(); if ( userID <= 0 ) { - return; + return false; } // do nothing if there is another login in process for that client if ( nLoginProcess::Find( userID ) ) { - return; + return false; } // trigger function cascade bouncing between threads (new nLoginProcess( userID ))->Init( authority, username, user, tString(message) ); #endif + + return true; } Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.h =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.h 2008-01-23 21:08:39 UTC (rev 7610) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.h 2008-01-24 02:12:16 UTC (rev 7611) @@ -53,7 +53,7 @@ static void HandlePasswordAnswer (nMessage& m); // on the server: request user authentification from login slot - static void RequestLogin(const tString& authority, const tString& username, nNetObject & user, const tOutput& message ); + static bool RequestLogin(const tString& authority, const tString& username, nNetObject & user, const tOutput& message ); }; #endif Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nConfig.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nConfig.cpp 2008-01-23 21:08:39 UTC (rev 7610) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nConfig.cpp 2008-01-24 02:12:16 UTC (rev 7611) @@ -447,6 +447,7 @@ "0.2.8_alpha20060414", // 12 "0.2.8.2", // 13 "0.2.8.3_alpha", // 14 + "0.2.8.3_alpha_auth", // 15 0 }; Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gAIBase.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gAIBase.cpp 2008-01-23 21:08:39 UTC (rev 7610) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gAIBase.cpp 2008-01-24 02:12:16 UTC (rev 7611) @@ -1155,11 +1155,6 @@ pingCharity = 300; NewObject(); - - // AI players don't need to log in -#ifdef KRAWALL_SERVER - Authenticate( GetName() + "@" ); -#endif } void gAIPlayer::ConfigureAIs() // ai configuration menu Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gGame.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gGame.cpp 2008-01-23 21:08:39 UTC (rev 7610) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gGame.cpp 2008-01-24 02:12:16 UTC (rev 7611) @@ -1508,7 +1508,7 @@ #ifdef KRAWALL_SERVER // don't allow unknown players to play - if ( ePlayerNetID::AuthenticationRequiredToPlay() && !pni->IsAuthenticated() ) + if ( ePlayerNetID::AuthenticationRequiredToPlay() && !pni->IsAuthenticated() && pni->IsHuman() ) continue; #endif @@ -2423,6 +2423,18 @@ void st_PrintPathInfo(tOutput &buf); +static void PlayerLogIn() +{ + ePlayer::LogIn(); + + if ( sg_IngameMenu ) + { + sg_IngameMenu->Exit(); + } + + con << tOutput( "$player_authenticate_action" ); +} + void sg_DisplayVersionInfo() { tOutput versionInfo; versionInfo << "$version_info_version" << "\n"; @@ -2509,6 +2521,16 @@ uMenuItemExit exx(&MainMenu,extitle, exhelp); + uMenuItemFunction * auth = 0; + static nVersionFeature authentication( 15 ); + if ( sn_GetNetState() == nCLIENT && ingame && authentication.Supported(0) ) + { + auth =tNEW(uMenuItemFunction)(&MainMenu, + "$player_authenticate_text", + "$player_authenticate_help", + &PlayerLogIn ); + } + uMenuItemFunction abb(&MainMenu, "$main_menu_about_text", "$main_menu_about_help", @@ -2668,6 +2690,11 @@ gLogo::SetDisplayed(false); sr_con.SetHeight(7); } + + if ( auth ) + { + delete auth; + } } @@ -4127,6 +4154,10 @@ { // synced finally. Send our player info over so we can join the game. ePlayerNetID::Update(); + + // and trigger the scheduled auto-logons. + ePlayer::SendAuthNames(); + synced_ = true; } Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gMenus.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gMenus.cpp 2008-01-23 21:08:39 UTC (rev 7610) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gMenus.cpp 2008-01-24 02:12:16 UTC (rev 7611) @@ -909,7 +909,16 @@ p->instantChatString[i], se_SpamMaxLen); } + uMenuItemToggle al + (&playerMenu,"$player_autologin_text", + "$player_autologin_help", + p->autoLogin); + uMenuItemString gid(&playerMenu, + "$player_global_id_text", + "$player_global_id_help", + p->globalID, 200); + uMenuItemToggle sp (&playerMenu,"$player_spectator_text", "$player_spectator_help", @@ -1048,7 +1057,10 @@ // request network synchronisation if the server can handle it static nVersionFeature inGameRenames( 5 ); if ( inGameRenames.Supported() ) + { ePlayerNetID::Update(); + ePlayer::SendAuthNames(); + } /* for (i=MAX_PLAYERS-1; i>=0; i--) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <z-...@us...> - 2008-01-24 02:28:19
|
Revision: 7612 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7612&view=rev Author: z-man Date: 2008-01-23 18:28:19 -0800 (Wed, 23 Jan 2008) Log Message: ----------- seperate message for local logons. Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp Modified: armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-24 02:12:16 UTC (rev 7611) +++ armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-24 02:28:19 UTC (rev 7612) @@ -2482,6 +2482,7 @@ login_request_failed Login failed. Try again! login_request_failed_dup Two logins with the same account are not permitted. login_request Login with Authority \1 +login_request_local Login with Local Account login_request_namechange Name changed. Login required. login_request_master Master server requires Login. Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-24 02:12:16 UTC (rev 7611) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-24 02:28:19 UTC (rev 7612) @@ -1011,7 +1011,11 @@ se_SplitName( p->GetRawAuthenticatedName(), userName, authority ); } - p->loginWanted = !nAuthentification::RequestLogin( authority, userName, *p, tOutput( "$login_request", authority ) ); + p->loginWanted = + !nAuthentification::RequestLogin( authority, + userName, + *p, + authority.Len() > 1 ? tOutput( "$login_request", authority ) : tOutput( "$login_request_local" ) ); #endif } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <z-...@us...> - 2008-01-24 02:35:07
|
Revision: 7613 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7613&view=rev Author: z-man Date: 2008-01-23 18:35:12 -0800 (Wed, 23 Jan 2008) Log Message: ----------- Better error messages. Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp Modified: armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-24 02:28:19 UTC (rev 7612) +++ armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-24 02:35:12 UTC (rev 7613) @@ -2481,6 +2481,7 @@ login_request_redundant Already logged in. login_request_failed Login failed. Try again! login_request_failed_dup Two logins with the same account are not permitted. +login_not_supported This server does not support authentication of the type you requested, sorry.\n login_request Login with Authority \1 login_request_local Login with Local Account login_request_namechange Name changed. Login required. Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-24 02:28:19 UTC (rev 7612) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-24 02:35:12 UTC (rev 7613) @@ -940,6 +940,8 @@ se_RequestLogin( p ); } +#else + sn_ConsoleOut( tOutput( "$login_not_supported" ), m.SenderID() ); #endif } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <z-...@us...> - 2008-01-24 09:55:44
|
Revision: 7614 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7614&view=rev Author: z-man Date: 2008-01-24 01:55:49 -0800 (Thu, 24 Jan 2008) Log Message: ----------- Added access levels to configuration system. Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.h Modified: armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-24 02:35:12 UTC (rev 7613) +++ armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-24 09:55:49 UTC (rev 7614) @@ -2445,7 +2445,20 @@ nconfig_error_ignoreold Ignoring old conf message for setting \1.\n nconfig_value_changed \1 changed from \2 to \3 on server order.\n +config_accesslevel_0 Owner +config_accesslevel_1 Administrator +config_accesslevel_2 Moderator +config_accesslevel_7 Team Leader +config_accesslevel_8 Team Member +config_accesslevel_9 Local User +config_accesslevel_10 Authenticated +config_accesslevel_20 Program +access_level_help Changes the access level of a configuration item to make it available to lower ranked users +access_level_usage usage: ACCESS_LEVEL <config command> <required minimal access level (numerical)>\n +access_level_change Required access level of command \1 changed to "\2".\n +access_level_error Required access level of command \1 is "\2", you only have "\3".\n + #************************************* #************************************* # Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-24 02:35:12 UTC (rev 7613) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-24 09:55:49 UTC (rev 7614) @@ -1550,6 +1550,9 @@ } void handle_chat_admin_commands(tJUST_CONTROLLED_PTR< ePlayerNetID > &p, tString say){ + // for the duration of this function, set the access level to the level of the user. + tCurrentAccessLevel levelOverride( p->GetAccessLevel() ); + if (say.StartsWith("/login")) { tString params(""); if (say.StrPos(" ") == -1) @@ -2008,7 +2011,7 @@ tString tos; tos << p2->Owner(); tos << ": "; - if ( p2->GetLastAccessLevel() < ePlayerNetID::AccessLevel_Default ) + if ( p2->GetLastAccessLevel() < tAccessLevel_Default ) { // player username comes from authentication name and may be much different from // the screen name @@ -2463,7 +2466,7 @@ ePlayerNetID::ePlayerNetID(int p):nNetObject(),listID(-1), teamListID(-1), allowTeamChange_(false), registeredMachine_(0), pID(p),chatSpam_( se_chatSpamSettings ) { // default access level - lastAccessLevel = accessLevel = AccessLevel_Default; + lastAccessLevel = accessLevel = tAccessLevel_Default; favoriteNumberOfPlayersPerTeam = 1; @@ -2531,7 +2534,7 @@ , allowTeamChange_(false), registeredMachine_(0), chatSpam_( se_chatSpamSettings ) { // default access level - lastAccessLevel = accessLevel = AccessLevel_Default; + lastAccessLevel = accessLevel = tAccessLevel_Default; greeted =false; chatting_ =false; @@ -2830,7 +2833,7 @@ if ( !IsAuthenticated() ) { - accessLevel = AccessLevel_Authenticated; + accessLevel = tAccessLevel_Authenticated; } rawAuthenticatedName_ = authName; @@ -2846,12 +2849,12 @@ // force falling back to regular user name on next update - accessLevel = AccessLevel_Program; + accessLevel = tAccessLevel_Default; } bool ePlayerNetID::IsAuthenticated() const { - return int(accessLevel) <= int(AccessLevel_Authenticated); + return int(accessLevel) <= int(tAccessLevel_Authenticated); } #endif Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h 2008-01-24 02:35:12 UTC (rev 7613) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h 2008-01-24 09:55:49 UTC (rev 7614) @@ -122,20 +122,6 @@ friend class tControlledPTR< ePlayerNetID >; // access level. lower numeric values are better. -public: - enum AccessLevel - { - AccessLevel_Owner = 0, // the server owner - AccessLevel_Admin = 1, // one of his admins - AccessLevel_Moderator = 2, // one of the moderators - AccessLevel_TeamLeader = 3, // a team leader - AccessLevel_TeamMember = 4, // a team member - AccessLevel_Local = 5, // any user with a local account - AccessLevel_Authenticated = 6,// any user with a an account anywhere - AccessLevel_Program = 10, // a regular player - AccessLevel_Default = 10 - }; - private: int listID; // ID in the list of all players @@ -169,8 +155,8 @@ bool allowTeamChange_; //!< allow team changes even if ALLOW_TEAM_CHANGE is disabled? //For improved remoteadmin - AccessLevel accessLevel; //!< admin access level of the current user - AccessLevel lastAccessLevel;//!< access level at the time of the last name update + tAccessLevel accessLevel; //!< admin access level of the current user + tAccessLevel lastAccessLevel;//!< access level at the time of the last name update nMachine * registeredMachine_; //!< the machine the player is registered with void RegisterWithMachine(); //!< registers with a machine @@ -323,12 +309,12 @@ virtual void TrailColor( REAL&r, REAL&g, REAL&b ) const; //Remote Admin add-ins... - bool IsLoggedIn() const { return (int)accessLevel < AccessLevel_Moderator; } - void BeLoggedIn() { accessLevel = AccessLevel_Admin; } - void BeNotLoggedIn() { accessLevel = AccessLevel_Program; } - AccessLevel GetAccessLevel() const { return accessLevel; } - AccessLevel GetLastAccessLevel() const { return lastAccessLevel; } - void SetAccessLevel( AccessLevel level ) { accessLevel = level; } + bool IsLoggedIn() const { return (int)accessLevel < tAccessLevel_Moderator; } + void BeLoggedIn() { accessLevel = tAccessLevel_Admin; } + void BeNotLoggedIn() { accessLevel = tAccessLevel_Program; } + tAccessLevel GetAccessLevel() const { return accessLevel; } + tAccessLevel GetLastAccessLevel() const { return lastAccessLevel; } + void SetAccessLevel( tAccessLevel level ) { accessLevel = level; } void UpdateName(); //! update the player name from the client's wishes static void FilterName( tString const & in, tString & out ); //! filters a name (removes unprintables, color codes and spaces) Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.cpp 2008-01-24 02:35:12 UTC (rev 7613) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.cpp 2008-01-24 09:55:49 UTC (rev 7614) @@ -144,6 +144,34 @@ bool tConfItemBase::printChange=true; bool tConfItemBase::printErrors=true; +//! for the lifetime of this object, change the user's admit level to the passed one. +tCurrentAccessLevel::tCurrentAccessLevel( tAccessLevel newLevel ) +{ + lastLevel_ = currentLevel_; + currentLevel_ = newLevel; +} + +tCurrentAccessLevel::~tCurrentAccessLevel() +{ + currentLevel_ = lastLevel_; +} + +//! returns the current access level +tAccessLevel tCurrentAccessLevel::GetAccessLevel() +{ + return currentLevel_; +} + +// returns the name of an access level +tString tCurrentAccessLevel::GetName( tAccessLevel level ) +{ + std::ostringstream s; + s << "$config_accesslevel_" << level; + return tString( tOutput( s.str().c_str() ) ); +} + +tAccessLevel tCurrentAccessLevel::currentLevel_ = tAccessLevel_Owner; //!< the current access level + static std::map< tString, tConfItemBase * > * st_confMap = 0; tConfItemBase::tConfItemMap & tConfItemBase::ConfItemMap() { @@ -152,6 +180,65 @@ return *st_confMap; } +// changes the access level of +class tConfItemLevel: public tConfItemBase +{ +public: + tConfItemLevel() + : tConfItemBase( "ACCESS_LEVEL" ) + { + } + + virtual void ReadVal(std::istream &s) + { + tString name; + s >> name; + + int levelInt; + s >> levelInt; + tAccessLevel level = static_cast< tAccessLevel >( levelInt ); + + if ( s.fail() ) + { + con << tOutput( "$access_level_usage" ); + return; + } + + // make name uppercase: + for(int i=name.Len()-1;i>=0;i--) + name[i]=toupper(name[i]); + + tConfItemMap & confmap = ConfItemMap(); + tConfItemMap::iterator iter = confmap.find( name ); + if ( iter != confmap.end() ) + { + tConfItemBase * ci = (*iter).second; + ci->requiredLevel = level; + con << tOutput( "$access_level_change", name, tCurrentAccessLevel::GetName( level ) ); + } + else + { + con << tOutput( "$config_command_unknown", name ); + } + } + + virtual void WriteVal(std::ostream &s) + { + tASSERT(0); + } + + virtual bool Writable(){ + return false; + } + + virtual bool Save(){ + return false; + } + +}; + +static tConfItemLevel st_confLevel; + bool st_FirstUse=true; static tConfItem<bool> fu("FIRST_USE",st_FirstUse); //static tConfItem<bool> fu("FIRST_USE","help_first_use",st_FirstUse); @@ -173,6 +260,8 @@ const_cast<tOutput&>(help).AddLocale(helpname); confmap[title] = this; + + requiredLevel = tAccessLevel_Admin; } tConfItemBase::tConfItemBase(const char *t, const tOutput& h) @@ -184,6 +273,8 @@ tERR_ERROR_INT("Two tConfItems with the same name " << t << "!"); confmap[title] = this; + + requiredLevel = tAccessLevel_Admin; } tConfItemBase::~tConfItemBase() @@ -254,11 +345,27 @@ bool cb=ci->changed; ci->changed=false; - ci->ReadVal(s); - if (ci->changed) - ci->WasChanged(); + + if ( ci->requiredLevel >= tCurrentAccessLevel::GetAccessLevel() ) + { + ci->ReadVal(s); + if (ci->changed) + ci->WasChanged(); + else + ci->changed=cb; + } else - ci->changed=cb; + { + tString discard; + discard.ReadLine(s); + + con << tOutput( "$access_level_error", + name, + tCurrentAccessLevel::GetName( ci->requiredLevel ), + tCurrentAccessLevel::GetName( tCurrentAccessLevel::GetAccessLevel() ) + ); + return; + } found=true; } Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.h =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.h 2008-01-24 02:35:12 UTC (rev 7613) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.h 2008-01-24 09:55:49 UTC (rev 7614) @@ -20,7 +20,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - + *************************************************************************** */ @@ -151,9 +151,46 @@ * The old stuff follows ************************************************************************/ +//! access levels for admin interfaces; lower numeric values are better +enum tAccessLevel +{ + tAccessLevel_Owner = 0, // the server owner + tAccessLevel_Admin = 1, // one of his admins + tAccessLevel_Moderator = 2, // one of the moderators + tAccessLevel_TeamLeader = 7, // a team leader + tAccessLevel_TeamMember = 8, // a team member + tAccessLevel_Local = 9, // any user with a local account + tAccessLevel_Authenticated = 10,// any user with a an account anywhere + tAccessLevel_Program = 20, // a regular player + tAccessLevel_Default = 20 +}; + +//! class managing the current access level +class tCurrentAccessLevel +{ +public: + //! for the lifetime of this object, change the user's admit level to the passed one. + tCurrentAccessLevel( tAccessLevel newLevel ); + ~tCurrentAccessLevel(); + + //! returns the current access level + static tAccessLevel GetAccessLevel(); + + //! returns the name of an access level + static tString GetName( tAccessLevel level ); +private: + tCurrentAccessLevel(); + tCurrentAccessLevel( tCurrentAccessLevel const & ); + tCurrentAccessLevel & operator = ( tCurrentAccessLevel const & ); + + tAccessLevel lastLevel_; //!< used to restore the last admin level when the object goes out of scope + static tAccessLevel currentLevel_; //!< the current access level +}; + class tConfItemBase { friend class tCheckedPTRBase; + friend class tConfItemLevel; int id; protected: @@ -161,6 +198,8 @@ const tOutput help; bool changed; + tAccessLevel requiredLevel; + typedef std::map< tString, tConfItemBase * > tConfItemMap; static tConfItemMap & ConfItemMap(); @@ -174,7 +213,9 @@ tConfItemBase(const char *title); virtual ~tConfItemBase(); - tString const & GetTitle() const { return title; } + tString const & GetTitle() const { + return title; + } static int EatWhitespace(std::istream &s); // eat whitespace from stream; return: first non-whitespace char @@ -189,9 +230,13 @@ virtual void WasChanged(){} // what to do if a read changed the thing - virtual bool Writable(){return true;} + virtual bool Writable(){ + return true; + } - virtual bool Save(){return true;} + virtual bool Save(){ + return true; + } }; // Arg! Msvc++ could not handle bool IO. Seems to be fine now. @@ -226,7 +271,7 @@ typedef STREAM TOSTREAM; \ typedef int * DUMMYREQUIRED; \ } \ - + //! macro for configuration enums: convert them to int. #define tCONFIG_ENUM( TYPE ) tCONFIG_AS( TYPE, int ) @@ -322,7 +367,7 @@ // read the rest of the line c=' '; - while(c!='\n' && s.good() && !s.eof()) c=s.get(); + while (c!='\n' && s.good() && !s.eof()) c=s.get(); } virtual void WriteVal(std::ostream &s){ @@ -340,7 +385,9 @@ virtual ~tSettingItem(){} - virtual bool Save(){return false;} + virtual bool Save(){ + return false; + } }; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <z-...@us...> - 2008-01-24 12:32:02
|
Revision: 7615 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7615&view=rev Author: z-man Date: 2008-01-24 04:30:39 -0800 (Thu, 24 Jan 2008) Log Message: ----------- Added: access levels to user accounts, aliases, reserved screen names, and authentication name based bans for REALLY stupid players. Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.h armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.cpp Modified: armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-24 09:55:49 UTC (rev 7614) +++ armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-24 12:30:39 UTC (rev 7615) @@ -2459,6 +2459,10 @@ access_level_change Required access level of command \1 changed to "\2".\n access_level_error Required access level of command \1 is "\2", you only have "\3".\n +user_level_help Changes the access level of a user. +user_level_usage usage: USER_LEVEL <authenticated name> <user access level (numerical)>\n +user_level_change Access level of user \1 changed to "\2".\n + #************************************* #************************************* # @@ -2501,6 +2505,7 @@ login_request_master Master server requires Login. login_message \1 has been logged in as \2.\n +login_message_special \1 has been logged in as \2 at access level "\3".\n logout_message \1 has been logged out as \2.\n login_failed_message 0xff7f7fLogin failed,0xffffff reason: \1\n @@ -2532,15 +2537,12 @@ pickup_authorized \1 is already authorized and does not need to be picked up.\n pickup_putdown_unauthorized You did not pick up \1, you have no right to put him down. -md5_password_admin_help Adds an admin account over the md5-hash based login system. -md5_password_admin_syntax Usage: MD5_PASSWORD_ADMIN <user name> <password>\n +local_user_help Adds a local user account from a name/password pair. +local_user_syntax Usage: LOCAL_USER <user name> <password>\n -md5_password_user_help Adds an user account over the md5-hash based login system. -md5_password_user_syntax Usage: MD5_PASSWORD_USER <user name> <password>\n +local_team_help Adds a local account for an entire team (team tags are compared). +local_team_syntax Usage: LOCAL_TEAM <team tag> <password>\n -md5_password_team_help Adds an account over the md5-hash based login system for an entire team (team tags are compared). -md5_password_team_syntax Usage: MD5_PASSWORD_TEAM <team tag> <password>\n - md5_password_teamleader_help Adds an account over the md5-hash based login system for a team leader. Team leaders can pick up players into the game. md5_password_teamleader_syntax Usage: MD5_PASSWORD_TEAMLEADER <user name> <password>\n @@ -2549,6 +2551,19 @@ md5_password_removed User name/team tag \1 removed.\n md5_password_remove_notfound User name/team tag \1 to remove not found.\n +reserve_screen_name_help Reserves a screen name to a registered user +reserve_screen_namne_usage Usage: RESERVE_SCREEN_NAME <screen name (in quotes if it contains spaces)> <user> +reserve_screen_name_change Screen name "\1" reserved for user \2.\n + +alias_help Allows bending authenticated names around: a player authenticated as X originally can appear as y. +alias_usage Usage: ALIAS <user> <alias of user> +alias_change User \1 will be known as \2.\n + +ban_user_help Allows to ban players based on their authentication ID. +ban_user_message User \1 has been banned.\n +unban_user_help Undoes BAN_USER. +unban_user_message User \1 has been unbanned.\n + # items that should not be translated include english_base_notranslate.txt Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-24 09:55:49 UTC (rev 7614) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-24 12:30:39 UTC (rev 7615) @@ -99,7 +99,7 @@ int lastC = 'x'; for( int i = 0; i < original.Len()-1; ++i ) { - int c = original[i]; + unsigned int c = static_cast< unsigned char >( original[i] ); // a valid character switch (c) @@ -140,7 +140,7 @@ else { // encode as hexcode - filter << std::hex << std::uppercase << std::setfill('0') << std::setw(2) << c; + filter << '%' << std::hex << std::uppercase << std::setfill('0') << std::setw(2) << c; } } @@ -151,6 +151,53 @@ return filter.str(); } +#ifdef KRAWALL_SERVER +// reverses se_EscapeName (left inverse only, UnEscape(Escape(x)) == x, but not Escape(UnEscape(y)) == y. ) +static std::string se_UnEscapeName( tString const & original ) +{ + std::ostringstream filter; + + int lastC = 'x'; + for( int i = 0; i < original.Len()-1; ++i ) + { + int c = original[i]; + + if ( lastC == '\\' ) + { + if ( c == '_' ) + { + c = ' '; + } + filter.put(c); + } + else if ( c == '%' ) + { + // decode hex code + char hex[3]; + hex[0] = original[i+1]; + hex[1] = original[i+2]; + hex[2] = 0; + i += 2; + + int decoded; + std::istringstream s(hex); + s >> std::hex >> decoded; + tASSERT( !s.fail() ); + filter.put(decoded); + } + else if ( c != '\\' ) + { + filter.put(c); + } + + lastC = c; + } + + // done! wrap up stream as string. + return filter.str(); +} +#endif + // generate the user name for an unauthenticated user static tString se_UnauthenticatedUserName( tString const & name ) { @@ -558,7 +605,7 @@ if (success) { - player->Authenticate( authName ); + player->Authenticate( authName, result.accessLevel ); #ifdef DEDICATED if ( authority == "admin" ) @@ -919,6 +966,11 @@ static void se_RequestLogin( ePlayerNetID * p ); +// check whether a special username is banned +#ifdef KRAWALL_SERVER +static bool se_IsUserBanned( ePlayerNetID * p, tString const & name ); +#endif + // receive a "login wanted" message from client static void se_LoginWanted( nMessage & m ) { @@ -938,6 +990,12 @@ m >> authName; p->SetRawAuthenticatedName( authName ); + // check for stupid bans + if ( se_IsUserBanned( p, authName ) ) + { + return; + } + se_RequestLogin( p ); } #else @@ -1591,24 +1649,15 @@ #else if ( sn_GetNetState() == nSERVER && p->Owner() != sn_myNetID ) { -#ifndef HAVE_LIBZTHREAD - if ( params.Len() > 1 ) - { - sn_ConsoleOut( "Sorry, distributed authentication not supported on this server.", p->Owner() ); - return; - } -#endif if ( p->IsAuthenticated() ) { sn_ConsoleOut( "$login_request_reduntant.", p->Owner() ); + return; } - else - { - } - if ( p->GetRawAuthenticatedName().Len() <= 1 ) + if ( p->GetRawAuthenticatedName().Len() <= 1 || params.StrPos("@") >= 0 ) { - if ( params.StrPos( "@" ) > 0 ) + if ( params.StrPos( "@" ) >= 0 ) { p->SetRawAuthenticatedName( params ); } @@ -1618,6 +1667,12 @@ } } + // check for stupid bans + if ( se_IsUserBanned( p, p->GetRawAuthenticatedName() ) ) + { + return; + } + p->loginWanted = true; se_RequestLogin( p ); @@ -2015,7 +2070,9 @@ { // player username comes from authentication name and may be much different from // the screen name - tos << p2->GetUserName() << " ( " << p2->GetName() << " )"; + tos << p2->GetUserName() << " ( " << p2->GetName() << ", " + << tCurrentAccessLevel::GetName( p2->GetAccessLevel() ) + << " )"; } else { @@ -2823,20 +2880,302 @@ } #ifdef KRAWALL_SERVER -void ePlayerNetID::Authenticate( tString const & authName ) + +// changes various user aspects +template< class P > class eUserConfig: public tConfItemBase { - if ( !IsAuthenticated() && IsHuman() ) +public: + P Get(tString const & name ) const { - sn_ConsoleOut( tOutput( "$login_message", GetName(), se_EscapeName( authName ).c_str() ) ); + typename Properties::const_iterator iter = properties.find( name ); + if ( iter != properties.end() ) + { + return (*iter).second; + } + + return GetDefault(); } +protected: + typedef std::map< tString, P > Properties; + eUserConfig( char const * name ) + : tConfItemBase( name ) + { + requiredLevel = tAccessLevel_Owner; + } + virtual P ReadRawVal(tString const & name, std::istream &s) const = 0; + virtual P GetDefault() const = 0; + + virtual void ReadVal(std::istream &s) + { + tString name; + s >> name; + + P value = ReadRawVal(name, s); + + properties[name] = value; + } + + Properties properties; +private: + + virtual void WriteVal(std::ostream &s) + { + tASSERT(0); + } + + virtual bool Writable(){ + return false; + } + + virtual bool Save(){ + return false; + } +}; + +// changes the access level of a player +class eUserLevel: public eUserConfig< tAccessLevel > +{ +public: + eUserLevel() + : eUserConfig< tAccessLevel >( "USER_LEVEL" ) + { + } + + tAccessLevel GetDefault() const + { + return tAccessLevel_Authenticated; + } + + virtual tAccessLevel ReadRawVal(tString const & name, std::istream &s) const + { + int levelInt; + s >> levelInt; + tAccessLevel level = static_cast< tAccessLevel >( levelInt ); + + if ( s.fail() ) + { + con << tOutput( "$user_level_usage" ); + return GetDefault(); + } + + con << tOutput( "$user_level_change", name, tCurrentAccessLevel::GetName( level ) ); + + return level; + } +}; + +static eUserLevel se_userLevel; + +// reserves a nickname +class eReserveNick: public eUserConfig< tString > +{ +#ifdef DEBUG + static void TestEscape() + { +#ifdef KRAWALL_SERVER + tString test("ä@%bla:"); + tString esc(se_EscapeName( test, false ).c_str()); + tString rev(se_UnEscapeName( esc ).c_str()); + tASSERT( test == rev ); +#endif + } +#endif +public: + eReserveNick() + : eUserConfig< tString >( "RESERVE_SCREEN_NAME" ) + { +#ifdef DEBUG + TestEscape(); +#endif + } + + tString GetDefault() const + { + return tString(); + } + + virtual tString ReadRawVal(tString const & name, std::istream &s) const + { + tString user; + s >> user; + + if ( user == "" ) + { + con << tOutput( "$reserve_screen_name_usage" ); + return GetDefault(); + } + + user = se_UnEscapeName( user ).c_str(); + + con << tOutput( "$reserve_screen_name_change", name, user ); + + return user; + } +}; + +static eReserveNick se_reserveNick; + +// authentication alias to map a local account to a global one +class eAlias: public eUserConfig< tString > +{ +public: + eAlias() + : eUserConfig< tString >( "ALIAS" ) + { + } + + tString GetDefault() const + { + return tString(); + } + + virtual tString ReadRawVal(tString const & name, std::istream &s) const + { + tString alias; + s >> alias; + + if ( alias == "" ) + { + con << tOutput( "$alias_usage" ); + return GetDefault(); + } + + alias = se_UnEscapeName( alias ).c_str(); + + con << tOutput( "$alias_change", name, alias ); + + return alias; + } +}; + +static eAlias se_alias; + +// bans for players too stupid to disable autologin +class eBanUser: public eUserConfig< bool > +{ +public: + eBanUser() + : eUserConfig< bool >( "BAN_USER" ) + { + } + + // unbans the user again + void UnBan( tString const & name ) + { + properties[name] = false; + con << tOutput( "$unban_user_message", name ); + } + + bool GetDefault() const + { + return false; + } + + virtual bool ReadRawVal(tString const & name, std::istream &s) const + { + con << tOutput( "$ban_user_message", name ); + return true; + } +}; + +static eBanUser se_banUser; + +// check whether a special username is banned +static bool se_IsUserBanned( ePlayerNetID * p, tString const & name ) +{ + if( se_banUser.Get( name ) ) + { + sn_KickUser( p->Owner(), tOutput( "$network_kill_banned", 60, "" ) ); + return true; + } + + return false; +} + +class eUnBanUser: public eUserConfig< bool > +{ +public: + eUnBanUser( ) + : eUserConfig< bool >( "UNBAN_USER" ) + { + } + + bool GetDefault() const + { + return false; + } + + virtual bool ReadRawVal(tString const & name, std::istream &s) const + { + se_banUser.UnBan(name); + return false; + } +}; + +static eUnBanUser se_unBanUser; + +static void se_CheckAccessLevel( tAccessLevel & level, tString const & authName ) +{ + tAccessLevel newLevel = se_userLevel.Get( authName ); + if ( newLevel < level ) + { + level = newLevel; + } +} + +void ePlayerNetID::Authenticate( tString const & authName, tAccessLevel accessLevel_ ) +{ + tString newAuthenticatedName( se_EscapeName( authName ).c_str() ); + if ( !IsAuthenticated() ) { - accessLevel = tAccessLevel_Authenticated; + // take the access level from the arguments + accessLevel = accessLevel_; + + // but elevate it for registered users + se_CheckAccessLevel( accessLevel, newAuthenticatedName ); + + rawAuthenticatedName_ = authName; + tString alias = se_alias.Get( newAuthenticatedName ); + if ( alias != "" ) + { + rawAuthenticatedName_ = alias; + newAuthenticatedName = se_EscapeName( rawAuthenticatedName_ ).c_str(); + + // elevate access level again according to the new alias + se_CheckAccessLevel( accessLevel, newAuthenticatedName ); + } + + // check for stupid bans + if ( se_IsUserBanned( this, newAuthenticatedName ) ) + { + return; + } + + // if a better access level has been passed in, take that + if ( accessLevel_ < accessLevel ) + { + accessLevel = accessLevel_; + } + + if ( IsHuman() ) + { + if ( accessLevel < tAccessLevel_Authenticated ) + { + sn_ConsoleOut( tOutput( "$login_message_special", + GetName(), + newAuthenticatedName, + tCurrentAccessLevel::GetName( accessLevel ) ) ); + } + else + { + sn_ConsoleOut( tOutput( "$login_message", GetName(), newAuthenticatedName ) ); + } + } } - rawAuthenticatedName_ = authName; GetScoreFromDisconnectedCopy(); } @@ -2989,6 +3328,7 @@ if ( name.Len() <= 1 ) return false; + // check for other players with the same name for (int i = se_PlayerNetIDs.Len()-1; i >= 0; --i ) { ePlayerNetID * player = se_PlayerNetIDs(i); @@ -2999,6 +3339,17 @@ } } +#ifdef KRAWALL_SERVER + // check for reserved nicknames + tString reservedFor = se_reserveNick.Get( name ); + if ( reservedFor != "" && + ( !exception || exception->GetAccessLevel() >= tAccessLevel_Default || + exception->GetRawAuthenticatedName() != reservedFor ) ) + { + return true; + } +#endif + return false; } Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h 2008-01-24 09:55:49 UTC (rev 7614) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h 2008-01-24 12:30:39 UTC (rev 7615) @@ -242,9 +242,10 @@ void Greet(); #ifdef KRAWALL_SERVER - void Authenticate( tString const & authName ); // make the authentification valid - void DeAuthenticate(); // make the authentification invalid - bool IsAuthenticated() const; // is the authentification valid? + void Authenticate( tString const & authName, + tAccessLevel accessLevel = tAccessLevel_Authenticated ); //!< make the authentification valid + void DeAuthenticate(); //!< make the authentification invalid + bool IsAuthenticated() const; //!< is the authentification valid? #endif static void RequestScheduledLogins(); //!< initiates login processes for all pending wishes Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.h =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.h 2008-01-24 09:55:49 UTC (rev 7614) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.h 2008-01-24 12:30:39 UTC (rev 7615) @@ -43,6 +43,7 @@ #include "tSafePTR.h" #include "tString.h" // #include "nNetObject.h" +#include "tConfiguration.h" class nNetObject; @@ -167,8 +168,10 @@ bool success; // was the operation successful? tString error; // potential error message + tAccessLevel accessLevel;// access level of user + nCheckResultBase() - : success( false ){} + : success( false ), accessLevel( tAccessLevel_Authenticated ){} }; struct nCheckResult: public nCheckResultBase Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp 2008-01-24 09:55:49 UTC (rev 7614) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp 2008-01-24 12:30:39 UTC (rev 7615) @@ -46,6 +46,9 @@ static nKrawall::nMethod sn_bmd5("bmd5"), sn_md5("md5"); +static tSettingItem< tString > sn_md5Prefix( "MD5_PREFIX", sn_md5.prefix ); +static tSettingItem< tString > sn_md5Suffix( "MD5_SUFFIX", sn_md5.suffix ); + //! fetch NULL-terminated list of locally supported methods nKrawall::nMethod const * const * nKrawall::nMethod::LocalMethods() { @@ -69,15 +72,25 @@ // scrambled passwords according to our various methods std::map< tString, nKrawall::nScrambledPassword > scrambledPasswords_; - nLogin( char const * authority, tString const & password, tString const & username ) - : authority_( authority ) + // access level for the login + tAccessLevel accessLevel_; + + static bool FixOK( tString const & fix ) { + return fix.StrPos( "%" ) < 0; + } + + nLogin( char const * authority, tString const & password, tString const & username, tAccessLevel accessLevel = tAccessLevel_Authenticated ) + : authority_( authority ), accessLevel_( accessLevel ) + { // scramble the password before storing it (in case an evil attacker can read our memory, // but not the configuration file where they are stored in plain text :) ) nKrawall::nMethod const * const * run = nKrawall::nMethod::LocalMethods(); while ( * run ) { - if ( username.Len() <= 1 && ( (*run)->prefix.Len() > 1 || (*run)->suffix.Len() > 1 ) ) + if ( username.Len() <= 1 && + ( !FixOK( (*run)->prefix ) || !FixOK( (*run)->suffix ) ) + ) { static bool warn = true; if ( warn ) @@ -147,40 +160,27 @@ static nLoginMap sn_partialLogins; // add an admin account -static void sn_ReadAdminPassword( std::istream & s ) +static void sn_ReadPassword( std::istream & s ) { tString username, password; s >> username; if ( !s.good() ) { - con << tOutput( "$md5_password_admin_syntax" ); + con << tOutput( "$local_user_syntax" ); return; } tConfItemBase::EatWhitespace(s); password.ReadLine(s); - - sn_exactLogins[ username ] = nLogin( "admin", password, username ); -} - -static tConfItemFunc sn_kpa( "MD5_PASSWORD_ADMIN", sn_ReadAdminPassword ); - -// add an admin account -static void sn_ReadUserPassword( std::istream & s ) -{ - tString username, password; - s >> username; - if ( !s.good() ) + if ( password == "" ) { - con << tOutput( "$md5_password_user_syntax" ); + con << tOutput( "$local_user_syntax" ); return; } - tConfItemBase::EatWhitespace(s); - password.ReadLine(s); - sn_exactLogins[ username ] = nLogin( "user", password, username ); + sn_exactLogins[ username ] = nLogin( "", password, username ); } -static tConfItemFunc sn_kpu( "MD5_PASSWORD_USER", sn_ReadUserPassword ); +static tConfItemFunc sn_kpa( "LOCAL_USER", sn_ReadPassword ); // add team account static void sn_ReadTeamPassword( std::istream & s ) @@ -189,34 +189,21 @@ s >> username; if ( !s.good() ) { - con << tOutput( "$md5_password_team_syntax" ); + con << tOutput( "$local_team_syntax" ); return; } tConfItemBase::EatWhitespace(s); password.ReadLine(s); - - sn_partialLogins[ username ] = nLogin( tString("team_") + username, password, tString("") ); -} - -static tConfItemFunc sn_kta( "MD5_PASSWORD_TEAM", sn_ReadTeamPassword ); - -// add teamleader leader account -static void sn_ReadTeamleaderPassword( std::istream & s ) -{ - tString username, password; - s >> username; - if ( !s.good() ) + if ( password == "" ) { - con << tOutput( "$md5_password_teamleader_syntax" ); + con << tOutput( "$local_team_syntax" ); return; } - tConfItemBase::EatWhitespace(s); - password.ReadLine(s); - sn_exactLogins[ username ] = nLogin( tString("teamleader_") + username, password, username ); + sn_partialLogins[ username ] = nLogin( tString("local_team_") + username, password, tString(""), tAccessLevel_TeamMember ); } -static tConfItemFunc sn_ktla( "MD5_PASSWORD_TEAMLEADER", sn_ReadTeamleaderPassword ); +static tConfItemFunc sn_kta( "LOCAL_TEAM", sn_ReadTeamPassword ); // finds a login element as iterator nLoginMap::iterator sn_FindLoginIterator( tString const & username, nLoginMap * & map, bool exact = false ) @@ -305,7 +292,8 @@ // check password result.success = login->CheckPassword( nScrambleInfo( result.username ), method, salt, hash, result.error ); - + result.accessLevel = login->accessLevel_; + return; } else Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.cpp 2008-01-24 09:55:49 UTC (rev 7614) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.cpp 2008-01-24 12:30:39 UTC (rev 7615) @@ -180,17 +180,19 @@ return *st_confMap; } -// changes the access level of +// changes the access level of a configuration item class tConfItemLevel: public tConfItemBase { public: tConfItemLevel() : tConfItemBase( "ACCESS_LEVEL" ) { + requiredLevel = tAccessLevel_Owner; } virtual void ReadVal(std::istream &s) { + // read name and access level tString name; s >> name; @@ -208,10 +210,12 @@ for(int i=name.Len()-1;i>=0;i--) name[i]=toupper(name[i]); + // find the item tConfItemMap & confmap = ConfItemMap(); tConfItemMap::iterator iter = confmap.find( name ); if ( iter != confmap.end() ) { + // and change the level tConfItemBase * ci = (*iter).second; ci->requiredLevel = level; con << tOutput( "$access_level_change", name, tCurrentAccessLevel::GetName( level ) ); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <z-...@us...> - 2008-01-24 12:40:52
|
Revision: 7616 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7616&view=rev Author: z-man Date: 2008-01-24 04:40:00 -0800 (Thu, 24 Jan 2008) Log Message: ----------- Proper error reporting when ZThread is not available and we can't to remote logins. Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp Modified: armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-24 12:30:39 UTC (rev 7615) +++ armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-24 12:40:00 UTC (rev 7616) @@ -2517,6 +2517,7 @@ login_error_invalidurl_defaultport Authentication URL \1 invalid. Just leave away the default port, please :). login_error_invalidurl_slash Authentication URL \1 invalid, double slash or ending with slash. login_error_invalidurl_notfound Authentication URL \1 invalid, it was not found. +login_error_noremote Authentication via Global ID not available on this server. login_error_methodmismatch The local method used for auhtentication has been modified since your password was set. In the server's config files, put all commands that define authentication methods before all local password definitions. login_error_nomethod No authentication method could be found. Your client supports \1, this server supports \2, and the authentication server supports \3. login_error_nomethodlist Authentication URL \1 does not return a list of supported methods. Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp 2008-01-24 12:30:39 UTC (rev 7615) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp 2008-01-24 12:40:00 UTC (rev 7616) @@ -340,10 +340,10 @@ void FetchInfoFromAuthority(); // report an authority info query error to the higher level system - bool ReportAuthorityError( tOutput const & error ) + bool ReportAuthorityError( tOutput const & error, bool real = false ) { // well, the public scripts don't support this yet, so let's fake it - if ( 0 ) + if ( !real ) { method.method = "bmd5"; method.prefix = ""; @@ -442,7 +442,7 @@ bool nLoginProcess::FetchInfoFromAuthorityRemote() { #ifndef HAVE_LIBZTHREAD - return ReportAuthorityError( "Internal errror, remote login not supported" ); + return ReportAuthorityError( tOutput("$login_error_noremote"), true ); #endif { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <z-...@us...> - 2008-01-24 12:58:19
|
Revision: 7617 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7617&view=rev Author: z-man Date: 2008-01-24 04:55:57 -0800 (Thu, 24 Jan 2008) Log Message: ----------- Updated. Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/NEWS armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt Modified: armagetronad/branches/0.2.8-auth/armagetronad/NEWS =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/NEWS 2008-01-24 12:40:00 UTC (rev 7616) +++ armagetronad/branches/0.2.8-auth/armagetronad/NEWS 2008-01-24 12:55:57 UTC (rev 7617) @@ -1,6 +1,7 @@ Changes since 0.2.8.2: New settings and commands: +- ACCESS_LEVEL to modify the required access level to change settings - KICK_TO and MOVE_TO: redirect a client to a different server - DEFAULT_KICK(_TO)_MESSAGE: default reason given to players for a kick - DEFAULT_KICK_TO_SERVER/PORT: default redirection target for KICK/MOVE_TO. @@ -49,7 +50,17 @@ - PLAYER_MESSAGE <user ID or name> <Message>: Like /msg, but from the console +If --enable-krawallserver was activated: +- LOCAL_USER, LOCAL_TEAM for local login accounts +- MD5_PREFIX/MD5_SUFFIX for additional password scrambling +- USER_LEVEL to grant users various access levels +- RESERVE_SCREEN_NAME to reserve a screen name to a certain player +- ALIAS to bend authentication names around +- (UN)BAN_USER to ban really stupid users based on their global user ID + Featurelets: +- --enable-krawallserver has been actually implemented now, and it enables secure logins + to accounts local to the server and not-so-secure logins managed by authentication servers. - A subculture list for server groups that are not managed by our main master servers - A friends list and filter for the server browser that shows you only servers with your friends on them. Modified: armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-24 12:40:00 UTC (rev 7616) +++ armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-24 12:55:57 UTC (rev 7617) @@ -2565,6 +2565,9 @@ unban_user_help Undoes BAN_USER. unban_user_message User \1 has been unbanned.\n +md5_prefix_help Extra hash prefix for local accounts used to scramble the password +md5_suffix_help Extra hash suffix for local accounts used to scramble the password + # items that should not be translated include english_base_notranslate.txt This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <z-...@us...> - 2008-01-24 13:29:43
|
Revision: 7618 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7618&view=rev Author: z-man Date: 2008-01-24 05:27:19 -0800 (Thu, 24 Jan 2008) Log Message: ----------- ZTHread no longer required for remote logins; without threads, the required lookups are done between rounds. Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/NEWS armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.h armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gGame.cpp Modified: armagetronad/branches/0.2.8-auth/armagetronad/NEWS =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/NEWS 2008-01-24 12:55:57 UTC (rev 7617) +++ armagetronad/branches/0.2.8-auth/armagetronad/NEWS 2008-01-24 13:27:19 UTC (rev 7618) @@ -51,6 +51,7 @@ console If --enable-krawallserver was activated: +- GLOBAL_ID_ENABLED to toggle remote accounts - LOCAL_USER, LOCAL_TEAM for local login accounts - MD5_PREFIX/MD5_SUFFIX for additional password scrambling - USER_LEVEL to grant users various access levels Modified: armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-24 12:55:57 UTC (rev 7617) +++ armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-24 13:27:19 UTC (rev 7618) @@ -2568,6 +2568,8 @@ md5_prefix_help Extra hash prefix for local accounts used to scramble the password md5_suffix_help Extra hash suffix for local accounts used to scramble the password +global_id_enabled_help If set to 0, Global IDs (Armathentication) will be disabled on this server. + # items that should not be translated include english_base_notranslate.txt Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp 2008-01-24 12:55:57 UTC (rev 7617) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp 2008-01-24 13:27:19 UTC (rev 7618) @@ -37,7 +37,10 @@ #include <memory> #include <string> #include <string.h> +#include <deque> +#undef HAVE_LIBZTHREAD + #ifdef HAVE_LIBZTHREAD #include <zthread/Thread.h> #include <zthread/LockedQueue.h> @@ -216,6 +219,12 @@ (object_->*function_)(); } + //! schedule a task for execution at the next convenient break, between game rounds for example + static void ScheduleBreak( T & object, void (T::*function)() ) + { + pendingForBreak_.push_back( nMemberFunctionRunnerTemplate( object, function ) ); + } + //! schedule a task for execution in a background thread static void ScheduleBackground( T & object, void (T::*function)() ) { @@ -229,11 +238,12 @@ else { // don't start threads when we're recording, just do the task at the next opportunity - ScheduleForeground( object, function ); + ScheduleBreak( object, function ); + } #else - // execute it immedeately - (object.*function)(); + // do it when you can without getting interrupted. + ScheduleBreak( object, function ); #endif } @@ -249,6 +259,18 @@ #endif } + + // function that calls tasks scheduled for the next break + static void OnBreak() + { + // finish all pending tasks + while( pendingForBreak_.size() > 0 ) + { + nMemberFunctionRunnerTemplate & next = pendingForBreak_.front(); + next.run(); + pendingForBreak_.pop_front(); + } + } private: //! pointer to the object we should so something with tJUST_CONTROLLED_PTR< T > object_; @@ -256,6 +278,9 @@ //! the function to call void (T::*function_)(); + // taks for the break + static std::deque< nMemberFunctionRunnerTemplate > pendingForBreak_; + #ifdef HAVE_LIBZTHREAD // queue of foreground tasks static ZThread::LockedQueue< nMemberFunctionRunnerTemplate, ZThread::FastMutex > pending_; @@ -273,6 +298,10 @@ #endif }; +template< class T > +std::deque< nMemberFunctionRunnerTemplate<T> > +nMemberFunctionRunnerTemplate<T>::pendingForBreak_; + #ifdef HAVE_LIBZTHREAD // static queue template< class T > @@ -284,6 +313,18 @@ class nMemberFunctionRunner { public: + enum ScheduleType + { + Break, + Foreground, + Background + }; + + template< class T > static void ScheduleBreak( T & object, void (T::*function)() ) + { + nMemberFunctionRunnerTemplate<T>::ScheduleBreak( object, function ); + } + template< class T > static void ScheduleBackground( T & object, void (T::*function)() ) { nMemberFunctionRunnerTemplate<T>::ScheduleBackground( object, function ); @@ -293,6 +334,22 @@ { nMemberFunctionRunnerTemplate<T>::ScheduleForeground( object, function ); } + + template< class T > static void ScheduleMayBlock( T & object, void (T::*function)(), bool block ) + { + if ( block ) + { +#ifdef HAVE_ZTHREAD + ScheduleBackground( object, function ); +#else + ScheduleBreak( object, function ); +#endif + } + else + { + ScheduleForeground( object, function ); + } + } }; @@ -332,7 +389,7 @@ clientSupportedMethods = sn_Connections[user.Owner()].supportedAuthenticationMethods_; - nMemberFunctionRunner::ScheduleBackground( *this, &nLoginProcess::FetchInfoFromAuthority ); + nMemberFunctionRunner::ScheduleMayBlock( *this, &nLoginProcess::FetchInfoFromAuthority, authority != "" ); } // That function triggers fetching of authentication relevant data from the authentication @@ -438,14 +495,18 @@ nMemberFunctionRunner::ScheduleForeground( *this, &nLoginProcess::QueryFromClient ); } +static bool sn_supportRemoteLogins = 1; +static tSettingItem< bool > sn_supportRemoteLoginsConf( "GLOBAL_ID_ENABLED", sn_supportRemoteLogins ); + // fetches info from remote authority bool nLoginProcess::FetchInfoFromAuthorityRemote() { -#ifndef HAVE_LIBZTHREAD - return ReportAuthorityError( tOutput("$login_error_noremote"), true ); -#endif - + if ( !sn_supportRemoteLogins ) { + return ReportAuthorityError( tOutput("$login_error_noremote"), true ); + } + + { // the hostname part of the authority should not contain uppercase letters { std::istringstream in( static_cast< const char * >( authority ) ); @@ -706,7 +767,7 @@ username = tColoredString::RemoveColors( username ); // and go on - nMemberFunctionRunner::ScheduleBackground( *this, &nLoginProcess::Authorize ); + nMemberFunctionRunner::ScheduleMayBlock( *this, &nLoginProcess::Authorize, authority != "" ); } // and here we go again: a background task talks with the authority @@ -811,3 +872,11 @@ return true; } +//! call when you have some time for lengthy authentication queries to servers +void nAuthentification::OnBreak() +{ +#ifdef KRAWALL_SERVER + nMemberFunctionRunnerTemplate< nLoginProcess >::OnBreak(); +#endif +} + Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.h =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.h 2008-01-24 12:55:57 UTC (rev 7617) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.h 2008-01-24 13:27:19 UTC (rev 7618) @@ -35,25 +35,26 @@ class nAuthentification: public nKrawall { public: - // callback where the game can register the password request/ - // lookup + //! callback where the game can register the password request/lookup typedef void UserPasswordCallback( nPasswordRequest const & request, nPasswordAnswer & answer ); - // callback where the game can register the login success - // lookup + //! callback where the game can register the login success typedef void LoginResultCallback( nCheckResult const & result ); - // let the game register the callbacks + //! let the game register the callbacks static void SetUserPasswordCallback(UserPasswordCallback* callback); static void SetLoginResultCallback (LoginResultCallback* callback); - // network handlers + //! network handlers static void HandlePasswordRequest(nMessage& m); static void HandlePasswordAnswer (nMessage& m); - // on the server: request user authentification from login slot + //! on the server: request user authentification from login slot static bool RequestLogin(const tString& authority, const tString& username, nNetObject & user, const tOutput& message ); + + //! call when you have some time for lengthy authentication queries to servers + static void OnBreak(); }; #endif Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gGame.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gGame.cpp 2008-01-24 12:55:57 UTC (rev 7617) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gGame.cpp 2008-01-24 13:27:19 UTC (rev 7618) @@ -70,6 +70,7 @@ #include "gParser.h" #include "tResourceManager.h" +#include "nAuthentification.h" #include <math.h> #include <stdlib.h> @@ -3083,6 +3084,9 @@ // unsigned short int mes1 = 1, mes2 = 1, mes3 = 1, mes4 = 1, mes5 = 1; + // now would be a good time to tend for pending tasks + nAuthentification::OnBreak(); + switch(state){ case GS_DELETE_GRID: // sr_con.autoDisplayAtNewline=true; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <z-...@us...> - 2008-01-24 14:47:11
|
Revision: 7620 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7620&view=rev Author: z-man Date: 2008-01-24 06:30:42 -0800 (Thu, 24 Jan 2008) Log Message: ----------- krawallserver -> armathentication :) Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/NEWS armagetronad/branches/0.2.8-auth/armagetronad/configure.ac Modified: armagetronad/branches/0.2.8-auth/armagetronad/NEWS =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/NEWS 2008-01-24 13:54:54 UTC (rev 7619) +++ armagetronad/branches/0.2.8-auth/armagetronad/NEWS 2008-01-24 14:30:42 UTC (rev 7620) @@ -50,7 +50,7 @@ - PLAYER_MESSAGE <user ID or name> <Message>: Like /msg, but from the console -If --enable-krawallserver was activated: +If --enable-armathentication was activated: - GLOBAL_ID_ENABLED to toggle remote accounts - LOCAL_USER, LOCAL_TEAM for local login accounts - MD5_PREFIX/MD5_SUFFIX for additional password scrambling Modified: armagetronad/branches/0.2.8-auth/armagetronad/configure.ac =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/configure.ac 2008-01-24 13:54:54 UTC (rev 7619) +++ armagetronad/branches/0.2.8-auth/armagetronad/configure.ac 2008-01-24 14:30:42 UTC (rev 7620) @@ -130,10 +130,10 @@ [enable special visuals for the krawall gaming network (default=disabled)]),, enable_krawall=no) -AC_ARG_ENABLE(krawallserver, - AC_HELP_STRING([--enable-krawallserver], - [enable special code for the krawall style user authentication (default=disabled)]),, -enable_krawallserver=no) +AC_ARG_ENABLE(armathentication, + AC_HELP_STRING([--enable-armathentication], + [enable server side code for the krawall style user authentication (default=disabled)]),, +enable_armathentication=no) AC_ARG_ENABLE(automakedefaults, AC_HELP_STRING([--enable-automakedefaults], @@ -233,7 +233,7 @@ AC_DEFINE(KRAWALL,,enables krawall) fi -if test x$enable_krawallserver = xyes; then +if test x$enable_armathentication = xyes; then AC_DEFINE(KRAWALL_SERVER,,enables krawall server) fi @@ -509,7 +509,7 @@ dnl ZThread dnl ************************************************* -if test x$enable_krawallserver = xyes; then +if test x$enable_armathentication = xyes; then test -z "$ZTHREAD_CONFIG" && ZTHREAD_CONFIG=zthread-config @@ -917,7 +917,7 @@ echo "" if test x$build_dedicated = xtrue -o x$armamaster = xtrue ; then -echo " Build with Krawall authentication support (server): $enable_krawallserver" +echo " Build with Armathentication support (server): $enable_armathentication" echo " Init scripts will be installed in : $initdir" echo " Dynamic data will be kept in : `eval echo ${aa_localstatedir}`" echo " PID files will be kept in : `eval echo ${rundir}`" This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <z-...@us...> - 2008-01-24 16:15:07
|
Revision: 7621 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7621&view=rev Author: z-man Date: 2008-01-24 08:10:05 -0800 (Thu, 24 Jan 2008) Log Message: ----------- Added access right settings for /admin commands, regular chat, playing, and the new /(de)op commands (replace /pickup) Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/NEWS armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt armagetronad/branches/0.2.8-auth/armagetronad/language/english_base_notranslate.txt armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.h armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tLocale.h armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gGame.cpp Modified: armagetronad/branches/0.2.8-auth/armagetronad/NEWS =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/NEWS 2008-01-24 14:30:42 UTC (rev 7620) +++ armagetronad/branches/0.2.8-auth/armagetronad/NEWS 2008-01-24 16:10:05 UTC (rev 7621) @@ -58,6 +58,7 @@ - RESERVE_SCREEN_NAME to reserve a screen name to a certain player - ALIAS to bend authentication names around - (UN)BAN_USER to ban really stupid users based on their global user ID +- ACCESS_LEVEL_OP/ADMIN/CHAT/PLAY/PLAY_SLIDING to control who can do which things Featurelets: - --enable-krawallserver has been actually implemented now, and it enables secure logins Modified: armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-24 14:30:42 UTC (rev 7620) +++ armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-24 16:10:05 UTC (rev 7621) @@ -2504,9 +2504,25 @@ login_request_namechange Name changed. Login required. login_request_master Master server requires Login. +# access level messages +access_level_op_help Minimal access level for /op and /deop commands. +access_level_admin_help Minimal access level for /admin command. +access_level_chat_help Minimal access level for chatting +access_level_play_help Minimal access level for playing +access_level_play_sliding_help Sliding minimal access level for playing; if players of a higher access level than given by ACCESS_LEVEL_PLAY are online, their level will be the minimal level for play; however, it will never be higher than ACCESS_LEVEL_PLAY_SLIDING. + +access_level_chat_timeout_help Time in seconds between public announcements that someone wants to chat, but can't. Set to 0 to disable the public wanrings. +access_level_chat_request \10xRESETT would like to chat, but is not authorized yet. Would someone be so kind and say "/op \2"?\n +access_level_chat_denied 0xff7f7fChat denied,0xffffff insufficient access level.\n +access_level_op_denied 0xff7f7f/(de)op denied,0xffffff insufficient access level.\n +access_level_op_overpowered 0xff7f7f/(de)op denied,0xffffff your victim has a higher level than you.\n +access_level_admin_denied 0xff7f7f/admin denied,0xffffff insufficient access level.\n + login_message \1 has been logged in as \2.\n login_message_special \1 has been logged in as \2 at access level "\3".\n +login_message_op \1 has been given access as \2 at level "\3" by order of \4.\n logout_message \1 has been logged out as \2.\n +logout_message_deop \1 has been logged out as \2 by order of \3.\n login_failed_message 0xff7f7fLogin failed,0xffffff reason: \1\n # various reasons for logins to fail @@ -2532,12 +2548,6 @@ chatcommand_requires_player \1 requires a player username as additional paramenter. -authentication_required_help Controls how authentication influences your right to play. If set to 0, authentication has no influence. If set to 2, you are always required to authenticate to play. If set to 1, you need to be authenticated if only one other player is already authenticated. - -pickup_teamleader You need to be logged in as team leader or admin to use the /pickup or /putdown command.\n -pickup_authorized \1 is already authorized and does not need to be picked up.\n -pickup_putdown_unauthorized You did not pick up \1, you have no right to put him down. - local_user_help Adds a local user account from a name/password pair. local_user_syntax Usage: LOCAL_USER <user name> <password>\n Modified: armagetronad/branches/0.2.8-auth/armagetronad/language/english_base_notranslate.txt =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base_notranslate.txt 2008-01-24 14:30:42 UTC (rev 7620) +++ armagetronad/branches/0.2.8-auth/armagetronad/language/english_base_notranslate.txt 2008-01-24 16:10:05 UTC (rev 7621) @@ -177,3 +177,19 @@ cycle_invulnerable_time_override_help UNDOCUMENTED cycle_wall_time_override_help UNDOCUMENTED +# yet undefined access levels, reserved for future use (we only want them to pop up for +# translators then) + +config_accesslevel_3 Moderator-2 +config_accesslevel_4 Moderator-3 +config_accesslevel_5 Moderator-4 +config_accesslevel_6 Moderator-5 +config_accesslevel_11 OP-ed +config_accesslevel_12 OP-ed-2 +config_accesslevel_13 OP-ed-3 +config_accesslevel_14 OP-ed-4 +config_accesslevel_15 OP-ed-5 +config_accesslevel_16 OP-ed-6 +config_accesslevel_17 OP-ed-7 +config_accesslevel_18 OP-ed-8 +config_accesslevel_19 OP-ed-9 Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-24 14:30:42 UTC (rev 7620) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-24 16:10:05 UTC (rev 7621) @@ -535,32 +535,36 @@ #endif #ifdef KRAWALL_SERVER -static int se_authenticationRequiredToPlay = 0; -static tSettingItem< int > se_authenticationRequiredToPlayConf( "AUTHENTICATION_REQUIRED", se_authenticationRequiredToPlay ); +// minimal access level to play +static tAccessLevel se_playAccessLevel = tAccessLevel_Program; +static tSettingItem< tAccessLevel > se_playAccessLevelConf( "ACCESS_LEVEL_PLAY", se_playAccessLevel ); -bool ePlayerNetID::AuthenticationRequiredToPlay() +// minimal sliding access level to play (slides up as soon as people of higher access level get authenticated ) +static tAccessLevel se_playAccessLevelSliding = tAccessLevel_Program; +static tSettingItem< tAccessLevel > se_playAccessLevelSlidingConf( "ACCESS_LEVEL_PLAY_SLIDING", se_playAccessLevelSliding ); + +tAccessLevel ePlayerNetID::AccessLevelRequiredToPlay() { - // strict settings - if ( se_authenticationRequiredToPlay >= 2 ) - { - return true; - } - if ( se_authenticationRequiredToPlay == 0 ) - { - return false; - } + tAccessLevel min = se_playAccessLevel; - // AUTHENTICATION_REQUIRED 1 means that as soon as a single player is authenticated, it is required for ( int i = se_PlayerNetIDs.Len()-1; i>=0; --i ) { ePlayerNetID* player = se_PlayerNetIDs(i); - if ( player->IsAuthenticated() && player->IsHuman() ) + if ( !player->IsHuman() ) + continue; + + tAccessLevel his = player->GetAccessLevel(); + if ( his < se_playAccessLevelSliding ) { - return true; + his = se_playAccessLevelSliding; } + if ( his < min ) + { + min = his; + } } - return false; + return min; } static void ResultCallback( nKrawall::nCheckResult const & result ) @@ -1227,7 +1231,7 @@ } #ifdef DEDICATED -#ifdef KRAWALL_SERVER_BLA +#ifdef KRAWALL_SERVER static ePlayerNetID * se_FindPlayerInChatCommand( ePlayerNetID * sender, char const * command, tString const & say ) { tString params(""); @@ -1603,6 +1607,14 @@ static tSettingItem<bool> se_interceptUnknownCommandsConf("INTERCEPT_UNKNOWN_COMMANDS", se_interceptUnknownCommands); +// minimal access level for /op/deop +static tAccessLevel se_opAccessLevel = tAccessLevel_TeamLeader; +static tSettingItem< tAccessLevel > se_opAccessLevelConf( "ACCESS_LEVEL_OP", se_opAccessLevel ); + +// minimal access level for /admin +static tAccessLevel se_adminAccessLevel = tAccessLevel_Moderator; +static tSettingItem< tAccessLevel > se_adminAccessLevelConf( "ACCESS_LEVEL_ADMIN", se_adminAccessLevel ); + void handle_command_intercept(tJUST_CONTROLLED_PTR< ePlayerNetID > &p, tString say) { con << "[cmd] " << *p << ": " << say << '\n'; } @@ -1682,68 +1694,76 @@ else if (say.StartsWith("/logout")) { #ifdef KRAWALL_SERVER // revoke the other kind of authentication as well - if ( se_authenticationRequiredToPlay < 2 && p->IsAuthenticated() ) + if ( p->IsAuthenticated() ) { p->DeAuthenticate(); } -#endif - +#else if ( p->IsLoggedIn() ) { sn_ConsoleOut("You have been logged out!\n",p->Owner()); } p->BeNotLoggedIn(); +#endif } -#ifdef KRAWALL_SERVER_BLA - else if (say.StartsWith("/pickup")) +#ifdef KRAWALL_SERVER + else if (say.StartsWith("/op")) { - tString const & auth = p->GetAuthority(); - if ( !auth.StartsWith( "teamleader" ) && auth != "admin" ) + if ( p->GetAccessLevel() <= se_opAccessLevel ) { - sn_ConsoleOut( "$pickup_teamleader", p->Owner() ); - return; - } - - ePlayerNetID * pickup = se_FindPlayerInChatCommand( p, "/pickup", say ); - if ( pickup ) - { - if ( pickup->IsAuth() ) + ePlayerNetID * pickup = se_FindPlayerInChatCommand( p, "/op", say ); + if ( pickup ) { - pickup->Auth( tString( "pickup_" ) + auth ); + if ( pickup->GetAccessLevel() > p->GetAccessLevel() ) + { + tString authName = pickup->GetUserName() + "@L_OP"; + if ( pickup->IsAuthenticated() ) + { + authName = pickup->GetRawAuthenticatedName(); + } + pickup->Authenticate( authName, static_cast< tAccessLevel >( p->GetAccessLevel() + 1 ), p ); + } + else + { + sn_ConsoleOut( tOutput( "$access_level_op_overpowered" ), p->Owner() ); + } } - else - { - sn_ConsoleOut( tOutput( "$pickup_authorized", pickup->GetUserName() ), p->Owner() ); - } } + else + { + sn_ConsoleOut( tOutput( "$access_level_op_denied" ), p->Owner() ); + } } - else if (say.StartsWith("/putdown")) + else if (say.StartsWith("/deop")) { - tString const & auth = p->GetAuthority(); - if ( !auth.StartsWith( "teamleader" ) && auth != "admin" ) + if ( p->GetAccessLevel() <= se_opAccessLevel ) { - sn_ConsoleOut( "$pickup_teamleader", p->Owner() ); - return; - } - - ePlayerNetID * pickup = se_FindPlayerInChatCommand( p, "/pickup", say ); - if ( pickup ) - { - if ( pickup->GetAuthority() == tString( "pickup_" ) + auth ) + ePlayerNetID * pickup = se_FindPlayerInChatCommand( p, "/deop", say ); + if ( pickup ) { - pickup->DeAuth(); + if ( pickup->GetAccessLevel() > p->GetAccessLevel() ) + { + if ( pickup->IsAuthenticated() ) + { + pickup->DeAuthenticate( p ); + } + } + else + { + sn_ConsoleOut( tOutput( "$access_level_op_overpowered" ), p->Owner() ); + } } - else - { - sn_ConsoleOut( tOutput( "$pickup_putdown_unauthorized", pickup->GetUserName() ), p->Owner() ); - } } + else + { + sn_ConsoleOut( tOutput( "$access_level_op_denied" ), p->Owner() ); + } } #endif else if (say.StartsWith("/admin")) { - if (!p->IsLoggedIn()) + if ( p->GetAccessLevel() > se_adminAccessLevel ) { - sn_ConsoleOut("You are not logged in.\n",p->Owner()); + sn_ConsoleOut( tOutput( "$access_level_admin_denied" ), p->Owner() ); return; } @@ -1790,6 +1810,14 @@ static bool se_silenceAll = false; // flag indicating whether new players should be silenced +// minimal access level for chat +static tAccessLevel se_chatAccessLevel = tAccessLevel_Program; +static tSettingItem< tAccessLevel > se_chatAccessLevelConf( "ACCESS_LEVEL_CHAT", se_chatAccessLevel ); + +// time between public chat requests, set to 0 to disable +REAL se_chatRequestTimeout = 60; +static tSettingItem< REAL > se_chatRequestTimeoutConf( "ACCESS_LEVEL_CHAT_TIMEOUT", se_chatRequestTimeout ); + static tSettingItem<bool> se_silAll("SILENCE_ALL", se_silenceAll); @@ -1849,6 +1877,8 @@ lengthMalus = 4.0; } + if ( !say.StartsWith("/") || say.StartsWith("/me") || say.StartsWith("/msg") || say.StartsWith("/team") ) + { // check if the player already said the same thing not too long ago for (short c = 0; c < p->lastSaid.Len(); c++) { if( (say.StripWhitespace() == p->lastSaid[c].StripWhitespace()) && ( (currentTime - p->lastSaidTimes[c]) < se_alreadySaidTimeout) ) { @@ -1857,6 +1887,32 @@ } } +#ifdef KRAWALL_SERVER + if ( p->GetAccessLevel() > se_chatAccessLevel ) + { + // check for spam already here + if ( nSpamProtection::Level_Mild <= p->chatSpam_.CheckSpam( 1.0f + lengthMalus, m.SenderID(), tOutput("$spam_chat") ) ) + { + return; + } + + // every once in a while, remind the public that someone has something to say + static double nextRequest = 0; + double now = tSysTimeFloat(); + if ( now > nextRequest && se_chatRequestTimeout > 0 ) + { + sn_ConsoleOut( tOutput("$access_level_chat_request", p->GetColoredName(), p->GetLogName() ), m.SenderID() ); + nextRequest = now + se_chatRequestTimeout; + } + else + { + sn_ConsoleOut( tOutput("$access_level_chat_denied" ), m.SenderID() ); + } + + return; + } +#endif + // update last said record { for( short zz = 12; zz>=1; zz-- ) @@ -1868,6 +1924,7 @@ p->lastSaid[0] = say; p->lastSaidTimes[0] = currentTime; } + } nSpamProtection::Level spamLevel = p->chatSpam_.CheckSpam( 1.0f + lengthMalus, m.SenderID(), tOutput("$spam_chat") ); bool pass = false; @@ -3135,7 +3192,7 @@ } } -void ePlayerNetID::Authenticate( tString const & authName, tAccessLevel accessLevel_ ) +void ePlayerNetID::Authenticate( tString const & authName, tAccessLevel accessLevel_, ePlayerNetID const * admin ) { tString newAuthenticatedName( se_EscapeName( authName ).c_str() ); @@ -3174,10 +3231,21 @@ { if ( accessLevel < tAccessLevel_Authenticated ) { - sn_ConsoleOut( tOutput( "$login_message_special", - GetName(), - newAuthenticatedName, - tCurrentAccessLevel::GetName( accessLevel ) ) ); + if ( admin ) + { + sn_ConsoleOut( tOutput( "$login_message_op", + GetName(), + newAuthenticatedName, + tCurrentAccessLevel::GetName( accessLevel ), + admin->GetLogName() ) ); + } + else + { + sn_ConsoleOut( tOutput( "$login_message_special", + GetName(), + newAuthenticatedName, + tCurrentAccessLevel::GetName( accessLevel ) ) ); + } } else { @@ -3189,10 +3257,17 @@ GetScoreFromDisconnectedCopy(); } -void ePlayerNetID::DeAuthenticate(){ +void ePlayerNetID::DeAuthenticate( ePlayerNetID const * admin ){ if ( IsAuthenticated() ) { - sn_ConsoleOut( tOutput( "$logout_message", GetName(), se_EscapeName( rawAuthenticatedName_ ).c_str() ) ); + if ( admin ) + { + sn_ConsoleOut( tOutput( "$logout_message_deop", GetName(), se_EscapeName( rawAuthenticatedName_ ).c_str(), admin->GetLogName() ) ); + } + else + { + sn_ConsoleOut( tOutput( "$logout_message", GetName(), se_EscapeName( rawAuthenticatedName_ ).c_str() ) ); + } } // force falling back to regular user name on next update Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h 2008-01-24 14:30:42 UTC (rev 7620) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h 2008-01-24 16:10:05 UTC (rev 7621) @@ -243,8 +243,9 @@ #ifdef KRAWALL_SERVER void Authenticate( tString const & authName, - tAccessLevel accessLevel = tAccessLevel_Authenticated ); //!< make the authentification valid - void DeAuthenticate(); //!< make the authentification invalid + tAccessLevel accessLevel = tAccessLevel_Authenticated, + ePlayerNetID const * admin = 0 ); //!< make the authentification valid + void DeAuthenticate( ePlayerNetID const * admin = 0 ); //!< make the authentification invalid bool IsAuthenticated() const; //!< is the authentification valid? #endif @@ -289,7 +290,7 @@ // and destroys those of players that have left #ifdef KRAWALL_SERVER - static bool AuthenticationRequiredToPlay(); // is authentication required to play on this server? + static tAccessLevel AccessLevelRequiredToPlay(); // is authentication required to play on this server? #endif static bool WaitToLeaveChat(); //!< waits for players to leave chat state. Returns true if the caller should wait to proceed with whatever he wants to do. Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp 2008-01-24 14:30:42 UTC (rev 7620) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp 2008-01-24 16:10:05 UTC (rev 7621) @@ -39,8 +39,6 @@ #include <string.h> #include <deque> -#undef HAVE_LIBZTHREAD - #ifdef HAVE_LIBZTHREAD #include <zthread/Thread.h> #include <zthread/LockedQueue.h> @@ -339,7 +337,7 @@ { if ( block ) { -#ifdef HAVE_ZTHREAD +#ifdef HAVE_LIBZTHREAD ScheduleBackground( object, function ); #else ScheduleBreak( object, function ); Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp 2008-01-24 14:30:42 UTC (rev 7620) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp 2008-01-24 16:10:05 UTC (rev 7621) @@ -99,8 +99,10 @@ con << "WARNING: local logins that use prefix or suffix do not work with team accounts.\n"; } } - - (*run)->ScramblePassword( nKrawall::nScrambleInfo( username ), password, scrambledPasswords_[ (*run)->method ] ); + else + { + (*run)->ScramblePassword( nKrawall::nScrambleInfo( username ), password, scrambledPasswords_[ (*run)->method ] ); + } ++run; } @@ -200,7 +202,7 @@ return; } - sn_partialLogins[ username ] = nLogin( tString("local_team_") + username, password, tString(""), tAccessLevel_TeamMember ); + sn_partialLogins[ username ] = nLogin( tString("L_TEAM_") + username, password, tString(""), tAccessLevel_TeamMember ); } static tConfItemFunc sn_kta( "LOCAL_TEAM", sn_ReadTeamPassword ); Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.h =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.h 2008-01-24 14:30:42 UTC (rev 7620) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.h 2008-01-24 16:10:05 UTC (rev 7621) @@ -275,6 +275,8 @@ //! macro for configuration enums: convert them to int. #define tCONFIG_ENUM( TYPE ) tCONFIG_AS( TYPE, int ) +tCONFIG_ENUM( tAccessLevel ); + template<class T> class tConfItem:virtual public tConfItemBase{ protected: T *target; Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tLocale.h =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tLocale.h 2008-01-24 14:30:42 UTC (rev 7620) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tLocale.h 2008-01-24 16:10:05 UTC (rev 7621) @@ -20,7 +20,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - + ************************************************************************** */ @@ -54,7 +54,9 @@ static tLanguage* FindStrict(tString const & name); //!< finds a language with the specified name. Aborts if the language is not found. static tLanguage* FindSloppy(tString const & name); //!< finds a language with the specified name. Returns NULL if the language is not found. - const tString& Name(){return name;} + const tString& Name(){ + return name; + } }; @@ -139,12 +141,28 @@ *this << identifier; } + template< class T1, class T2, class T3, class T4 > + tOutput( char const * identifier, T1 const & template1, T2 const & template2, T3 const & template3, T4 const & template4 ) + :anchor(NULL) + { + tASSERT( identifier && identifier[0] == '$' ); + + SetTemplateParameter(1, template1); + SetTemplateParameter(2, template2); + SetTemplateParameter(3, template3); + SetTemplateParameter(4, template4); + + *this << identifier; + } + tOutput(const tOutput &o); // copy constructor tOutput& operator=(const tOutput &o); // copy operator void Append(const tOutput &o); - bool IsEmpty()const { return !anchor; } + bool IsEmpty()const { + return !anchor; + } }; class tOutputItemBase: public tListItem<tOutputItemBase> @@ -161,9 +179,13 @@ { T element; public: - tOutputItem(tOutput& o, const T& e): tOutputItemBase(o), element(e){}; - virtual void Print(tString& target) const {target << element;} - virtual void Clone(tOutput& o) const {tNEW(tOutputItem<T>)(o, element);} +tOutputItem(tOutput& o, const T& e): tOutputItemBase(o), element(e){}; +virtual void Print(tString& target) const { + target << element; +} +virtual void Clone(tOutput& o) const { + tNEW(tOutputItem<T>)(o, element); +} }; Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gGame.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gGame.cpp 2008-01-24 14:30:42 UTC (rev 7620) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gGame.cpp 2008-01-24 16:10:05 UTC (rev 7621) @@ -1464,6 +1464,11 @@ if (sn_GetNetState()!=nCLIENT) { +#ifdef KRAWALL_SERVER + // fetch minimum access level required to play + tAccessLevel minAccessLevel = ePlayerNetID::AccessLevelRequiredToPlay(); +#endif + // update team settings gAIPlayer::SetNumberOfAIs(sg_currentSettings->numAIs, sg_currentSettings->minPlayers, @@ -1509,7 +1514,7 @@ #ifdef KRAWALL_SERVER // don't allow unknown players to play - if ( ePlayerNetID::AuthenticationRequiredToPlay() && !pni->IsAuthenticated() && pni->IsHuman() ) + if ( pni->GetAccessLevel() > minAccessLevel && pni->IsHuman() ) continue; #endif This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <z-...@us...> - 2008-01-24 16:41:49
|
Revision: 7622 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7622&view=rev Author: z-man Date: 2008-01-24 08:38:19 -0800 (Thu, 24 Jan 2008) Log Message: ----------- No more senseless name change messages, better error messages. Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h Modified: armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-24 16:10:05 UTC (rev 7621) +++ armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-24 16:38:19 UTC (rev 7622) @@ -2516,6 +2516,7 @@ access_level_chat_denied 0xff7f7fChat denied,0xffffff insufficient access level.\n access_level_op_denied 0xff7f7f/(de)op denied,0xffffff insufficient access level.\n access_level_op_overpowered 0xff7f7f/(de)op denied,0xffffff your victim has a higher level than you.\n +access_level_op_self 0xff7f7f/(de)op denied,0xffffff can't do that to yourself :).\n access_level_admin_denied 0xff7f7f/admin denied,0xffffff insufficient access level.\n login_message \1 has been logged in as \2.\n Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-24 16:10:05 UTC (rev 7621) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-24 16:38:19 UTC (rev 7622) @@ -1714,6 +1714,12 @@ ePlayerNetID * pickup = se_FindPlayerInChatCommand( p, "/op", say ); if ( pickup ) { + if ( pickup == p ) + { + sn_ConsoleOut( tOutput( "$access_level_op_self" ), p->Owner() ); + return; + } + if ( pickup->GetAccessLevel() > p->GetAccessLevel() ) { tString authName = pickup->GetUserName() + "@L_OP"; @@ -1741,6 +1747,12 @@ ePlayerNetID * pickup = se_FindPlayerInChatCommand( p, "/deop", say ); if ( pickup ) { + if ( pickup == p ) + { + sn_ConsoleOut( tOutput( "$access_level_op_self" ), p->Owner() ); + return; + } + if ( pickup->GetAccessLevel() > p->GetAccessLevel() ) { if ( pickup->IsAuthenticated() ) @@ -3419,7 +3431,7 @@ ePlayerNetID * player = se_PlayerNetIDs(i); if ( player != exception ) { - if ( name == player->GetUserName() ) + if ( name == player->GetUserName() || name == ePlayerNetID::FilterName( player->GetName() ) ) return true; } } @@ -5315,6 +5327,8 @@ , oldScreenName_( player.GetName() ) , oldLogName_( player.GetLogName() ) { + // store old name for password re-request and name change message + oldPrintName_ << player_ << tColoredString::ColorString(.5,1,.5); } ~eNameMessenger() @@ -5322,6 +5336,16 @@ tString logName = player_.GetLogName(); tString const & screenName = player_.GetName(); + // messages for the users + tColoredString printName; + printName << player_ << tColoredString::ColorString(.5,1,.5); + + tOutput mess; + + mess.SetTemplateParameter(1, printName); + mess.SetTemplateParameter(2, oldPrintName_); + + // is the player new? if ( oldLogName_.Len() <= 1 && logName.Len() > 0 ) { if ( player_.IsHuman() ) @@ -5331,6 +5355,13 @@ se_SaveToLadderLog(ladder); player_.Greet(); + + // print spectating join message (regular join messages are handled by eTeam) + if ( player_.IsSpectating() || !se_assignTeamAutomatically ) + { + mess << "$player_entered_spectator"; + sn_ConsoleOut(mess); + } } } else if ( logName != oldLogName_ || screenName != oldScreenName_ ) @@ -5338,11 +5369,25 @@ tString ladder; ladder << "PLAYER_RENAMED " << oldLogName_ << " " << logName << " " << nMachine::GetMachine(player_.Owner()).GetIP() << " " << screenName << "\n"; se_SaveToLadderLog(ladder); + + + if ( bool(player_.GetVoter() ) ) + { + player_.GetVoter()->PlayerChanged(); + } + + if ( oldPrintName_ != printName ) + { + mess << "$player_renamed"; + + sn_ConsoleOut(mess); + } } } ePlayerNetID & player_; tString oldScreenName_, oldLogName_; + tColoredString oldPrintName_; }; // ****************************************************************************************** @@ -5363,11 +5408,6 @@ // monitor name changes eNameMessenger messenger( *this ); - // store old name for password re-request and name change message - tColoredString oldprintname; - tString oldUserName( GetUserName() ); - oldprintname << *this << tColoredString::ColorString(.5,1,.5); - // apply client change, stripping excess spaces if ( sn_GetNetState() != nCLIENT ) { @@ -5446,35 +5486,6 @@ { // sync the new name RequestSync(); - - tOutput mess; - - tColoredString printname; - printname << *this << tColoredString::ColorString(.5,1,.5); - - mess.SetTemplateParameter(1, printname); - mess.SetTemplateParameter(2, oldprintname); - - if (oldUserName.Len()<=1 && GetUserName().Len()>=1){ - // print spectating join message (regular join messages are handled by eTeam) - if ( IsSpectating() || !se_assignTeamAutomatically ) - { - mess << "$player_entered_spectator"; - sn_ConsoleOut(mess); - } - - } - else if (strcmp(oldUserName,GetUserName())) - { - mess << "$player_renamed"; - - if ( bool(this->voter_) ) - { - this->voter_->PlayerChanged(); - } - - sn_ConsoleOut(mess); - } } } Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h 2008-01-24 16:10:05 UTC (rev 7621) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.h 2008-01-24 16:38:19 UTC (rev 7622) @@ -257,6 +257,7 @@ void SetSilenced( bool silenced ) { silenced_ = silenced; } bool& AccessSilenced( void ) { return silenced_; } + eVoter * GetVoter(){return voter_;} // returns our voter void CreateVoter(); // create our voter or find it static void SilenceMenu(); // menu where you can silence players static void PoliceMenu(); // menu where you can silence and kick players This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <z-...@us...> - 2008-01-24 18:11:48
|
Revision: 7623 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7623&view=rev Author: z-man Date: 2008-01-24 10:08:19 -0800 (Thu, 24 Jan 2008) Log Message: ----------- Added /promote and /demote, saner spam checking. Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/NEWS armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp Modified: armagetronad/branches/0.2.8-auth/armagetronad/NEWS =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/NEWS 2008-01-24 16:38:19 UTC (rev 7622) +++ armagetronad/branches/0.2.8-auth/armagetronad/NEWS 2008-01-24 18:08:19 UTC (rev 7623) @@ -59,6 +59,8 @@ - ALIAS to bend authentication names around - (UN)BAN_USER to ban really stupid users based on their global user ID - ACCESS_LEVEL_OP/ADMIN/CHAT/PLAY/PLAY_SLIDING to control who can do which things +- /login chat command then uses the more secure hashed base logins +- new chat commands /op, /deop, /promote and /demote to change other players' access rights Featurelets: - --enable-krawallserver has been actually implemented now, and it enables secure logins Modified: armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-24 16:38:19 UTC (rev 7622) +++ armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-24 18:08:19 UTC (rev 7623) @@ -2505,23 +2505,29 @@ login_request_master Master server requires Login. # access level messages -access_level_op_help Minimal access level for /op and /deop commands. +access_level_op_help Minimal access level for /op, /deop, /promote and /demote commands. +access_level_op_max_help Maximal access level attainable by /op and /promote commands. access_level_admin_help Minimal access level for /admin command. access_level_chat_help Minimal access level for chatting access_level_play_help Minimal access level for playing access_level_play_sliding_help Sliding minimal access level for playing; if players of a higher access level than given by ACCESS_LEVEL_PLAY are online, their level will be the minimal level for play; however, it will never be higher than ACCESS_LEVEL_PLAY_SLIDING. access_level_chat_timeout_help Time in seconds between public announcements that someone wants to chat, but can't. Set to 0 to disable the public wanrings. -access_level_chat_request \10xRESETT would like to chat, but is not authorized yet. Would someone be so kind and say "/op \2"?\n +access_level_chat_request \10xRESETT would like to chat, but is not authorized yet. Would someone be so kind and say "/op \2" or "/promote \2"?\n access_level_chat_denied 0xff7f7fChat denied,0xffffff insufficient access level.\n -access_level_op_denied 0xff7f7f/(de)op denied,0xffffff insufficient access level.\n -access_level_op_overpowered 0xff7f7f/(de)op denied,0xffffff your victim has a higher level than you.\n -access_level_op_self 0xff7f7f/(de)op denied,0xffffff can't do that to yourself :).\n -access_level_admin_denied 0xff7f7f/admin denied,0xffffff insufficient access level.\n +access_level_op_denied 0xff7f7f\1 denied,0xffffff insufficient access level.\n +access_level_op_overpowered 0xff7f7f\1 denied,0xffffff your need higher access righrs than your victim.\n +access_level_op_self 0xff7f7f\1 denied,0xffffff can't do that to yourself :).\n +access_level_op_denied_max 0xff7f7f\1 denied,0xffffff your victim already has maximal rights.\n -login_message \1 has been logged in as \2.\n -login_message_special \1 has been logged in as \2 at access level "\3".\n -login_message_op \1 has been given access as \2 at level "\3" by order of \4.\n +access_level_demote \1 has been demoted to "\2" by order of \3.\n +access_level_promote \1 has been promoted to "\2" by order of \3.\n + +access_level_admin_denied 0xff7f7f\1 denied,0xffffff insufficient access level.\n + +login_message \3\1 has been logged in as \2.\n +login_message_byorder Order of \1: +login_message_special \4\1 has been logged in as \2 at access level "\3".\n logout_message \1 has been logged out as \2.\n logout_message_deop \1 has been logged out as \2 by order of \3.\n login_failed_message 0xff7f7fLogin failed,0xffffff reason: \1\n Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-24 16:38:19 UTC (rev 7622) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-24 18:08:19 UTC (rev 7623) @@ -313,7 +313,7 @@ } }; -static tConfItemPassword p; +static tConfItemPassword se_p; // username menu item class eMenuItemUserName: public uMenuItemString @@ -1607,10 +1607,6 @@ static tSettingItem<bool> se_interceptUnknownCommandsConf("INTERCEPT_UNKNOWN_COMMANDS", se_interceptUnknownCommands); -// minimal access level for /op/deop -static tAccessLevel se_opAccessLevel = tAccessLevel_TeamLeader; -static tSettingItem< tAccessLevel > se_opAccessLevelConf( "ACCESS_LEVEL_OP", se_opAccessLevel ); - // minimal access level for /admin static tAccessLevel se_adminAccessLevel = tAccessLevel_Moderator; static tSettingItem< tAccessLevel > se_adminAccessLevelConf( "ACCESS_LEVEL_ADMIN", se_adminAccessLevel ); @@ -1619,6 +1615,131 @@ con << "[cmd] " << *p << ": " << say << '\n'; } +#ifdef KRAWALL_SERVER + +// minimal access level for /op/deop +static tAccessLevel se_opAccessLevel = tAccessLevel_TeamLeader; +static tSettingItem< tAccessLevel > se_opAccessLevelConf( "ACCESS_LEVEL_OP", se_opAccessLevel ); + +// maximal result thereof +static tAccessLevel se_opAccessLevelMax = tAccessLevel_Moderator; +static tSettingItem< tAccessLevel > se_opAccessLevelMaxConf( "ACCESS_LEVEL_OP_MAX", se_opAccessLevelMax ); + +// an operation that changes the access level of another player +typedef void (*OPFUNC)( ePlayerNetID * admin, ePlayerNetID * victim ); +static void se_ChangeAccess( ePlayerNetID * admin, tString say, char const * command, OPFUNC F ) +{ + if ( admin->GetAccessLevel() <= se_opAccessLevel ) + { + ePlayerNetID * victim = se_FindPlayerInChatCommand( admin, command, say ); + if ( victim ) + { + if ( victim == admin ) + { + sn_ConsoleOut( tOutput( "$access_level_op_self", command ), admin->Owner() ); + } + else if ( victim->GetAccessLevel() < admin->GetAccessLevel() ) + { + sn_ConsoleOut( tOutput( "$access_level_op_overpowered", command ), admin->Owner() ); + } + else + { + (*F)( admin, victim ); + } + } + } + else + { + sn_ConsoleOut( tOutput( "$access_level_op_denied", command ), admin->Owner() ); + } +} + +// our operations of this kind: op grants access +void se_OpBase( ePlayerNetID * admin, ePlayerNetID * victim, char const * command, int accessLevel ) +{ + tString authName = victim->GetUserName() + "@L_OP"; + if ( victim->IsAuthenticated() ) + { + authName = victim->GetRawAuthenticatedName(); + } + + if ( accessLevel < se_opAccessLevelMax ) + accessLevel = se_opAccessLevelMax; + + if ( accessLevel > admin->GetAccessLevel() ) + { + victim->Authenticate( authName, static_cast< tAccessLevel >( accessLevel ), admin ); + } + else + { + sn_ConsoleOut( tOutput( "$access_level_op_denied_max", command ), admin->Owner() ); + } +} + +void se_Op( ePlayerNetID * admin, ePlayerNetID * victim ) +{ + int accessLevel = admin->GetAccessLevel() + 1; + + se_OpBase( admin, victim, "/op", accessLevel ); +} + +// DeOp takes it away +void se_DeOp( ePlayerNetID * admin, ePlayerNetID * victim ) +{ + if ( victim->IsAuthenticated() ) + { + victim->DeAuthenticate( admin ); + } +} + +// Promote elevates the access rights +void se_Promote( ePlayerNetID * admin, ePlayerNetID * victim ) +{ + int accessLevelInt = victim->GetAccessLevel() - 1; + tAccessLevel accessLevel = static_cast< tAccessLevel >( accessLevelInt ); + if ( accessLevel > tAccessLevel_Authenticated ) + { + accessLevel = tAccessLevel_Authenticated; + } + + if ( victim->IsAuthenticated() ) + { + victim->SetAccessLevel( accessLevel ); + + sn_ConsoleOut( tOutput( "$access_level_promote", + victim->GetLogName(), + tCurrentAccessLevel::GetName( accessLevel ), + admin->GetLogName() ) ); + } + else + { + se_OpBase( admin, victim, "/promote", accessLevel ); + } +} + +// Deomote reduces the access rights +void se_Demote( ePlayerNetID * admin, ePlayerNetID * victim ) +{ + int accessLevelInt = victim->GetAccessLevel() + 1; + tAccessLevel accessLevel = static_cast< tAccessLevel >( accessLevelInt ); + + if ( accessLevel <= tAccessLevel_Authenticated ) + { + victim->SetAccessLevel( accessLevel ); + + sn_ConsoleOut( tOutput( "$access_level_demote", + victim->GetLogName(), + tCurrentAccessLevel::GetName( accessLevel ), + admin->GetLogName() ) ); + } + else if ( victim->IsAuthenticated() ) + { + victim->DeAuthenticate( admin ); + } +} + +#endif // KRAWALL + void handle_chat_admin_commands(tJUST_CONTROLLED_PTR< ePlayerNetID > &p, tString say){ // for the duration of this function, set the access level to the level of the user. tCurrentAccessLevel levelOverride( p->GetAccessLevel() ); @@ -1709,68 +1830,20 @@ #ifdef KRAWALL_SERVER else if (say.StartsWith("/op")) { - if ( p->GetAccessLevel() <= se_opAccessLevel ) - { - ePlayerNetID * pickup = se_FindPlayerInChatCommand( p, "/op", say ); - if ( pickup ) - { - if ( pickup == p ) - { - sn_ConsoleOut( tOutput( "$access_level_op_self" ), p->Owner() ); - return; - } - - if ( pickup->GetAccessLevel() > p->GetAccessLevel() ) - { - tString authName = pickup->GetUserName() + "@L_OP"; - if ( pickup->IsAuthenticated() ) - { - authName = pickup->GetRawAuthenticatedName(); - } - pickup->Authenticate( authName, static_cast< tAccessLevel >( p->GetAccessLevel() + 1 ), p ); - } - else - { - sn_ConsoleOut( tOutput( "$access_level_op_overpowered" ), p->Owner() ); - } - } - } - else - { - sn_ConsoleOut( tOutput( "$access_level_op_denied" ), p->Owner() ); - } + se_ChangeAccess( p, say, "/op", &se_Op ); } else if (say.StartsWith("/deop")) { - if ( p->GetAccessLevel() <= se_opAccessLevel ) - { - ePlayerNetID * pickup = se_FindPlayerInChatCommand( p, "/deop", say ); - if ( pickup ) - { - if ( pickup == p ) - { - sn_ConsoleOut( tOutput( "$access_level_op_self" ), p->Owner() ); - return; - } - - if ( pickup->GetAccessLevel() > p->GetAccessLevel() ) - { - if ( pickup->IsAuthenticated() ) - { - pickup->DeAuthenticate( p ); - } - } - else - { - sn_ConsoleOut( tOutput( "$access_level_op_overpowered" ), p->Owner() ); - } - } - } - else - { - sn_ConsoleOut( tOutput( "$access_level_op_denied" ), p->Owner() ); - } + se_ChangeAccess( p, say, "/deop", &se_DeOp ); } + else if (say.StartsWith("/promote")) + { + se_ChangeAccess( p, say, "/promote", &se_Promote ); + } + else if (say.StartsWith("/demote")) + { + se_ChangeAccess( p, say, "/demote", &se_Demote ); + } #endif else if (say.StartsWith("/admin")) { if ( p->GetAccessLevel() > se_adminAccessLevel ) @@ -1858,6 +1931,67 @@ return false; } +// handles spam checking at the right time +class eChatSpamTester +{ +public: + eChatSpamTester( REAL severity, ePlayerNetID * p, tString const & say ) + : tested_( false ), shouldBlock_( false ), severity_( severity ), player_( p ), say_( say ) + { + } + + bool Block() + { + if ( !tested_ ) + { + shouldBlock_ = Check(); + tested_ = true; + } + + return shouldBlock_; + } + + bool Check() + { + nTimeRolling currentTime = tSysTimeFloat(); + + // check if the player already said the same thing not too long ago + for (short c = 0; c < player_->lastSaid.Len(); c++) + { + if( (say_.StripWhitespace() == player_->lastSaid[c].StripWhitespace()) && ( (currentTime - player_->lastSaidTimes[c]) < se_alreadySaidTimeout) ) + { + sn_ConsoleOut( tOutput("$spam_protection_repeat", say_ ), player_->Owner() ); + return true; + } + } + + if ( nSpamProtection::Level_Mild <= player_->chatSpam_.CheckSpam( severity_, player_->Owner(), tOutput("$spam_chat") ) ) + { + return true; + } + + // update last said record + { + for( short zz = 12; zz>=1; zz-- ) + { + player_->lastSaid[zz] = player_->lastSaid[zz-1]; + player_->lastSaidTimes[zz] = player_->lastSaidTimes[zz-1]; + } + + player_->lastSaid[0] = say_; + player_->lastSaidTimes[0] = currentTime; + } + + return false; + } + + bool tested_; + bool shouldBlock_; + REAL severity_; + ePlayerNetID * player_; + tString say_; +}; + void handle_chat(nMessage &m){ nTimeRolling currentTime = tSysTimeFloat(); unsigned short id; @@ -1888,26 +2022,19 @@ { lengthMalus = 4.0; } - - if ( !say.StartsWith("/") || say.StartsWith("/me") || say.StartsWith("/msg") || say.StartsWith("/team") ) - { - // check if the player already said the same thing not too long ago - for (short c = 0; c < p->lastSaid.Len(); c++) { - if( (say.StripWhitespace() == p->lastSaid[c].StripWhitespace()) && ( (currentTime - p->lastSaidTimes[c]) < se_alreadySaidTimeout) ) { - sn_ConsoleOut( tOutput("$spam_protection_repeat", say ), m.SenderID() ); - return; - } - } - + + eChatSpamTester spamChatTester( lengthMalus, p, say ); + + #ifdef KRAWALL_SERVER if ( p->GetAccessLevel() > se_chatAccessLevel ) { // check for spam already here - if ( nSpamProtection::Level_Mild <= p->chatSpam_.CheckSpam( 1.0f + lengthMalus, m.SenderID(), tOutput("$spam_chat") ) ) + if ( spamChatTester.Block() ) { return; } - + // every once in a while, remind the public that someone has something to say static double nextRequest = 0; double now = tSysTimeFloat(); @@ -1920,27 +2047,11 @@ { sn_ConsoleOut( tOutput("$access_level_chat_denied" ), m.SenderID() ); } - + return; } #endif - - // update last said record - { - for( short zz = 12; zz>=1; zz-- ) - { - p->lastSaid[zz] = p->lastSaid[zz-1]; - p->lastSaidTimes[zz] = p->lastSaidTimes[zz-1]; - } - - p->lastSaid[0] = say; - p->lastSaidTimes[0] = currentTime; - } - } - - nSpamProtection::Level spamLevel = p->chatSpam_.CheckSpam( 1.0f + lengthMalus, m.SenderID(), tOutput("$spam_chat") ); - bool pass = false; - + if (say.StartsWith("/")) { std::string sayStr(say); std::istringstream s(sayStr); @@ -1960,6 +2071,10 @@ if (command == "/me") { if ( IsSilencedWithWarning(p) ) return; + if ( spamChatTester.Block() ) + { + return; + } tColoredString console; console << tColoredString::ColorString(1,1,1) << "* "; @@ -2059,6 +2174,11 @@ } // Send a message to your team else if (command == "/team") { + if ( spamChatTester.Block() ) + { + return; + } + eTeam *currentTeam = p->CurrentTeam(); if (currentTeam != NULL) // If a player has just joined the game, he is not yet on a team. Sending a /team message will crash the server @@ -2084,6 +2204,11 @@ return; } else if (command == "/msg" ) { + if ( spamChatTester.Block() ) + { + return; + } + int current_place=0; // current place in buffer_name. // search for end of recipient and store recipient in buffer_name @@ -2161,8 +2286,14 @@ #endif } - if ( spamLevel < nSpamProtection::Level_Mild && say.Len() <= se_SpamMaxLen+2 && pass != true && !IsSilencedWithWarning(p) ) + // check for spam + if ( spamChatTester.Block() ) { + return; + } + + if ( say.Len() <= se_SpamMaxLen+2 && !IsSilencedWithWarning(p) ) + { se_BroadcastChat( p, say ); se_DisplayChatLocally( p, say); } @@ -3233,36 +3364,40 @@ return; } + // minimal access level + if ( accessLevel > tAccessLevel_Authenticated ) + { + accessLevel = tAccessLevel_Authenticated; + } + // if a better access level has been passed in, take that if ( accessLevel_ < accessLevel ) { accessLevel = accessLevel_; } + tString order( "" ); + if ( admin ) + { + order = tOutput( "$login_message_byorder", + admin->GetLogName() ); + } + if ( IsHuman() ) { if ( accessLevel < tAccessLevel_Authenticated ) { - if ( admin ) - { - sn_ConsoleOut( tOutput( "$login_message_op", - GetName(), - newAuthenticatedName, - tCurrentAccessLevel::GetName( accessLevel ), - admin->GetLogName() ) ); - } - else - { - sn_ConsoleOut( tOutput( "$login_message_special", - GetName(), - newAuthenticatedName, - tCurrentAccessLevel::GetName( accessLevel ) ) ); - } + sn_ConsoleOut( tOutput( "$login_message_special", + GetName(), + newAuthenticatedName, + tCurrentAccessLevel::GetName( accessLevel ), + order ) ); } else { - sn_ConsoleOut( tOutput( "$login_message", GetName(), newAuthenticatedName ) ); + sn_ConsoleOut( tOutput( "$login_message", GetName(), newAuthenticatedName, order ) ); } + } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <z-...@us...> - 2008-01-25 23:10:08
|
Revision: 7625 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7625&view=rev Author: z-man Date: 2008-01-25 15:10:10 -0800 (Fri, 25 Jan 2008) Log Message: ----------- Documented settings. text input fields now let the text wrap correctly and make use of the space allocated for them in a not-completely-dumb way. And *sigh* depending on the text field, color codes are either ignored (for the usernames) or both displayed in text and rendered. "KICK 2pack" no longer kicks user 2 instead of player 2pack. all admin commands now also accept partial name matches, like /msg, and check for case sensitive matches in the screen name first, then the user name, then case insensitive matches in the two. Added authority black/whitelists. Debug recordings now work with authentication and are safe to share, no secret information is recorded. Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/NEWS armagetronad/branches/0.2.8-auth/armagetronad/config/settings_dedicated.cfg armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt armagetronad/branches/0.2.8-auth/armagetronad/language/english_base_notranslate.txt armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/engine/eVoter.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/engine/eVoter.h armagetronad/branches/0.2.8-auth/armagetronad/src/network/nAuthentification.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawall.h armagetronad/branches/0.2.8-auth/armagetronad/src/network/nKrawallPrivate.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/network/nNetwork.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/network/nNetwork.h armagetronad/branches/0.2.8-auth/armagetronad/src/render/rFont.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/render/rFont.h armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.h armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tString.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tString.h armagetronad/branches/0.2.8-auth/armagetronad/src/tron/gMenus.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/ui/uInputQueue.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/ui/uInputQueue.h armagetronad/branches/0.2.8-auth/armagetronad/src/ui/uMenu.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/ui/uMenu.h Added Paths: ----------- armagetronad/branches/0.2.8-auth/armagetronad/config/settings_authentication.cfg Modified: armagetronad/branches/0.2.8-auth/armagetronad/NEWS =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/NEWS 2008-01-24 18:32:12 UTC (rev 7624) +++ armagetronad/branches/0.2.8-auth/armagetronad/NEWS 2008-01-25 23:10:10 UTC (rev 7625) @@ -51,18 +51,22 @@ console If --enable-armathentication was activated: +- AUTHORITY_WHITELIST and AUTHORITY_BLACKLIST to filter authorities you want on your server. - GLOBAL_ID_ENABLED to toggle remote accounts - LOCAL_USER, LOCAL_TEAM for local login accounts - MD5_PREFIX/MD5_SUFFIX for additional password scrambling - USER_LEVEL to grant users various access levels - RESERVE_SCREEN_NAME to reserve a screen name to a certain player -- ALIAS to bend authentication names around -- (UN)BAN_USER to ban really stupid users based on their global user ID +- USER_ALIAS to bend authentication names around +- (UN)BAN_USER to ban really stupid users based on their global user ID, + BAN_USER_LIST to show a list. - ACCESS_LEVEL_OP/ADMIN/CHAT/PLAY/PLAY_SLIDING to control who can do which things - /login chat command then uses the more secure hashed base logins - new chat commands /op, /deop, /promote and /demote to change other players' access rights Featurelets: +- all admin commands now also accept partial name matches, like /msg, and check for case sensitive + matches in the screen name first, then the user name, then case insensitive matches in the two. - --enable-krawallserver has been actually implemented now, and it enables secure logins to accounts local to the server and not-so-secure logins managed by authentication servers. - A subculture list for server groups that are not managed by our main master servers @@ -109,6 +113,10 @@ - ROUND_SCORE has the player's team's score appended. Bugfixes: +- Text input fields now let the text wrap correctly and make use of the space allocated + for them in a not-completely-dumb way. And *sigh* depending on the text field, color + codes are either ignored (for the usernames) or both displayed in text and rendered. +- "KICK 2pack" no longer kicks user 2 instead of player 2pack. - Fixed various trail end related extrapolation/simulation inaccuracies that looked like lag. - When extrapolating, the game's sensors never detected own or teammates' walls, Added: armagetronad/branches/0.2.8-auth/armagetronad/config/settings_authentication.cfg =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/config/settings_authentication.cfg (rev 0) +++ armagetronad/branches/0.2.8-auth/armagetronad/config/settings_authentication.cfg 2008-01-25 23:10:10 UTC (rev 7625) @@ -0,0 +1,299 @@ +######################################################################### +# IMPORTANT: Users should NOT edit this file. Instead, copy the +# lines you want to change into a new file named autoexec.cfg +# ( either here or in your var directory ). +# This file will be overwritten when you upgrade, autoexec.cfg won't. +# Be sure to save the file as plain text, not rich text, especially +# if you're using TextEdit on a Mac. +######################################################################### + +######################################################################### +# +# Policies +# +######################################################################### + +# As all Armagetron subsystems, Authentication is complex and has many +# options for you to tweak. The policies for the default settings were +# chosen with the following priorities: +# 1. Compatibility with old clients +# 2. Security +# 3. General usability +# If you are a very security aware person, you will probably disagree +# with the priority choilce of 1. vs 2, and want to get maximal security, +# even if that means old clients will not be able to authenticate on +# your server; in this case, uncomment the following line: + +# HASH_METHOD_BLACKLIST bmd5 + +# this will disable the hash protocol clients up to 0.2.8.2.1 knew as +# the only one, which is vulnerable to relatively easy man in the +# middle attacks. New clients will, by default, refuse to use it, so +# if the the admins on your server are well educated and protect their +# login data with all means available to them, which includes using an +# up-to-date client, you should be safe even without this setting. +# You may get the occasional faked login from a regular player, though. + +######################################################################### +# +# Local Accounts +# +######################################################################### + +# To help your local users store their passwords, you should change the +# following settings to something server-specific: + +MD5_PREFIX %u: +MD5_SUFFIX :arma + +# those are strings that are appended/prepended to the password before +# the hash function is applied to them. So far, only the md5 protocol +# supports them, bmd5 ignores them. If you put a %u into the strings, +# it will be replaced by the username. This helps combat precomputation +# attacks; for team accounts, it will force the password to be kept in +# memory in plain text, though (not much of a problem). +# You need to set these up before you define the accounts. + +# The following commands are available for you to create local accounts: + +# LOCAL_USER <user name> <user password> + +# Creates an account for a single player. You should restrict the username +# to ASCII characters, best lowercase letters and numbers, and avoid spaces +# and the symbols @, #, \, :, and %. They will still work, but look ugly +# in the logs and on the screen because they all need to get escaped. +# Spaces in the username, if you absolutely must have them, need to +# be quoted or escaped, the user "Foo Bar" can get an account with either +# LOCAL_USER "Foo Bar" <password> +# or +# LOCAL_USER Foo\ Bar <password> +# You can get a literal \ into a usename by putting it there twice. + +# When logged in, local user accounts will appear as <user name>@ in the logs +# and on the screen, and they will have "Local" access rights by default. + +# You can also define accounts for whole teams with + +# LOCAL_TEAM <team name> <team password> + +# Those accouts will allow login from all usernames with a name starting with +# the team name. Users logged in via such an account will appear as +# <user name>@L_TEAM and get the access rights of "Team Member", more +# about that later. Accounts of this type are intended to be used for organized +# tournaments. + +######################################################################### +# +# Remote Accounts +# +######################################################################### + +# We support a distributed authentication system where a user has to only get +# an account at the authority of his choice and use that to authenticate with +# on all participating servers. By default, this system is disabled. Enable +# it by changing the following setting to 1. + +GLOBAL_ID 0 + +# Your server will then make connection to the remote authentication servers +# every time a user will try to authenticate; those connections will happen +# in the background and should not cause too much extra lag. + +# Accounts from remote authentication servers will appear as +# <user name>@<authority> in your logs. + +# Maybe you don't want to accept logins from all authorities. If you want to +# exclude some, put them into this comma separated list: + +AUTHORITY_BLACKLIST + +# If you only want to accept logins from a selected group of authorities, put +# them into this comma separated list: + +AUTHORITY_WHITELIST + +######################################################################### +# +# Access Rights +# +######################################################################### + +# The old, single password inteface to the /admin command is disabled +# when you compile a server with this authentication. Instead, you +# can assign access rights to individual players with + +# USER_LEVEL <user name> <level> + +# The user name is the user's full authentication name as it appears in +# your logs, with all the escapes and character encodings; the "Foo Bar@" +# user from the example above would usually appear as Foo\_Bar@, and that +# is how you need to put him there. The level is the numberic access level; +# lower values are better. The predefined meanings (of course, you can +# disagree and define your own) of these are: + +# Level Meaning Details +# 0 Owner The owner of the server. Commands entered on the +# server console are executed with these rights. +# 1 Admin A server administrator. By default, almost as +# powerful as the owner himself. +# 2 Moderator A server moderator. Is still allowed to use /admin, +# but is restricted to player management commands. +# 7 Team Leader Leader of a team. By default, no admin rights at all. +# 8 Team Member Member of a team. Local team accounts get this level. +# 12 Local User Players with local accounts get this level. +# 15 Authenticated Players with remote accounts get this level. +# 20 Program Unauthenticated players. + +# As you see, lower numeric values mean more access rights. When we say +# "a user needs at least level X to do Y", that means his numeric level +# needs to be smaller or equal than X. + +# Remote (Global ID) accounts run a slightly higher risk of getting +# compromised than local accounts (simpy due to the fact that they +# will get used more often in more locations), so you should restrict +# Admin and Moderator rights to local accounts. To still have your +# Admins and Moderators appear with their Global ID accounts in your +# logs, use this little trick: define them a local account, give +# the rights to that, and define an alias for the local account: + +# LOCAL_USER z-man <password> +# USER_LEVEL z-man@ 1 +# USER_ALIAS z-man@ Z-Man@forums + +# When your admin then logs in to your server under his global account, +# nothing special happens; only when he uses your local account, he +# will get the access rights, and apart from that, there will be no +# differences; he still wil appear under his global account. + +# You can modifiy the minimal access rights required to do certain things. +# First, there are the administrative chat commands. To use /admin, you +# need to be at least + +ACCESS_LEVEL_ADMIN 2 + +# To use the /op, /dop, /promote and /demote ad-hoc access level modifying +# commands, you need ot have at least + +ACCESS_LEVEL_OP 7 + +# and these commands cannot raise the level of a user above + +ACCESS_LEVEL_OP_MAX 2 + +# (and of course, not above the player issuing these commands.) + +# To play on the server, you need to be at least at + +ACCESS_LEVEL_PLAY 20 + +# However, if users of a higher access level than you are present, and +# your level is below + +ACCESS_LEVEL_PLAY_SLIDING 20 + +# you still will not be able to play. This is for servers with +# flexible tournament schedules, there you'll want to raise +# it to the level of 8 (Team Member), so that once the members +# of teams authorized to play on your server log in, all other +# players get removed. + +# And, lastly, to be able to chat, you need at least this level: + +ACCESS_LEVEL_CHAT 20 + +# If you don't have that, everyone on the server will be reminded +# that you want to chat at most every + +ACCESS_LEVEL_CHAT_TIMEOUT 60 + +# seconds. + +# Having sufficient rights to use /admin does not entitle you to +# use all of the commands; they need to be unlocked for you. +# By default, most Admins can use all commands. To change the +# access level required to use a command, use + +# ACCESS_LEVEL <command> <level> + +# That command itself is by default restricted to be used by +# the owner, because it is the master key to all other commands. +# Sensible commands to unlock for moderator use are: + +ACCESS_LEVEL PLAYER_MESSAGE 2 +ACCESS_LEVEL KICK 2 +ACCESS_LEVEL BAN 2 +ACCESS_LEVEL KICK_TO 2 +ACCESS_LEVEL MOVE_TO 2 +ACCESS_LEVEL KILL 2 +ACCESS_LEVEL SILENCE 2 +ACCESS_LEVEL VOICE 2 +ACCESS_LEVEL CONSOLE_MESSAGE 2 +ACCESS_LEVEL CENTER_MESSAGE 2 + +# If you want to give team members access to the basic /admin command, +# you can also allow them to manage players: + +ACCESS_LEVEL ALLOW_TEAM_CHANGE_PLAYER 7 +ACCESS_LEVEL DISALLOW_TEAM_CHANGE_PLAYER 7 + +######################################################################### +# +# Various +# +######################################################################### + +# The log format in ladderlog.txt is picked so that no unauthenticated +# user can ever appear under the same name as an authenticated user. To +# achieve that, @ signs are escaped for unauthenticated users. That +# changes their names relative to the way they appeared in older versions +# of the server. If you rather want to keep the names of unauthenticated +# players as they were before, change this to 1: + +LEGACY_LOG_NAMES 0 + +# Then, instead of mangling unauthenticated names, the authenticated names +# get a 0: prepended before them. + +# Really, really stupid users can be banned via their user ID with + +# BAN_USER <user> + +# Players of average intellect will not be stopped from playing by this, +# but they won't appear in your logs as authenticated and won't collect +# rating points for their account, so maybe this is not so useless as +# it seems. You can revert a ban with + +# UNBAN_USER <user> + +# and get a list with + +# BAN_USER_LIST + +# You can reserve a screen name to a certain user: + +# RESERVE_SCREEN_NAME <user> <screen name> + +# All other players, authenticated or not, will not be able to change their +# screen name to the picked name, then.The command is of course only +# of use if you have set ALLOW_IMPOSTORS to 0. + +# You can bend authenticated user names around with + +# ALIAS <user> <alias> + +# after doing that, a player who authenticates as <user> will appear +# as <alias>. He will get granted the access rights you gave both +# IDs. + +# By default, the authentication names of all players are visible to +# everyone. You can grant your players a certain degree of anonymity +# by hiding the user names of all players of a certain maximal access +# level with + +ACCESS_LEVEL_HIDE_OF 15 + +# However, to users of the minimal access level + +ACCESS_LEVEL_HIDE_TO 2 + +# , all user names are shown at all times. Modified: armagetronad/branches/0.2.8-auth/armagetronad/config/settings_dedicated.cfg =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/config/settings_dedicated.cfg 2008-01-24 18:32:12 UTC (rev 7624) +++ armagetronad/branches/0.2.8-auth/armagetronad/config/settings_dedicated.cfg 2008-01-25 23:10:10 UTC (rev 7625) @@ -101,6 +101,15 @@ ############################################################################################ # +# Authentication +# +############################################################################################ + +# if you compiled your server with authentication enabled, you can uncomment the following line: +# SINCLUDE settings_authentication.cfg + +############################################################################################ +# # Public information # ############################################################################################ Modified: armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-24 18:32:12 UTC (rev 7624) +++ armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-25 23:10:10 UTC (rev 7625) @@ -2277,8 +2277,6 @@ voted_kill_kick You have been kicked by an angry mob of players; please stay away. network_kill_spectator You have been sitting in spectator mode for too long. -network_kick_notfound Player \1 not found. Remember that the matching is case sensitive.\n - network_ban_kph Kicks per hour of IP \1 are now \2.\n network_ban Players from IP \1 are banned for \2 minutes. Reason: \3\n network_noban Players from IP \1 are no longer banned.\n @@ -2450,8 +2448,8 @@ config_accesslevel_2 Moderator config_accesslevel_7 Team Leader config_accesslevel_8 Team Member -config_accesslevel_9 Local User -config_accesslevel_10 Authenticated +config_accesslevel_12 Local User +config_accesslevel_15 Authenticated config_accesslevel_20 Program access_level_help Changes the access level of a configuration item to make it available to lower ranked users @@ -2497,7 +2495,7 @@ login_request_redundant Already logged in. login_request_failed Login failed. Try again! -login_request_failed_dup Two logins with the same account are not permitted. +login_request_failed_dup Two logins with the same account are not permitted.\n login_not_supported This server does not support authentication of the type you requested, sorry.\n login_request Login with Authority \1 login_request_local Login with Local Account @@ -2505,6 +2503,8 @@ login_request_master Master server requires Login. # access level messages +access_level_hide_of_help Hide user account information of players with at most this access level. +access_level_hide_to_help Hide user account information to players with less than this access level. access_level_op_help Minimal access level for /op, /deop, /promote and /demote commands. access_level_op_max_help Maximal access level attainable by /op and /promote commands. access_level_admin_help Minimal access level for /admin command. @@ -2525,6 +2525,13 @@ access_level_admin_denied 0xff7f7f\1 denied,0xffffff insufficient access level.\n +authority_blacklist_help Comma separated list of authorities your server should refuse to query. +authority_whitelist_help If non-empty, only authorities on this comma separated list will be queried by your server. +trust_lan_help If set to 1, the server assumes that your LAN is safe and that nobody can run a pharming server on it. +hash_method_blacklist_help List of hash authentication methods to disable support for. + +login_message_requested User \1 requests authentication as "\2@\3".\n +login_message_responded Password request sent to user \1, username "\2", method \3, message "\4".\n login_message \3\1 has been logged in as \2.\n login_message_byorder Order of \1: login_message_special \4\1 has been logged in as \2 at access level "\3".\n @@ -2541,6 +2548,9 @@ login_error_invalidurl_slash Authentication URL \1 invalid, double slash or ending with slash. login_error_invalidurl_notfound Authentication URL \1 invalid, it was not found. login_error_noremote Authentication via Global ID not available on this server. +login_error_blacklist Authority \1 is on this server's blacklist. +login_error_whitelist Authority \1 is not on this server's whitelist. +login_error_pharm Server adress mismatch, \1 (sent by client) != \2 (our address). Pharming suspected. If you are connecting from the LAN and get this error, either set "TRUST_LAN" on the server (only if your LAN can be fully trusted, of course) or use "SERVER_IP" to make the local IP known to the server. login_error_methodmismatch The local method used for auhtentication has been modified since your password was set. In the server's config files, put all commands that define authentication methods before all local password definitions. login_error_nomethod No authentication method could be found. Your client supports \1, this server supports \2, and the authentication server supports \3. login_error_nomethodlist Authentication URL \1 does not return a list of supported methods. @@ -2573,7 +2583,7 @@ reserve_screen_namne_usage Usage: RESERVE_SCREEN_NAME <screen name (in quotes if it contains spaces)> <user> reserve_screen_name_change Screen name "\1" reserved for user \2.\n -alias_help Allows bending authenticated names around: a player authenticated as X originally can appear as y. +user_alias_help Allows bending authenticated names around: a player authenticated as X originally can appear as y. alias_usage Usage: ALIAS <user> <alias of user> alias_change User \1 will be known as \2.\n @@ -2581,11 +2591,12 @@ ban_user_message User \1 has been banned.\n unban_user_help Undoes BAN_USER. unban_user_message User \1 has been unbanned.\n +ban_user_list_help Gives a list of banned users. md5_prefix_help Extra hash prefix for local accounts used to scramble the password md5_suffix_help Extra hash suffix for local accounts used to scramble the password -global_id_enabled_help If set to 0, Global IDs (Armathentication) will be disabled on this server. +global_id_help If set to 1, Global IDs (Armathentication) will be enabled on this server. # items that should not be translated include english_base_notranslate.txt Modified: armagetronad/branches/0.2.8-auth/armagetronad/language/english_base_notranslate.txt =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base_notranslate.txt 2008-01-24 18:32:12 UTC (rev 7624) +++ armagetronad/branches/0.2.8-auth/armagetronad/language/english_base_notranslate.txt 2008-01-25 23:10:10 UTC (rev 7625) @@ -184,12 +184,12 @@ config_accesslevel_4 Moderator-3 config_accesslevel_5 Moderator-4 config_accesslevel_6 Moderator-5 -config_accesslevel_11 OP-ed -config_accesslevel_12 OP-ed-2 -config_accesslevel_13 OP-ed-3 -config_accesslevel_14 OP-ed-4 -config_accesslevel_15 OP-ed-5 -config_accesslevel_16 OP-ed-6 -config_accesslevel_17 OP-ed-7 -config_accesslevel_18 OP-ed-8 -config_accesslevel_19 OP-ed-9 +config_accesslevel_9 Recruit +config_accesslevel_10 Recruit-1 +config_accesslevel_11 Recruit-2 +config_accesslevel_13 OP-ed +config_accesslevel_14 OP-ed-2 +config_accesslevel_16 OP-ed-3 +config_accesslevel_17 OP-ed-4 +config_accesslevel_18 OP-ed-5 +config_accesslevel_19 OP-ed-6 Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-24 18:32:12 UTC (rev 7624) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-25 23:10:10 UTC (rev 7625) @@ -49,6 +49,7 @@ #include "eVoter.h" #include "tReferenceHolder.h" #include "tRandom.h" +#include "uInputQueue.h" #include "nServerInfo.h" #include "tRecorder.h" #include "nConfig.h" @@ -88,7 +89,7 @@ // if unsed, usernames of non-authenticated players get all special characters escaped (especially all @) // and usernames of authenticated players get left as they are (with all special characters except the last // escaped.) -bool se_legacyLogNames = true; +bool se_legacyLogNames = false; static tSettingItem<bool> se_llnConf("LEGACY_LOG_NAMES", se_legacyLogNames ); // transform special characters in name to escape sequences @@ -455,11 +456,18 @@ failure = true; } + static char const * section = "PASSWORD_MENU"; + tRecorder::Playback( section, failure ); + tRecorder::Record( section, failure ); + // immediately return the stored password if it was not marked as wrong: if (!failure) { - answer.username = storage->username; - answer.scrambled = storage->password; + if ( storage ) + { + answer.username = storage->username; + answer.scrambled = storage->password; + } answer.automatic = true; return; @@ -467,8 +475,10 @@ else storage->username.Clear(); + // scramble input for recording + uInputScrambler scrambler; + // password was not stored. Request it from user: - uMenu login(message, false); // password storage; @@ -476,7 +486,8 @@ eMenuItemPassword pw(&login, password); eMenuItemUserName us(&login, username); - + us.SetColorMode( rTextField::COLOR_IGNORE ); + uMenuItemSelection<int> storepw(&login, "$login_storepw_text", "$login_storepw_help", @@ -503,7 +514,7 @@ // return username/scrambled password { // scramble password - request.ScramblePassword( nKrawall::nScrambleInfo( username), password, scrambled ); + request.ScramblePassword( nKrawall::nScrambleInfo( username ), password, scrambled ); // if S_login still exists, we were not canceled answer.aborted = !eMenuItemPassword::entered; @@ -567,22 +578,71 @@ return min; } +// maximal user level whose accounts are hidden from other users +static tAccessLevel se_hideAccessLevelOf = tAccessLevel_Program; +static tSettingItem< tAccessLevel > se_hideAccessLevelOfConf( "ACCESS_LEVEL_HIDE_OF", se_hideAccessLevelOf ); + +// but they are only hidden to players with a lower access level than this +static tAccessLevel se_hideAccessLevelTo = tAccessLevel_Moderator; +static tSettingItem< tAccessLevel > se_hideAccessLevelToConf( "ACCESS_LEVEL_HIDE_TO", se_hideAccessLevelTo ); + +// determines whether hider can hide from seeker +static bool se_Hide( ePlayerNetID const * hider, ePlayerNetID const * seeker ) +{ + tASSERT( hider ); + if ( !seeker || seeker == hider ) + { + return false; + } + + return + hider->GetAccessLevel() >= se_hideAccessLevelOf && + seeker->GetAccessLevel() > se_hideAccessLevelTo; +} + +// console messages for players who can see users of access level hider +void se_SecretConsoleOut( tOutput const & message, tAccessLevel hider ) +{ + // high enough access levels are never secret + if ( hider < se_hideAccessLevelOf ) + { + sn_ConsoleOut( message ); + } + else + { + bool canSee[ MAXCLIENTS+1 ]; + for( int i = MAXCLIENTS; i>=0; --i ) + { + canSee[i] = false; + } + + // look which clients have someone who can see the message + for ( int i = se_PlayerNetIDs.Len()-1; i>=0; --i ) + { + ePlayerNetID* player = se_PlayerNetIDs(i); + if ( player->GetAccessLevel() <= se_hideAccessLevelTo ) + { + canSee[ player->Owner() ] = true; + } + } + + // and send it + for( int i = MAXCLIENTS; i>=0; --i ) + { + if ( canSee[i] ) + { + sn_ConsoleOut( message, i ); + } + } + } +} + static void ResultCallback( nKrawall::nCheckResult const & result ) { tString username = result.username; tString authority = result.authority; bool success = result.success; - // record and playback result (required because on playback, a new - // salt is generated and this way, a recoding does not contain ANY - // exploitable information for password theft: the scrambled password - // stored in the incoming network stream has an unknown salt value. ) - static char const * section = "AUTH"; - tRecorder::Playback( section, success ); - tRecorder::Playback( section, authority ); - tRecorder::Record( section, success ); - tRecorder::Record( section, authority ); - ePlayerNetID * player = dynamic_cast< ePlayerNetID * >( static_cast< nNetObject * >( result.user ) ); if ( !player || player->Owner() <= 0 ) { @@ -598,7 +658,7 @@ ePlayerNetID* player = se_PlayerNetIDs(i); if ( player->IsAuthenticated() && player->GetRawAuthenticatedName() == authName ) { - sn_ConsoleOut( tOutput("$login_failed_message_dup"), player->Owner() ); + sn_ConsoleOut( tOutput("$login_request_failed_dup"), player->Owner() ); return; } } @@ -620,11 +680,12 @@ { tOutput out( tOutput("$login_failed_message", result.error ) ); sn_ConsoleOut( out, player->Owner() ); + con << out; // redo automatic logins immedeately if ( result.automatic ) { - nAuthentification::RequestLogin( authority ,player->GetUserName(), *player, "$login_request_failed" ); + nAuthentification::RequestLogin( authority ,username , *player, "$login_request_failed" ); } } } @@ -632,6 +693,11 @@ // continue with scheduled logon messages ePlayerNetID::RequestScheduledLogins(); } +#else +static bool se_Hide( ePlayerNetID const * hider, ePlayerNetID const * seeker ) +{ + return false; +} #endif @@ -1162,7 +1228,32 @@ return false; } -ePlayerNetID * CompareBufferToPlayerNames( const tString & current_buffer, int & num_matches ) { +// function that returns one of the player names +typedef tString const & (ePlayerNetID::*SE_NameGetter)() const; + +// function that filters strings +typedef tString (*SE_NameFilter)( tString const & ); + +// identity filter +static tString se_NameFilterID( tString const & name ) +{ + return name; +} + +// function that filters player pairs +typedef bool (*SE_NameHider)( ePlayerNetID const * hider, ePlayerNetID const * seeker ); + +// non-hider +static bool se_NonHide( ePlayerNetID const * hider, ePlayerNetID const * seeker ) +{ + return false; +} + +// the other filter is ePlayerNetID::FilterName + +// search for exact or partial matches in player names +ePlayerNetID * CompareBufferToPlayerNames( const tString & name, int & num_matches, ePlayerNetID * requester, SE_NameGetter GetName = &ePlayerNetID::GetName, SE_NameFilter Filter = &se_NameFilterID, SE_NameHider Hider = &se_NonHide ) +{ num_matches = 0; ePlayerNetID * match = 0; @@ -1170,14 +1261,21 @@ for ( int a = se_PlayerNetIDs.Len()-1; a>=0; --a ) { ePlayerNetID* toMessage = se_PlayerNetIDs(a); + if ( (*Hider)( toMessage, requester ) ) + { + continue; + } + + tString playerName = (*Filter)( (toMessage->*GetName)() ); + // exact match? - if ( current_buffer == toMessage->GetUserName() ) + if ( playerName == name ) { num_matches = 1; return toMessage; } - if ( Contains(current_buffer, toMessage->GetUserName())) { + if ( Contains(name, playerName)) { match= toMessage; // Doesn't matter that this is wrote over everytime, when we only have one match it will be there. num_matches+=1; } @@ -1187,20 +1285,55 @@ return match; } -ePlayerNetID * se_FindPlayerByName( tString const & username, ePlayerNetID * requester = 0 ) +ePlayerNetID * se_FindPlayerByName( tString const & name, ePlayerNetID * requester = 0 ) { int num_matches = 0; - ePlayerNetID * ret = CompareBufferToPlayerNames( username, num_matches ); - + // look for matches in the exact player names first + ePlayerNetID * ret = CompareBufferToPlayerNames( name, num_matches, requester ); if ( ret && num_matches == 1 ) { return ret; } + // ok, next round: try filtering the names before comparing them, this makes the matching case-insensitive + SE_NameFilter Filter = &ePlayerNetID::FilterName; + + // look for matches in the screen names again + if ( !ret ) + { + ret = CompareBufferToPlayerNames( name, num_matches, requester, &ePlayerNetID::GetName, Filter ); + } + if ( ret && num_matches == 1 ) + { + return ret; + } + +#ifdef KRAWALL_SERVER + // nothing found? try the user names. + if ( !ret ) + { + ret = CompareBufferToPlayerNames( name, num_matches, requester, &ePlayerNetID::GetUserName, &se_NameFilterID, &se_Hide ); + } + if ( ret && num_matches == 1 ) + { + return ret; + } + + // still nothing found? user names again + if ( !ret ) + { + ret = CompareBufferToPlayerNames( name, num_matches, requester, &ePlayerNetID::GetUserName, Filter, &se_Hide ); + } + if ( ret && num_matches == 1 ) + { + return ret; + } +#endif + // More than than one match for the current buffer. Complain about that. else if (num_matches > 1) { - tOutput toSender( "$msg_toomanymatches", username ); + tOutput toSender( "$msg_toomanymatches", name ); if ( requester ) { sn_ConsoleOut(toSender,requester->Owner() ); @@ -1213,7 +1346,7 @@ } // 0 matches. The user can't spell. Complain about that, too. else { - tOutput toSender( "$msg_nomatch", username ); + tOutput toSender( "$msg_nomatch", name ); if ( requester ) { sn_ConsoleOut(toSender,requester->Owner() ); @@ -1226,24 +1359,18 @@ } } -#ifdef DEDICATED -#ifdef KRAWALL_SERVER -static ePlayerNetID * se_FindPlayerInChatCommand( ePlayerNetID * sender, char const * command, tString const & say ) +static ePlayerNetID * se_FindPlayerInChatCommand( ePlayerNetID * sender, char const * command, std::istream & s ) { - tString params(""); - if (say.StrPos(" ") == -1) + tString player; + s >> player; + + if (player == "" ) { sn_ConsoleOut( tOutput( "$chatcommand_requires_player", command ), sender->Owner() ); } - else - { - params = say.SubStr(say.StrPos(" ") + 1); - } - return se_FindPlayerByName( params, sender ); + return se_FindPlayerByName( player, sender ); } -#endif -#endif // chat message from server to client void handle_chat_client( nMessage & ); @@ -1607,7 +1734,7 @@ static tAccessLevel se_adminAccessLevel = tAccessLevel_Moderator; static tSettingItem< tAccessLevel > se_adminAccessLevelConf( "ACCESS_LEVEL_ADMIN", se_adminAccessLevel ); -void handle_command_intercept(tJUST_CONTROLLED_PTR< ePlayerNetID > &p, tString say) { +void handle_command_intercept(ePlayerNetID *p, tString say) { con << "[cmd] " << *p << ": " << say << '\n'; } @@ -1623,11 +1750,11 @@ // an operation that changes the access level of another player typedef void (*OPFUNC)( ePlayerNetID * admin, ePlayerNetID * victim ); -static void se_ChangeAccess( ePlayerNetID * admin, tString say, char const * command, OPFUNC F ) +static void se_ChangeAccess( ePlayerNetID * admin, std::istream & s, char const * command, OPFUNC F ) { if ( admin->GetAccessLevel() <= se_opAccessLevel ) { - ePlayerNetID * victim = se_FindPlayerInChatCommand( admin, command, say ); + ePlayerNetID * victim = se_FindPlayerInChatCommand( admin, command, s ); if ( victim ) { if ( victim == admin ) @@ -1702,10 +1829,10 @@ { victim->SetAccessLevel( accessLevel ); - sn_ConsoleOut( tOutput( "$access_level_promote", - victim->GetLogName(), - tCurrentAccessLevel::GetName( accessLevel ), - admin->GetLogName() ) ); + se_SecretConsoleOut( tOutput( "$access_level_promote", + victim->GetLogName(), + tCurrentAccessLevel::GetName( accessLevel ), + admin->GetLogName() ), victim->GetAccessLevel() ); } else { @@ -1721,12 +1848,12 @@ if ( accessLevel <= tAccessLevel_Authenticated ) { + se_SecretConsoleOut( tOutput( "$access_level_demote", + victim->GetLogName(), + tCurrentAccessLevel::GetName( accessLevel ), + admin->GetLogName() ), victim->GetAccessLevel() ); + victim->SetAccessLevel( accessLevel ); - - sn_ConsoleOut( tOutput( "$access_level_demote", - victim->GetLogName(), - tCurrentAccessLevel::GetName( accessLevel ), - admin->GetLogName() ) ); } else if ( victim->IsAuthenticated() ) { @@ -1736,136 +1863,151 @@ #endif // KRAWALL -void handle_chat_admin_commands(tJUST_CONTROLLED_PTR< ePlayerNetID > &p, tString say){ - // for the duration of this function, set the access level to the level of the user. - tCurrentAccessLevel levelOverride( p->GetAccessLevel() ); - - if (say.StartsWith("/login")) { - tString params(""); - if (say.StrPos(" ") == -1) - { +// log in (via admin password or hash based login) +static void se_AdminLogin( ePlayerNetID * p, tString const & say ) +{ + tString params(""); + if (say.StrPos(" ") == -1) + { #ifndef KRAWALL_SERVER - return; + return; #endif - } - else - { - params = say.SubStr(say.StrPos(" ") + 1); - } - + } + else + { + params = say.SubStr(say.StrPos(" ") + 1); + } + #ifndef KRAWALL_SERVER - // the password is not stored in the recording, hence we have to store the - // result of the password test - bool accept = true; - static const char * section = "REMOTE_LOGIN"; - if ( !tRecorder::Playback( section, accept ) ) - accept = ( params == sg_adminPass && sg_adminPass != "NONE" ); - tRecorder::Record( section, accept ); - - //change this later to read from a password file or something... - //or integrate it with auth if we ever get that done... - if ( accept ) { - se_AdminLogin( p ); - } - else + // the password is not stored in the recording, hence we have to store the + // result of the password test + bool accept = true; + static const char * section = "REMOTE_LOGIN"; + if ( !tRecorder::Playback( section, accept ) ) + accept = ( params == sg_adminPass && sg_adminPass != "NONE" ); + tRecorder::Record( section, accept ); + + //change this later to read from a password file or something... + //or integrate it with auth if we ever get that done... + if ( accept ) { + se_AdminLogin( p ); + } + else + { + tString failedLogin; + sn_ConsoleOut("Login denied!\n",p->Owner()); + failedLogin << "Remote admin login for user \"" << p->GetUserName(); + failedLogin << "\" using password \"" << params << "\" rejected.\n"; + sn_ConsoleOut(failedLogin, 0); + } +#else + if ( sn_GetNetState() == nSERVER && p->Owner() != sn_myNetID ) + { + if ( p->IsAuthenticated() ) { - tString failedLogin; - sn_ConsoleOut("Login denied!\n",p->Owner()); - failedLogin << "Remote admin login for user \"" << p->GetUserName(); - failedLogin << "\" using password \"" << params << "\" rejected.\n"; - sn_ConsoleOut(failedLogin, 0); + sn_ConsoleOut( "$login_request_redundant", p->Owner() ); + return; } -#else - if ( sn_GetNetState() == nSERVER && p->Owner() != sn_myNetID ) + + if ( p->GetRawAuthenticatedName().Len() <= 1 || params.StrPos("@") >= 0 ) { - if ( p->IsAuthenticated() ) + if ( params.StrPos( "@" ) >= 0 ) { - sn_ConsoleOut( "$login_request_redundant", p->Owner() ); - return; + p->SetRawAuthenticatedName( params ); } - - if ( p->GetRawAuthenticatedName().Len() <= 1 || params.StrPos("@") >= 0 ) + else { - if ( params.StrPos( "@" ) >= 0 ) - { - p->SetRawAuthenticatedName( params ); - } - else - { - p->SetRawAuthenticatedName( p->GetUserName() + "@" + params ); - } + p->SetRawAuthenticatedName( p->GetUserName() + "@" + params ); } - - // check for stupid bans - if ( se_IsUserBanned( p, p->GetRawAuthenticatedName() ) ) - { - return; - } - - p->loginWanted = true; - - se_RequestLogin( p ); } + + // check for stupid bans + if ( se_IsUserBanned( p, p->GetRawAuthenticatedName() ) ) + { + return; + } + + p->loginWanted = true; + + se_RequestLogin( p ); + } #endif +} + +// log out +static void se_AdminLogout( ePlayerNetID * p ) +{ +#ifdef KRAWALL_SERVER + // revoke the other kind of authentication as well + if ( p->IsAuthenticated() ) + { + p->DeAuthenticate(); } - else if (say.StartsWith("/logout")) { -#ifdef KRAWALL_SERVER - // revoke the other kind of authentication as well - if ( p->IsAuthenticated() ) - { - p->DeAuthenticate(); - } #else - if ( p->IsLoggedIn() ) - { - sn_ConsoleOut("You have been logged out!\n",p->Owner()); - } - p->BeNotLoggedIn(); + if ( p->IsLoggedIn() ) + { + sn_ConsoleOut("You have been logged out!\n",p->Owner()); + } + p->BeNotLoggedIn(); #endif +} + +// /admin chat command +static void se_AdminAdmin( ePlayerNetID * p, std::istream & s ) +{ + if ( p->GetAccessLevel() > se_adminAccessLevel ) + { + sn_ConsoleOut( tOutput( "$access_level_admin_denied" ), p->Owner() ); + return; } + + // install filter + eAdminConsoleFilter consoleFilter( p->Owner() ); + + if ( tRecorder::IsPlayingBack() ) + { + tConfItemBase::LoadPlayback(); + } + else + { + tConfItemBase::LoadAll(s); + } +} + +static void handle_chat_admin_commands( ePlayerNetID * p, tString const & say, std::istream & s ) +{ + // for the duration of this function, set the access level to the level of the user. + tCurrentAccessLevel levelOverride( p->GetAccessLevel() ); + + if (say.StartsWith("/login")) + { + se_AdminLogin( p, say ); + } + else if (say.StartsWith("/logout")) + { + se_AdminLogout( p ); + } #ifdef KRAWALL_SERVER else if (say.StartsWith("/op")) { - se_ChangeAccess( p, say, "/op", &se_Op ); + se_ChangeAccess( p, s, "/op", &se_Op ); } else if (say.StartsWith("/deop")) { - se_ChangeAccess( p, say, "/deop", &se_DeOp ); + se_ChangeAccess( p, s, "/deop", &se_DeOp ); } else if (say.StartsWith("/promote")) { - se_ChangeAccess( p, say, "/promote", &se_Promote ); + se_ChangeAccess( p, s, "/promote", &se_Promote ); } else if (say.StartsWith("/demote")) { - se_ChangeAccess( p, say, "/demote", &se_Demote ); + se_ChangeAccess( p, s, "/demote", &se_Demote ); } #endif - else if (say.StartsWith("/admin")) { - if ( p->GetAccessLevel() > se_adminAccessLevel ) - { - sn_ConsoleOut( tOutput( "$access_level_admin_denied" ), p->Owner() ); - return; - } - - tString params(""); - if (say.StrPos(" ") == -1) - return; - else - params = say.SubStr(say.StrPos(" ") + 1); - - // install filter - eAdminConsoleFilter consoleFilter( p->Owner() ); - - if ( tRecorder::IsPlayingBack() ) - { - tConfItemBase::LoadPlayback(); - } - else - { - std::stringstream s(static_cast< char const * >( params ) ); - tConfItemBase::LoadAll(s); - } + else if (say.StartsWith("/admin")) + { + se_AdminAdmin( p, s ); } else if (se_interceptUnknownCommands) @@ -1902,37 +2044,12 @@ static tSettingItem<bool> se_silAll("SILENCE_ALL", se_silenceAll); - -// checks whether a player is silenced, giving him appropriate warnings if he is -bool IsSilencedWithWarning( ePlayerNetID const * p ) -{ - if ( !se_enableChat && ! p->IsLoggedIn() ) - { - // everyone except the admins is silenced - sn_ConsoleOut( tOutput( "$spam_protection_silenceall" ), p->Owner() ); - return true; - } - else if ( p->IsSilenced() ) - { - if(se_silenceAll) { - // player is silenced, but all players are silenced by default - sn_ConsoleOut( tOutput( "$spam_protection_silenced_default" ), p->Owner() ); - } else { - // player is specially silenced - sn_ConsoleOut( tOutput( "$spam_protection_silenced" ), p->Owner() ); - } - return true; - } - - return false; -} - // handles spam checking at the right time class eChatSpamTester { public: - eChatSpamTester( REAL severity, ePlayerNetID * p, tString const & say ) - : tested_( false ), shouldBlock_( false ), severity_( severity ), player_( p ), say_( say ) + eChatSpamTester( ePlayerNetID * p, tString const & say ) + : tested_( false ), shouldBlock_( false ), player_( p ), say_( say ) { } @@ -1961,8 +2078,14 @@ } } - if ( nSpamProtection::Level_Mild <= player_->chatSpam_.CheckSpam( severity_, player_->Owner(), tOutput("$spam_chat") ) ) + REAL lengthMalus = say_.Len() / 20.0; + if ( lengthMalus > 4.0 ) { + lengthMalus = 4.0; + } + + if ( nSpamProtection::Level_Mild <= player_->chatSpam_.CheckSpam( 1+lengthMalus, player_->Owner(), tOutput("$spam_chat") ) ) + { return true; } @@ -2003,12 +2126,272 @@ bool tested_; bool shouldBlock_; - REAL severity_; ePlayerNetID * player_; tString say_; }; -void handle_chat(nMessage &m){ +// checks whether a player is silenced, giving him appropriate warnings if he is +bool IsSilencedWithWarning( ePlayerNetID const * p ) +{ + if ( !se_enableChat && ! p->IsLoggedIn() ) + { + // everyone except the admins is silenced + sn_ConsoleOut( tOutput( "$spam_protection_silenceall" ), p->Owner() ); + return true; + } + else if ( p->IsSilenced() ) + { + if(se_silenceAll) { + // player is silenced, but all players are silenced by default + sn_ConsoleOut( tOutput( "$spam_protection_silenced_default" ), p->Owner() ); + } else { + // player is specially silenced + sn_ConsoleOut( tOutput( "$spam_protection_silenced" ), p->Owner() ); + } + return true; + } + + return false; +} + +// /me chat commant +static void se_ChatMe( ePlayerNetID * p, std::istream & s, eChatSpamTester & spam ) +{ + if ( IsSilencedWithWarning(p) || spam.Block() ) + { + return; + } + + tString msg; + msg.ReadLine( s ); + + tColoredString console; + console << tColoredString::ColorString(1,1,1) << "* "; + console << *p; + console << tColoredString::ColorString(1,1,.5) << " " << msg; + console << tColoredString::ColorString(1,1,1) << " *"; + + tColoredString forOldClients; + forOldClients << tColoredString::ColorString(1,1,1) << "*" + << tColoredString::ColorString(1,1,.5) << msg + << tColoredString::ColorString(1,1,1) << "*"; + + se_BroadcastChatLine( p, console, forOldClients ); + console << "\n"; + sn_ConsoleOut(console,0); + return; +} + +// /teamleave chat command: leaves the current team +static void se_ChatTeamLeave( ePlayerNetID * p ) +{ + if ( se_assignTeamAutomatically ) + { + sn_ConsoleOut(tOutput("$player_teamleave_disallowed"), p->Owner() ); + return; + } + if(!p->TeamChangeAllowed()) { + sn_ConsoleOut(tOutput("$player_disallowed_teamchange"), p->Owner() ); + return; + } + + eTeam * leftTeam = p->NextTeam(); + if ( leftTeam ) + { + if ( !leftTeam ) + leftTeam = p->CurrentTeam(); + + if ( leftTeam->NumPlayers() > 1 ) + { + sn_ConsoleOut( tOutput( "$player_leave_team_wish", + tColoredString::RemoveColors(p->GetName()), + tColoredString::RemoveColors(leftTeam->Name()) ) ); + } + else + { + sn_ConsoleOut( tOutput( "$player_leave_game_wish", + tColoredString::RemoveColors(p->GetName()) ) ); + } + } + + p->SetTeamWish(0); +} + +// team shuffling: reorders team formation +static void se_ChatShuffle( ePlayerNetID * p, std::istream & s ) +{ + tString msg; + msg.ReadLine( s ); + + // team position shuffling. Allow players to change their team setup. + // syntax: + // /teamshuffle: shuffles you all the way to the outside. + // /teamshuffle <pos>: shuffles you to position pos + // /teamshuffle +/-<dist>: shuffles you dist to the outside/inside + // con << msgRest << "\n"; + int IDNow = p->TeamListID(); + if (!p->CurrentTeam()) + { + sn_ConsoleOut(tOutput("$player_not_on_team"), p->Owner()); + return; + } + int len = p->CurrentTeam()->NumPlayers(); + int IDWish = len-1; // default to shuffle to the outside + + // but read the target position as additional parameter + if (msg.Len() > 1) + { + IDWish = IDNow; + if ( msg[0] == '+' ) + IDWish += msg.toInt(1); + else if ( msg[0] == '-' ) + IDWish -= msg.toInt(1); + else + IDWish = msg.toInt()-1; + } + + if (IDWish < 0) + IDWish = 0; + if (IDWish >= len) + IDWish = len-1; + + if ( !se_allowShuffleUp && IDWish < IDNow ) + { + sn_ConsoleOut(tOutput("$player_noshuffleup"), p->Owner()); + return; + } + + if( IDNow == IDWish ) + { + sn_ConsoleOut(tOutput("$player_noshuffle"), p->Owner()); + } + + p->CurrentTeam()->Shuffle( IDNow, IDWish ); +} + +// /team chat commant: talk to your team +static void se_ChatTeam( ePlayerNetID * p, std::istream & s, eChatSpamTester & spam ) +{ + // odd, the refactored original did not check for silence. Probably by design. + if ( /* IsSilencedWithWarning(player) || */ spam.Block() ) + { + return; + } + + tString msg; + msg.ReadLine( s ); + + eTeam *currentTeam = p->CurrentTeam(); + + if (currentTeam != NULL) // If a player has just joined the game, he is not yet on a team. Sending a /team message will crash the server + { + // Log message to server and sender + tColoredString messageForServerAndSender = se_BuildChatString(currentTeam, p, msg); + messageForServerAndSender << "\n"; + sn_ConsoleOut(messageForServerAndSender, 0); + sn_ConsoleOut(messageForServerAndSender, p->Owner()); + + // Send message to team-mates + int numTeamPlayers = currentTeam->NumPlayers(); + for (int teamPlayerIndex = 0; teamPlayerIndex < numTeamPlayers; teamPlayerIndex++) { + if (currentTeam->Player(teamPlayerIndex)->Owner() != p->Owner()) // Do not resend the message to yourself + se_SendTeamMessage(currentTeam, p, currentTeam->Player(teamPlayerIndex), msg); + } + } + else + { + sn_ConsoleOut(tOutput("$player_not_on_team"), p->Owner()); + } +} + +// /team chat commant: talk to your team +static void se_ChatMsg( ePlayerNetID * p, std::istream & s, eChatSpamTester & spam ) +{ + // odd, the refactored original did not check for silence. Probably by design. + if ( /* IsSilencedWithWarning(player) || */ spam.Block() ) + { + return; + } + + // Check for player + ePlayerNetID * receiver = se_FindPlayerInChatCommand( p, "/msg", s ); + + // One match, send it. + if ( receiver ) { + // extract rest of message: it is the true message to send + std::ws(s); + + // read the rest of the message + tString msg_core; + msg_core.ReadLine(s); + + // build chat string + tColoredString toServer = se_BuildChatString( p, receiver, msg_core ); + toServer << '\n'; + + // log locally + sn_ConsoleOut(toServer,0); + + if ( p->CurrentTeam() == receiver->CurrentTeam() || !IsSilencedWithWarning(p) ) + { + // log to sender's console + sn_ConsoleOut(toServer, p->Owner()); + + // send to receiver + if ( p->Owner() != receiver->Owner() ) + se_SendPrivateMessage( p, receiver, msg_core ); + } + } +} + +static void ListPlayers( ePlayerNetID * receiver ) +{ + for ( int i2 = se_PlayerNetIDs.Len()-1; i2>=0; --i2 ) + { + ePlayerNetID* p2 = se_PlayerNetIDs(i2); + std::ostringstream tos; + tos << p2->Owner(); + tos << ": "; + if ( p2->GetLastAccessLevel() < tAccessLevel_Default && !se_Hide( p2, receiver ) ) + { + // player username comes from authentication name and may be much different from + // the screen name + tos << p2->GetUserName() << " ( " << p2->GetName() << ", " + << tCurrentAccessLevel::GetName( p2->GetAccessLevel() ) + << " )"; + } + else + { + tos << p2->GetName(); + } + tos << "\n"; + + if ( receiver ) + { + sn_ConsoleOut(tos.str().c_str(), receiver->Owner()); + } + else + { + con << tos.str(); + } + } +} + +static void players_conf(std::istream &s) +{ + ListPlayers( 0 ); +} + +static tConfItemFunc players("PLAYERS",&players_conf); + +// /players gives a player list +static void se_ChatPlayers( ePlayerNetID * p ) +{ + ListPlayers( p ); +} + +void handle_chat( nMessage &m ) +{ nTimeRolling currentTime = tSysTimeFloat(); unsigned short id; m.Read(id); @@ -2032,24 +2415,17 @@ return; } - // spam protection: - REAL lengthMalus = say.Len() / 20.0; - if ( lengthMalus > 4.0 ) - { - lengthMalus = 4.0; - } + eChatSpamTester spam( p, say ); - eChatSpamTester spamChatTester( lengthMalus, p, say ); - - if (say.StartsWith("/")) { std::string sayStr(say); std::istringstream s(sayStr); + tString command; s >> command; - tString msg; tConfItemBase::EatWhitespace(s); - msg.ReadLine(s); + + // now, s is ready for reading the rest of the message. #ifdef DEDICATED if (se_InterceptCommands.StrPos(command) != -1) { @@ -2059,228 +2435,45 @@ else #endif if (command == "/me") { - if ( IsSilencedWithWarning(p) ) - return; - if ( spamChatTester.Block() ) - { - return; - } - - tColoredString console; - console << tColoredString::ColorString(1,1,1) << "* "; - console << *p; - console << tColoredString::ColorString(1,1,.5) << " " << msg; - console << tColoredString::ColorString(1,1,1) << " *"; - - tColoredString forOldClients; - forOldClients << tColoredString::ColorString(1,1,1) << "*" - << tColoredString::ColorString(1,1,.5) << msg - << tColoredString::ColorString(1,1,1) << "*"; - - se_BroadcastChatLine( p, console, forOldClients ); - console << "\n"; - sn_ConsoleOut(console,0); + se_ChatMe( p, s, spam ); return; } else if (command == "/teamleave") { - if ( se_assignTeamAutomatically ) - { - sn_ConsoleOut(tOutput("$player_teamleave_disallowed"), p->Owner() ); - return; - } - if(!p->TeamChangeAllowed()) { - sn_ConsoleOut(tOutput("$player_disallowed_teamchange"), p->Owner() ); - return; - } - - eTeam * leftTeam = p->NextTeam(); - if ( leftTeam ) - { - if ( !leftTeam ) - leftTeam = p->CurrentTeam(); - - if ( leftTeam->NumPlayers() > 1 ) - { - sn_ConsoleOut( tOutput( "$player_leave_team_wish", - tColoredString::RemoveColors(p->GetName()), - tColoredString::RemoveColors(leftTeam->Name()) ) );... [truncated message content] |
From: <z-...@us...> - 2008-01-26 01:36:45
|
Revision: 7626 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7626&view=rev Author: z-man Date: 2008-01-25 17:36:50 -0800 (Fri, 25 Jan 2008) Log Message: ----------- Added SUDO command. Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/NEWS armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.h Modified: armagetronad/branches/0.2.8-auth/armagetronad/NEWS =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/NEWS 2008-01-25 23:10:10 UTC (rev 7625) +++ armagetronad/branches/0.2.8-auth/armagetronad/NEWS 2008-01-26 01:36:50 UTC (rev 7626) @@ -1,6 +1,7 @@ Changes since 0.2.8.2: New settings and commands: +- SUDO to temporarily raise the access level - ACCESS_LEVEL to modify the required access level to change settings - KICK_TO and MOVE_TO: redirect a client to a different server - DEFAULT_KICK(_TO)_MESSAGE: default reason given to players for a kick Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.cpp 2008-01-25 23:10:10 UTC (rev 7625) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.cpp 2008-01-26 01:36:50 UTC (rev 7626) @@ -151,6 +151,12 @@ currentLevel_ = newLevel; } + +tCurrentAccessLevel::tCurrentAccessLevel() +{ + lastLevel_ = currentLevel_; +} + tCurrentAccessLevel::~tCurrentAccessLevel() { currentLevel_ = lastLevel_; @@ -238,7 +244,7 @@ { tASSERT(0); } - + virtual bool Writable(){ return false; } @@ -246,11 +252,63 @@ virtual bool Save(){ return false; } - }; static tConfItemLevel st_confLevel; +//! sudo command: elevates the access level for the context of the current configuration file +class tSudo: tConfItemBase +{ +public: + tSudo() + : tConfItemBase( "SUDO" ) + { + requiredLevel = tAccessLevel_Program; + } + + virtual void ReadVal( std::istream & s ) + { + int required_int = 0, elevated_int = 20; + + // read required and elevated access levels + s >> required_int; + s >> elevated_int; + + tAccessLevel elevated = static_cast< tAccessLevel >( elevated_int ); + tAccessLevel required = static_cast< tAccessLevel >( required_int ); + + if ( s.eof() || !s.good() || s.fail() ) + { + con << tOutput( "$sudo_usage" ); + } + else if ( tCurrentAccessLevel::GetAccessLevel() < required ) + { + con << tOutput( "$access_level_error", + "SUDO", + required, + tCurrentAccessLevel::GetName( tCurrentAccessLevel::GetAccessLevel() ) + ); + } + else + { + tCurrentAccessLevel::currentLevel_ = elevated; + } + } + + virtual void WriteVal(std::ostream &s) + { + tASSERT(0); + } + + virtual bool Writable(){ + return false; + } + + virtual bool Save(){ + return false; + } +}; + bool st_FirstUse=true; static tConfItem<bool> fu("FIRST_USE",st_FirstUse); //static tConfItem<bool> fu("FIRST_USE","help_first_use",st_FirstUse); @@ -565,6 +623,8 @@ } void tConfItemBase::LoadAll(std::istream &s){ + tCurrentAccessLevel levelResetter; + while(!s.eof() && s.good()) { tString line; Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.h =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.h 2008-01-25 23:10:10 UTC (rev 7625) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.h 2008-01-26 01:36:50 UTC (rev 7626) @@ -168,9 +168,13 @@ //! class managing the current access level class tCurrentAccessLevel { + friend class tSudo; public: //! for the lifetime of this object, change the user's admit level to the passed one. tCurrentAccessLevel( tAccessLevel newLevel ); + + //! does not change the access level on construction, but resets it on destruction + tCurrentAccessLevel(); ~tCurrentAccessLevel(); //! returns the current access level @@ -179,7 +183,6 @@ //! returns the name of an access level static tString GetName( tAccessLevel level ); private: - tCurrentAccessLevel(); tCurrentAccessLevel( tCurrentAccessLevel const & ); tCurrentAccessLevel & operator = ( tCurrentAccessLevel const & ); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <z-...@us...> - 2008-01-26 01:38:09
|
Revision: 7627 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7627&view=rev Author: z-man Date: 2008-01-25 17:38:14 -0800 (Fri, 25 Jan 2008) Log Message: ----------- Worked around gcc-3.3 problems with function pointer default arguments. Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp Modified: armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-26 01:36:50 UTC (rev 7626) +++ armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-26 01:38:14 UTC (rev 7627) @@ -2457,6 +2457,9 @@ access_level_change Required access level of command \1 changed to "\2".\n access_level_error Required access level of command \1 is "\2", you only have "\3".\n +sudo_help For the duratioon of the rest of the configuration file thiss directive appears in, elevate the access level. +sudo_usage Usage: SUDO <required access levell> <elevated access level>\n + user_level_help Changes the access level of a user. user_level_usage usage: USER_LEVEL <authenticated name> <user access level (numerical)>\n user_level_change Access level of user \1 changed to "\2".\n Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-26 01:36:50 UTC (rev 7626) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/engine/ePlayer.cpp 2008-01-26 01:38:14 UTC (rev 7627) @@ -1252,7 +1252,13 @@ // the other filter is ePlayerNetID::FilterName // search for exact or partial matches in player names -ePlayerNetID * CompareBufferToPlayerNames( const tString & name, int & num_matches, ePlayerNetID * requester, SE_NameGetter GetName = &ePlayerNetID::GetName, SE_NameFilter Filter = &se_NameFilterID, SE_NameHider Hider = &se_NonHide ) +ePlayerNetID * CompareBufferToPlayerNames + ( const tString & name, + int & num_matches, + ePlayerNetID * requester, + SE_NameGetter GetName, // = &ePlayerNetID::GetName, + SE_NameFilter Filter, // = &se_NameFilterID, + SE_NameHider Hider )// = &se_NonHide ) { num_matches = 0; ePlayerNetID * match = 0; @@ -1285,12 +1291,13 @@ return match; } + ePlayerNetID * se_FindPlayerByName( tString const & name, ePlayerNetID * requester = 0 ) { - int num_matches = 0; + int num_matches = 0; // look for matches in the exact player names first - ePlayerNetID * ret = CompareBufferToPlayerNames( name, num_matches, requester ); + ePlayerNetID * ret = CompareBufferToPlayerNames( name, num_matches, requester, &ePlayerNetID::GetName, &se_NameFilterID, &se_NonHide ); if ( ret && num_matches == 1 ) { return ret; @@ -1302,7 +1309,7 @@ // look for matches in the screen names again if ( !ret ) { - ret = CompareBufferToPlayerNames( name, num_matches, requester, &ePlayerNetID::GetName, Filter ); + ret = CompareBufferToPlayerNames( name, num_matches, requester, &ePlayerNetID::GetName, Filter, &se_NonHide ); } if ( ret && num_matches == 1 ) { @@ -1357,6 +1364,8 @@ } return NULL; } + + return 0; } static ePlayerNetID * se_FindPlayerInChatCommand( ePlayerNetID * sender, char const * command, std::istream & s ) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <z-...@us...> - 2008-01-26 12:52:01
|
Revision: 7629 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7629&view=rev Author: z-man Date: 2008-01-26 04:52:01 -0800 (Sat, 26 Jan 2008) Log Message: ----------- Refined and documented SUDO. Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/config/settings_authentication.cfg armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.h Modified: armagetronad/branches/0.2.8-auth/armagetronad/config/settings_authentication.cfg =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/config/settings_authentication.cfg 2008-01-26 01:53:47 UTC (rev 7628) +++ armagetronad/branches/0.2.8-auth/armagetronad/config/settings_authentication.cfg 2008-01-26 12:52:01 UTC (rev 7629) @@ -236,6 +236,24 @@ ACCESS_LEVEL ALLOW_TEAM_CHANGE_PLAYER 7 ACCESS_LEVEL DISALLOW_TEAM_CHANGE_PLAYER 7 +# A very powerful command with access levels is SUDO. Like the sudo +# shell command on Unix, it allows regular users to execute commands +# with higher rights than they originally have, but only sequences of +# commands the server owner has prepared for them. If you put + +# SUDO <required access level> <elevated access level> + +# into a configuration file, and a remote admin with at least the rights +# <required access level> orders to include that file, the commands after +# the SUDO command will be executed as if the user had access level +# <elevated access level>. Otherwise, script execution is aborted. +# The effect carries on to other config files included by the one with +# the SUDO command, but wears off as soon as processing the file with +# the command is done. Especially, since every command given as remote +# admin directly is considered one file, "/admin SUDO 20 0" will elevate +# the rights to Owner, but since no second command can be issued on the +# same line, nothing further happens. + ######################################################################### # # Various Modified: armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-26 01:53:47 UTC (rev 7628) +++ armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-26 12:52:01 UTC (rev 7629) @@ -2460,6 +2460,9 @@ sudo_help For the duratioon of the rest of the configuration file thiss directive appears in, elevate the access level. sudo_usage Usage: SUDO <required access levell> <elevated access level>\n +abort_loading_name Loading Abort +abort_loading_description Current config file/stream loading was aborted by command \1. + user_level_help Changes the access level of a user. user_level_usage usage: USER_LEVEL <authenticated name> <user access level (numerical)>\n user_level_change Access level of user \1 changed to "\2".\n Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.cpp 2008-01-26 01:53:47 UTC (rev 7628) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.cpp 2008-01-26 12:52:01 UTC (rev 7629) @@ -38,6 +38,7 @@ #include "tToDo.h" #include "tConsole.h" #include "tDirectories.h" +#include "tLocale.h" #include "tRecorder.h" #include "tCommandLine.h" #include "tResourceManager.h" @@ -191,6 +192,8 @@ return *st_confMap; } +#ifdef KRAWALL_SERVER + // changes the access level of a configuration item class tConfItemLevel: public tConfItemBase { @@ -280,6 +283,7 @@ if ( s.fail() ) { con << tOutput( "$sudo_usage" ); + throw tAbortLoading( "SUDO" ); } else if ( tCurrentAccessLevel::GetAccessLevel() > required ) { @@ -288,6 +292,7 @@ tCurrentAccessLevel::GetName( required ), tCurrentAccessLevel::GetName( tCurrentAccessLevel::GetAccessLevel() ) ); + throw tAbortLoading( "SUDO" ); } else { @@ -311,10 +316,28 @@ static tSudo st_sudo; +#endif + bool st_FirstUse=true; static tConfItem<bool> fu("FIRST_USE",st_FirstUse); //static tConfItem<bool> fu("FIRST_USE","help_first_use",st_FirstUse); + +tAbortLoading::tAbortLoading( char const * command ) +: command_( command ) +{ +} + +tString tAbortLoading::DoGetName() const +{ + return tString(tOutput( "$abort_loading_name")); +} + +tString tAbortLoading::DoGetDescription() const +{ + return tString(tOutput( "$abort_loading_description", command_ )); +} + tConfItemBase::tConfItemBase(const char *t) :id(-1),title(t), changed(false){ @@ -627,6 +650,8 @@ void tConfItemBase::LoadAll(std::istream &s){ tCurrentAccessLevel levelResetter; + try{ + while(!s.eof() && s.good()) { tString line; @@ -682,6 +707,12 @@ // std::cout << line << '\n'; } } + } + catch( tAbortLoading const & e ) + { + // loading was aborted + con << e.GetDescription() << "\n"; + } } void tConfItemBase::DocAll(std::ostream &s){ Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.h =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.h 2008-01-26 01:53:47 UTC (rev 7628) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.h 2008-01-26 12:52:01 UTC (rev 7629) @@ -31,6 +31,7 @@ #include "tList.h" #include "tString.h" #include "tLinkedList.h" +#include "tException.h" #include "tLocale.h" #include "tConsole.h" #include "tLocale.h" @@ -289,6 +290,18 @@ tCONFIG_ENUM( tAccessLevel ); +//! exception to be thrown when the current script should be aborted +class tAbortLoading: public tException +{ +public: + tAbortLoading( char const * command ); +private: + tString command_; //!< the command responsible for the abort + + virtual tString DoGetName() const; + virtual tString DoGetDescription() const; +}; + template<class T> class tConfItem:virtual public tConfItemBase{ protected: T *target; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <z-...@us...> - 2008-01-26 16:00:31
|
Revision: 7631 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7631&view=rev Author: z-man Date: 2008-01-26 08:00:21 -0800 (Sat, 26 Jan 2008) Log Message: ----------- SUDO -> CASACL (Check And Set ACcess Level), prounounced like Quetzalcoatl, your friendly Aztec God. Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/config/settings_authentication.cfg armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.cpp armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.h Modified: armagetronad/branches/0.2.8-auth/armagetronad/config/settings_authentication.cfg =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/config/settings_authentication.cfg 2008-01-26 13:33:11 UTC (rev 7630) +++ armagetronad/branches/0.2.8-auth/armagetronad/config/settings_authentication.cfg 2008-01-26 16:00:21 UTC (rev 7631) @@ -236,32 +236,36 @@ ACCESS_LEVEL ALLOW_TEAM_CHANGE_PLAYER 7 ACCESS_LEVEL DISALLOW_TEAM_CHANGE_PLAYER 7 -# A very powerful command with access levels is SUDO. Like the sudo -# shell command on Unix, it allows regular users to execute commands -# with higher rights than they originally have, but only sequences of -# commands the server owner has prepared for them. If you put +# A very powerful command with access levels is CASACL, prounounced +# like Quetzalcoatl, your friendly Aztec God. A bit like the suid flag +# on Unix executables, the setuid system command, and not completely +# unlike the sudo shell command or, if you go very far, Access Control +# in Vista, it allows to change the access level a config file is +# executed under. If you put -# SUDO <required access level> <elevated access level> +# CASACL <required access level> <elevated access level> # into a configuration file, and a remote admin with at least the rights # <required access level> orders to include that file, the commands after -# the SUDO command will be executed as if the user had access level +# the CASACL command will be executed as if the user had access level # <elevated access level>. Otherwise, script execution is aborted. # The effect carries on to other config files included by the one with -# the SUDO command, but wears off as soon as processing the file with +# the CASACL command, but wears off as soon as processing the file with # the command is done. Especially, since every command given as remote -# admin directly is considered one file, "/admin SUDO 20 0" will elevate +# admin directly is considered one file, "/admin CASACL 20 0" will elevate # the rights to Owner, but since no second command can be issued on the # same line, nothing further happens. -# We recommend you put a SUDO command at the top of every configuration +# We recommend you put a CASACL command at the top of every configuration # file your remote administrators are going to include; it serves two # purposes then: it guards the file from unauthorized inclusion, and # it makes sure all the commands in the file work whenever the initial -# SUDO command is passed, provided you test it once with any account. +# CASACL command is passed, provided you test it once with any account. # This avoids scripts that only work partially and leave your server # in an unhealthy state. +# Oh yeah, CASACL is short for Check And Set ACcess Level. + ######################################################################### # # Various Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.cpp =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.cpp 2008-01-26 13:33:11 UTC (rev 7630) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.cpp 2008-01-26 16:00:21 UTC (rev 7631) @@ -259,12 +259,14 @@ static tConfItemLevel st_confLevel; -//! sudo command: elevates the access level for the context of the current configuration file -class tSudo: tConfItemBase +static char const *st_casacl = "CASACL"; + +//! casacl (Check And Set ACcess Level) command: elevates the access level for the context of the current configuration file +class tCasacl: tConfItemBase { public: - tSudo() - : tConfItemBase( "SUDO" ) + tCasacl() + : tConfItemBase( st_casacl ) { requiredLevel = tAccessLevel_Program; } @@ -283,7 +285,7 @@ if ( s.fail() ) { con << tOutput( "$sudo_usage" ); - throw tAbortLoading( "SUDO" ); + throw tAbortLoading( st_casacl ); } else if ( tCurrentAccessLevel::GetAccessLevel() > required ) { @@ -292,7 +294,7 @@ tCurrentAccessLevel::GetName( required ), tCurrentAccessLevel::GetName( tCurrentAccessLevel::GetAccessLevel() ) ); - throw tAbortLoading( "SUDO" ); + throw tAbortLoading( st_casacl ); } else { @@ -314,7 +316,7 @@ } }; -static tSudo st_sudo; +static tCasacl st_sudo; #endif Modified: armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.h =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.h 2008-01-26 13:33:11 UTC (rev 7630) +++ armagetronad/branches/0.2.8-auth/armagetronad/src/tools/tConfiguration.h 2008-01-26 16:00:21 UTC (rev 7631) @@ -169,7 +169,7 @@ //! class managing the current access level class tCurrentAccessLevel { - friend class tSudo; + friend class tCasacl; public: //! for the lifetime of this object, change the user's admit level to the passed one. tCurrentAccessLevel( tAccessLevel newLevel ); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <z-...@us...> - 2008-01-26 16:31:46
|
Revision: 7633 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7633&view=rev Author: z-man Date: 2008-01-26 08:30:19 -0800 (Sat, 26 Jan 2008) Log Message: ----------- More SUDO -> CASACL Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/NEWS armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt Modified: armagetronad/branches/0.2.8-auth/armagetronad/NEWS =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/NEWS 2008-01-26 16:30:01 UTC (rev 7632) +++ armagetronad/branches/0.2.8-auth/armagetronad/NEWS 2008-01-26 16:30:19 UTC (rev 7633) @@ -1,8 +1,6 @@ Changes since 0.2.8.2: New settings and commands: -- SUDO to temporarily raise the access level -- ACCESS_LEVEL to modify the required access level to change settings - KICK_TO and MOVE_TO: redirect a client to a different server - DEFAULT_KICK(_TO)_MESSAGE: default reason given to players for a kick - DEFAULT_KICK_TO_SERVER/PORT: default redirection target for KICK/MOVE_TO. @@ -52,6 +50,8 @@ console If --enable-armathentication was activated: +- CASACL to temporarily raise the access level +- ACCESS_LEVEL to modify the required access level to change settings - AUTHORITY_WHITELIST and AUTHORITY_BLACKLIST to filter authorities you want on your server. - GLOBAL_ID_ENABLED to toggle remote accounts - LOCAL_USER, LOCAL_TEAM for local login accounts Modified: armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-26 16:30:01 UTC (rev 7632) +++ armagetronad/branches/0.2.8-auth/armagetronad/language/english_base.txt 2008-01-26 16:30:19 UTC (rev 7633) @@ -2457,8 +2457,8 @@ access_level_change Required access level of command \1 changed to "\2".\n access_level_error Required access level of command \1 is "\2", you only have "\3".\n -sudo_help For the duratioon of the rest of the configuration file thiss directive appears in, elevate the access level. -sudo_usage Usage: SUDO <required access levell> <elevated access level>\n +casacl_help For the duratioon of the rest of the configuration file thiss directive appears in, elevate the access level. +casacl_usage Usage: CASACL <required access levell> <elevated access level>\n abort_loading_name Loading Abort abort_loading_description Current config file/stream loading was aborted by command \1. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |