# HG changeset patch # User unc0rr # Date 1390688224 -14400 # Node ID b235e520ea2100600fe6336c81aaa0549b46692e # Parent dbaf90a0fbe073838137f13abefb16644c636f7a Mutual authentication: server side diff -r dbaf90a0fbe0 -r b235e520ea21 QTfrontend/net/newnetclient.cpp --- a/QTfrontend/net/newnetclient.cpp Sun Jan 26 00:09:50 2014 +0400 +++ b/QTfrontend/net/newnetclient.cpp Sun Jan 26 02:17:04 2014 +0400 @@ -239,7 +239,7 @@ void HWNewNet::SendPasswordHash(const QString & hash) { // don't send it immediately, only store and check if server asked us for a password - m_passwordHash = hash; + m_passwordHash = hash.toAscii(); maybeSendPassword(); } @@ -311,7 +311,7 @@ return; } - if(lst[2] != m_serverHash) + if(lst[1] != m_serverHash) { Error("Server authentication error"); Disconnect(); @@ -1145,15 +1145,13 @@ if(m_passwordHash.isEmpty() || m_serverSalt.isEmpty()) return; - QString hash; - - hash = QCryptographicHash::hash( + QString hash = QCryptographicHash::hash( m_clientSalt.toAscii() .append(m_serverSalt.toAscii()) .append(m_passwordHash) .append(cProtoVer->toAscii()) .append("!hedgewars") - , QCryptographicHash::Sha1); + , QCryptographicHash::Sha1).toHex(); m_serverHash = QCryptographicHash::hash( m_serverSalt.toAscii() @@ -1161,7 +1159,7 @@ .append(m_passwordHash) .append(cProtoVer->toAscii()) .append("!hedgewars") - , QCryptographicHash::Sha1); + , QCryptographicHash::Sha1).toHex(); RawSendNet(QString("PASSWORD%1%2%1%3").arg(delimeter).arg(hash).arg(m_clientSalt)); } diff -r dbaf90a0fbe0 -r b235e520ea21 gameServer/Actions.hs --- a/gameServer/Actions.hs Sun Jan 26 00:09:50 2014 +0400 +++ b/gameServer/Actions.hs Sun Jan 26 02:17:04 2014 +0400 @@ -466,9 +466,9 @@ else [ByeClient $ loc "Authentication failed"] playerLogin p a contr = do - chan <- client's sendChan + cl <- client's id mapM_ processAction [ - AnswerClients [chan] ["ASKPASSWORD"] + AnswerClients [sendChan cl] $ ("ASKPASSWORD") : if clientProto cl < 48 then [] else [serverSalt cl] , ModifyClient (\c -> c{webPassword = p, isAdministrator = a, isContributor = contr}) ] diff -r dbaf90a0fbe0 -r b235e520ea21 gameServer/Consts.hs --- a/gameServer/Consts.hs Sun Jan 26 00:09:50 2014 +0400 +++ b/gameServer/Consts.hs Sun Jan 26 02:17:04 2014 +0400 @@ -4,4 +4,4 @@ import qualified Data.ByteString.Char8 as B serverVersion :: B.ByteString -serverVersion = "2" +serverVersion = "3" diff -r dbaf90a0fbe0 -r b235e520ea21 gameServer/CoreTypes.hs --- a/gameServer/CoreTypes.hs Sun Jan 26 00:09:50 2014 +0400 +++ b/gameServer/CoreTypes.hs Sun Jan 26 02:17:04 2014 +0400 @@ -98,6 +98,7 @@ connectTime :: UTCTime, nick :: B.ByteString, webPassword :: B.ByteString, + serverSalt :: B.ByteString, logonPassed :: Bool, isVisible :: Bool, clientProto :: !Word16, diff -r dbaf90a0fbe0 -r b235e520ea21 gameServer/HWProtoNEState.hs --- a/gameServer/HWProtoNEState.hs Sun Jan 26 00:09:50 2014 +0400 +++ b/gameServer/HWProtoNEState.hs Sun Jan 26 02:17:04 2014 +0400 @@ -2,7 +2,9 @@ module HWProtoNEState where import Control.Monad.Reader +import qualified Data.ByteString.Lazy as BL import qualified Data.ByteString.Char8 as B +import Data.Digest.Pure.SHA -------------------------------------- import CoreTypes import Actions @@ -42,12 +44,29 @@ (ci, irnc) <- ask let cl = irnc `client` ci - if passwd == webPassword cl then + if clientProto cl < 48 && passwd == webPassword cl then return $ JoinLobby : [AnswerClients [sendChan cl] ["ADMIN_ACCESS"] | isAdministrator cl] else return [ByeClient "Authentication failed"] +handleCmd_NotEntered ["PASSWORD", passwd, clientSalt] = do + (ci, irnc) <- ask + let cl = irnc `client` ci + + let clientHash = h [clientSalt, serverSalt cl, webPassword cl, showB $ clientProto cl, "!hedgewars"] + let serverHash = h [serverSalt cl, clientSalt, webPassword cl, showB $ clientProto cl, "!hedgewars"] + + if passwd == clientHash then + return $ + AnswerClients [sendChan cl] ["SERVER_AUTH", serverHash] + : JoinLobby + : [AnswerClients [sendChan cl] ["ADMIN_ACCESS"] | isAdministrator cl] + else + return [ByeClient "Authentication failed"] + where + h = B.pack . showDigest . sha1 . BL.fromChunks + #if defined(OFFICIAL_SERVER) handleCmd_NotEntered ["CHECKER", protoNum, newNick, password] = do (ci, irnc) <- ask diff -r dbaf90a0fbe0 -r b235e520ea21 gameServer/NetRoutines.hs --- a/gameServer/NetRoutines.hs Sun Jan 26 00:09:50 2014 +0400 +++ b/gameServer/NetRoutines.hs Sun Jan 26 02:17:04 2014 +0400 @@ -6,13 +6,20 @@ import Data.Time import Control.Monad import Data.Unique +import qualified Codec.Binary.Base64 as Base64 +import qualified Data.ByteString as BW +import qualified Data.ByteString.Char8 as B +import qualified Control.Exception as E +import System.Entropy ----------------------------- import CoreTypes import Utils -import RoomsAndClients + acceptLoop :: Socket -> Chan CoreMessage -> IO () -acceptLoop servSock chan = forever $ +acceptLoop servSock chan = E.bracket openHandle closeHandle f + where + f ch = forever $ do (sock, sockAddr) <- Network.Socket.accept servSock @@ -23,6 +30,7 @@ sendChan' <- newChan uid <- newUnique + salt <- liftM (B.pack . Base64.encode . BW.unpack) $ hGetEntropy ch 16 let newClient = (ClientInfo @@ -33,6 +41,7 @@ currentTime "" "" + salt False False 0 diff -r dbaf90a0fbe0 -r b235e520ea21 gameServer/hedgewars-server.cabal --- a/gameServer/hedgewars-server.cabal Sun Jan 26 00:09:50 2014 +0400 +++ b/gameServer/hedgewars-server.cabal Sun Jan 26 02:17:04 2014 +0400 @@ -28,6 +28,8 @@ hslogger, process, deepseq, - utf8-string + utf8-string, + SHA, + entropy ghc-options: -O2