00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "nKrawall.h"
00036 #include "nNetwork.h"
00037 #include "nServerInfo.h"
00038 #include "nNetObject.h"
00039 #include "tString.h"
00040 #include "tArray.h"
00041 #include "tConsole.h"
00042 #include "tSysTime.h"
00043 #include "tMemManager.h"
00044 #include "tRandom.h"
00045
00046 #include <stdlib.h>
00047 #include <string>
00048 #include <vector>
00049 #include <string.h>
00050
00051 #ifndef DEDICATED
00052
00053 static tString sn_methodBlacklist( "bmd5" );
00054 #else
00055
00056 static tString sn_methodBlacklist( "" );
00057 #endif
00058 static tConfItemLine sn_methodBlacklistConf( "HASH_METHOD_BLACKLIST", sn_methodBlacklist );
00059
00060 static void sn_GetSupportedMethods( std::vector< tString > & toFill )
00061 {
00062 char const * protocols[] = {
00063 "md5",
00064 "bmd5",
00065 0
00066 };
00067
00068
00069 char const * const * run = protocols;
00070 while ( *run )
00071 {
00072 tString method( *run );
00073 if ( !tIsInList( sn_methodBlacklist, method ) )
00074 {
00075 toFill.push_back( method );
00076 }
00077 ++run;
00078 }
00079 }
00080
00081 static bool sn_IsSupportedMethod( tString const & method )
00082 {
00083 std::vector< tString > methods;
00084 sn_GetSupportedMethods( methods);
00085
00086 for( std::vector< tString >::iterator iter = methods.begin(); iter != methods.end(); ++iter )
00087 {
00088 if ( method == *iter )
00089 {
00090 return true;
00091 }
00092 }
00093
00094 return false;
00095 }
00096
00097
00098 tString nKrawall::nMethod::SupportedMethods()
00099 {
00100 std::ostringstream s;
00101
00102 std::vector< tString > methods;
00103 sn_GetSupportedMethods( methods);
00104
00105 bool first = false;
00106 for( std::vector< tString >::iterator iter = methods.begin(); iter != methods.end(); ++iter )
00107 {
00108 if ( !first )
00109 {
00110 s << ", ";
00111 }
00112 s << *iter;
00113
00114 first = false;
00115 }
00116
00117 return tString( s.str().c_str() );
00118 }
00119
00120
00121 static bool sn_BothHave( tString const & a, tString const & b, tString const & m)
00122 {
00123 return tIsInList( a, m ) && tIsInList( b, m );
00124 }
00125
00126
00127 tString nKrawall::nMethod::BestMethod( tString const & a, tString const & b )
00128 {
00129 tString ret;
00130
00131
00132 std::vector< tString > methods;
00133 sn_GetSupportedMethods( methods);
00134 for( std::vector< tString >::iterator iter = methods.begin(); iter != methods.end(); ++iter )
00135 {
00136 if ( sn_BothHave( a, b, *iter ) )
00137 {
00138 return *iter;
00139 }
00140 }
00141
00142 return tString("");
00143 }
00144
00146 bool nKrawall::nMethod::BestLocalMethod( tString const & supportedOnClient, nMethod & result )
00147 {
00148 nMethod const * const * run = LocalMethods();
00149
00150 while ( * run )
00151 {
00152 if ( sn_IsSupportedMethod( (*run)->method ) && tIsInList( supportedOnClient, (*run)->method ) )
00153 {
00154 result = **run;
00155 return true;
00156 }
00157
00158 ++run;
00159 }
00160
00161 return false;
00162 }
00163
00164 bool nKrawall::nMethod::Equal( nMethod const & a, nMethod const & b )
00165 {
00166 return a.method == b.method && a.prefix == b.prefix && a.suffix == b.suffix;
00167 }
00168
00169
00170
00171 static tString sn_Replace( nKrawall::nScrambleInfo const & info, tString const & original )
00172 {
00173 std::istringstream in( static_cast< char const * >( original ) );
00174 std::ostringstream out;
00175
00176 char s = in.get();
00177 while ( !in.eof() )
00178 {
00179 if ( s != '%' || in.eof() )
00180 {
00181 out.put(s);
00182 }
00183 else
00184 {
00185 s = in.get();
00186 if ( s == 'u' )
00187 {
00188 out << info.username;
00189 }
00190 else
00191 {
00192 out << '%' << s;
00193 }
00194 }
00195
00196 s = in.get();
00197 }
00198
00199 return tString( out.str().c_str() );
00200 }
00201
00202 void nKrawall::nMethod::ScramblePassword( nScrambleInfo const & info, tString const & password, nScrambledPassword & scramble ) const
00203 {
00204 if ( method == "bmd5" )
00205 {
00206 nKrawall::BrokenScramblePassword( password, scramble );
00207 }
00208 else
00209 {
00210 tASSERT( method == "md5" );
00211 nKrawall::ScramblePassword( sn_Replace(info,prefix) + password + sn_Replace(info,suffix), scramble );
00212 }
00213 }
00214
00216 void nKrawall::nMethod::ScrambleSalt( nSalt & salt, tString const & serverIP ) const
00217 {
00218 if ( method != "bmd5" )
00219 {
00220
00221 nSalt tmp;
00222 nKrawall::ScramblePassword( serverIP, tmp );
00223 nKrawall::ScrambleWithSalt2( salt, tmp, salt );
00224 }
00225 }
00226
00227
00228 void nKrawall::nMethod::ScrambleWithSalt( nScrambleInfo const & info, nScrambledPassword const & scrambled, nSalt const & salt, nScrambledPassword & result ) const
00229 {
00230
00231 if ( !sn_IsSupportedMethod( method ) )
00232 {
00233 memset( &result, sizeof(result), 0);
00234 con << tColoredStringProxy(1,0,0) << "INTERNAL ERROR OR PHARMING ATTEMPT:" << tColoredStringProxy(1,1,1) << " unsupported hash method " << method << " selected.\n";
00235 return;
00236 }
00237
00238
00239 nKrawall::ScrambleWithSalt2( scrambled, salt, result );
00240 }
00241
00242
00243
00244 nKrawall::nMethod::nMethod( char const * method_, std::istream & properties )
00245 {
00246 method = method_;
00247
00248 while ( !properties.eof() )
00249 {
00250 tString property;
00251 properties >> property;
00252 tToLower( property );
00253
00254 std::ws( properties );
00255 if ( property == "prefix" )
00256 {
00257 prefix.ReadLine( properties );
00258 }
00259 else if ( property == "suffix" )
00260 {
00261 suffix.ReadLine( properties );
00262 }
00263
00264 }
00265 }
00266
00267 nKrawall::nMethod::nMethod( char const * method_, char const * prefix_, char const * suffix_)
00268
00269 : method( method_ ),
00270 prefix( prefix_ ),
00271 suffix( suffix_ )
00272 {
00273 }
00274
00275 #ifdef KRAWALL_SERVER_LEAGUE
00276 bool nKrawall::MayRequirePassword(tString& adress, unsigned int port)
00277 {
00278 return true;
00279
00280
00281 if (adress.Len() < 4)
00282 return false;
00283
00284 if (!strncmp(adress, "127.", 4))
00285 return true;
00286
00287 return false;
00288 }
00289 #endif
00290
00291 bool nKrawall::ArePasswordsEqual(const nScrambledPassword& a,
00292 const nScrambledPassword& b)
00293 {
00294 for (int i=15; i>=0; i--)
00295 if (a[i] != b[i])
00296 return false;
00297
00298 return true;
00299 }
00300
00301 nKrawall::nCheckResult::nCheckResult()
00302 : aborted( false ), automatic( false ){}
00303
00304 nKrawall::nCheckResult::~nCheckResult(){}
00305
00306 nKrawall::nCheckResult::nCheckResult( nCheckResult const & other )
00307 : nCheckResultBase( other ), user( other.user ), aborted( other.aborted ), automatic( other.automatic )
00308 {
00309 }
00310
00311 static void sn_WriteHexByte( std::ostream & s, int c )
00312 {
00313
00314 s << std::hex << std::setfill('0') << std::setw(2) << c;
00315
00316
00317 }
00318
00319
00320 tString nKrawall::EncodeScrambledPassword( nScrambledPassword const & scrambled )
00321 {
00322 std::ostringstream s;
00323 for( int i = 0; i < 16; ++i )
00324 {
00325 unsigned int val = scrambled[i];
00326 sn_WriteHexByte( s, val );
00327 }
00328
00329 return tString( s.str().c_str() );
00330 }
00331
00332
00333 tString nKrawall::EncodeString( tString const & original )
00334 {
00335 std::istringstream in( static_cast< char const * >( original ) );
00336 std::ostringstream out;
00337
00338 char c = in.get();
00339 while ( !in.eof() )
00340 {
00341 if ( c == ' ' )
00342 {
00343 out.put( '+' );
00344 }
00345 else if ( isalnum( c ) )
00346 {
00347 out.put( c );
00348 }
00349 else
00350 {
00351 out.put('%');
00352 out << std::uppercase;
00353 sn_WriteHexByte( out, c );
00354 }
00355 c = in.get();
00356 }
00357
00358 return tString( out.str().c_str() );
00359 }
00360
00361
00362 void nKrawall::WriteScrambledPassword(const nScrambledPassword& scrambled,
00363 nMessage &m)
00364 {
00365 for (int i = 7; i>=0; i--)
00366 m.Write(scrambled[i << 1] + (scrambled[(i << 1) + 1] << 8));
00367 }
00368
00369 void nKrawall::ReadScrambledPassword( nMessage &m,
00370 nScrambledPassword& scrambled)
00371 {
00372 for (int i = 7; i>=0; i--)
00373 {
00374 unsigned short x;
00375 m.Read(x);
00376 unsigned char low = x & 255;
00377 unsigned char high = (x - low) >> 8;
00378
00379 scrambled[ i << 1 ] = low;
00380 scrambled[(i << 1) + 1] = high;
00381 }
00382 }
00383
00384
00385 void nKrawall::WriteScrambledPassword(const nScrambledPassword& scrambled,
00386 std::ostream &s)
00387 {
00388 for (int i = 15; i>=0; i--)
00389 s << (int)scrambled[i] << ' ';
00390 }
00391
00392 void nKrawall::ReadScrambledPassword( std::istream &s,
00393 nScrambledPassword& scrambled)
00394 {
00395 for (int i = 15; i>=0; i--)
00396 {
00397 int x;
00398 s >> x;
00399 scrambled[i] = x;
00400 }
00401 }
00402
00403
00404
00405
00406 void nKrawall::ScramblePassword(const tString& password,
00407 nScrambledPassword &scrambled)
00408 {
00409 md5_state_t state;
00410 md5_init(&state);
00411 md5_append(&state, (md5_byte_t const *)(password.c_str()), password.size());
00412 md5_finish(&state, scrambled.content);
00413 }
00414
00415
00416 void nKrawall::BrokenScramblePassword(const tString& password,
00417 nScrambledPassword &scrambled)
00418 {
00419 md5_state_t state;
00420 md5_init(&state);
00421 md5_append(&state, (md5_byte_t const *)(password.c_str()), password.Len());
00422 md5_finish(&state, scrambled.content);
00423 }
00424
00425
00426
00427 void nKrawall::ScrambleWithSalt2(const nScrambledPassword& source,
00428 const nSalt& salt,
00429 nScrambledPassword& dest)
00430 {
00431 md5_state_t state;
00432 md5_init(&state);
00433 md5_append(&state, source.content, 16);
00434 md5_append(&state, salt.content , 16);
00435 md5_finish(&state, dest.content);
00436 }
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447 void nKrawall::RandomSalt(nSalt& salt)
00448 {
00449
00450 tRandomizer & randomizer = tRandomizer::GetInstance();
00451 for (int i=15; i>=0; i--)
00452 salt[i] = randomizer.Get( 256 );
00453
00454 }
00455
00456 #ifdef KRAWALL_SERVER
00457
00459 void nKrawall::SplitUserName( tString const & original, tString & username, tString & authority )
00460 {
00461 std::ostringstream filter;
00462
00463 for( int i = original.Len()-2; i >=0 ; --i )
00464 {
00465 if ( original[i] == '@' )
00466 {
00467 username = original.SubStr( 0, i );
00468 authority = original.SubStr( i+1, original.Len() - i -2 );
00469 return;
00470 }
00471 }
00472
00473 username = original;
00474 authority = "";
00475 }
00476
00477 #ifdef KRAWALL_SERVER_LEAGUE
00478
00479
00480 void nKrawall::ReceiveLeagueMessage(const tString& message)
00481 {
00482
00483
00484 if (message[0] == 'K')
00485 {
00486 tString killer(message.c_str()+1);
00487 tString victim(message.c_str()+1+killer.Len());
00488
00489 MasterFrag(killer, victim);
00490 }
00491 else if (message[0] == 'R')
00492 {
00493 tString numP(message.c_str()+1);
00494 int pos = 1 + numP.Len();
00495
00496 int numPlayers = atoi(numP);
00497 tArray<tString> players(numPlayers);
00498 for (int i = numPlayers-1; i>=0; i--)
00499 {
00500 players(i) = tString(message.c_str()+pos);
00501 pos += players(i).Len();
00502 }
00503
00504 MasterRoundEnd(&players[0], numPlayers);
00505 }
00506 }
00507
00508
00509
00510
00511 void nKrawall::Frag(const tString &killer, const tString& victim, tString& message)
00512 {
00513 message << 'K';
00514 message << killer << '\0';
00515 message << victim << '\0';
00516 }
00517
00518
00519
00520 void nKrawall::RoundEnd(const tString* players, int numPlayers, tString& message)
00521 {
00522 message << 'R';
00523 message << numPlayers << '\0';
00524 for (int i = numPlayers-1; i>=0; i--)
00525 message << players[i] << '\0';
00526 }
00527
00528
00529
00530
00531 void nKrawall::ServerFrag(const tString &killer, const tString& victim)
00532 {
00533 tString message;
00534 Frag(killer, victim, message);
00535 SendLeagueMessage(message);
00536 }
00537
00538
00539
00540 void nKrawall::ServerRoundEnd(const tString* players, int numPlayers)
00541 {
00542 tString message;
00543 RoundEnd(players, numPlayers, message);
00544 SendLeagueMessage(message);
00545 }
00546
00547
00548
00549
00550 void ReceiveLeagueMessage(nMessage &m);
00551 void ReceiveLeagueMessageAck(nMessage &m);
00552
00553 static nDescriptor nLeagueMessage(42, &ReceiveLeagueMessage, "password_request", true);
00554
00555 static nDescriptor nLeagueMessageAck(43, &ReceiveLeagueMessageAck, "password_answer", true);
00556
00557
00558
00559 static void SignMessage(unsigned int id, const tString& message, nKrawall::nScrambledPassword& signature)
00560 {
00561 tString pw = message;
00562 pw << " " << id;
00563 nKrawall::nScrambledPassword temp;
00564 nKrawall::ScramblePassword(pw, temp);
00565 nKrawall::ScrambleWithSalt(temp, nKrawall::SecretLeagueKey(), signature);
00566 }
00567
00568
00569 static unsigned int S_NextID = 3;
00570
00571
00572 class nLM
00573 {
00574 public:
00575 tString message;
00576 unsigned int id;
00577 REAL sentTime;
00578 };
00579
00580
00581
00582 static tArray<nLM> S_WFA;
00583
00584
00585
00586 void nKrawall::SendLeagueMessage(const tString& message)
00587 {
00588
00589 return;
00590
00591 int i;
00592 REAL time = tSysTimeFloat();
00593
00594
00595 nServerInfo *master = nServerInfo::GetMasters();
00596 if (!master)
00597 return;
00598
00599 sn_Bend(master->GetConnectionName(), master->GetPort());
00600
00601
00602 for (i=0; i < S_WFA.Len(); i++)
00603 {
00604 nLM& resend = S_WFA(i);
00605 if (resend.sentTime + 2 < time)
00606 {
00607
00608 nMessage *m = tNEW(nMessage) (nLeagueMessage);
00609 (*m) << resend.id;
00610 (*m) << resend.message;
00611
00612 nKrawall::nScrambledPassword signature;
00613 SignMessage(resend.id, resend.message, signature);
00614 nKrawall::WriteScrambledPassword(signature, *m);
00615
00616 m->SendImmediately(0, false);
00617
00618
00619 resend.sentTime = time;
00620 }
00621 }
00622
00623 if (!&message)
00624 return;
00625
00626
00627 nLM& send = S_WFA[S_WFA.Len()];
00628 send.id = S_NextID++;
00629 send.sentTime = time;
00630 send.message = message;
00631
00632
00633
00634
00635 nKrawall::nScrambledPassword signature;
00636 SignMessage(send.id, message, signature);
00637
00638
00639 nMessage *m = tNEW(nMessage) (nLeagueMessage);
00640 (*m) << send.id;
00641 (*m) << message;
00642 nKrawall::WriteScrambledPassword(signature, *m);
00643
00644 m->SendImmediately(0, false);
00645 nMessage::SendCollected(0);
00646 }
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661 #define STOREBACK 40
00662
00663
00664 class nLastLeagueMessage
00665 {
00666 public:
00667 tString adr;
00668 unsigned int port;
00669 unsigned int ids[STOREBACK];
00670 };
00671
00672
00673
00674 static tArray<nLastLeagueMessage> S_LLM;
00675
00676
00677
00678
00679 void ReceiveLeagueMessage(nMessage &m)
00680 {
00681 int i;
00682
00683
00684 tString senderAdr;
00685 sn_GetAdr(m.SenderID(), senderAdr);
00686 unsigned int senderPort = sn_GetPort(m.SenderID());
00687
00688 unsigned int id;
00689 tString message;
00690
00691
00692 m >> id;
00693 m >> message;
00694
00695
00696 if (!nKrawall::IsFromKrawall(senderAdr, senderPort))
00697 {
00698 con << "Rejecting league message " << id << " from " << senderAdr << ":" << senderPort << " : not from Krawall.\n";
00699 return;
00700 }
00701
00702
00703 nMessage *ret = tNEW(nMessage)(nLeagueMessageAck);
00704 (*ret) << id;
00705 ret->SendImmediately(m.SenderID(), false);
00706 nMessage::SendCollected(m.SenderID());
00707
00708
00709 nKrawall::nScrambledPassword realsignature, receivedsignature;
00710 SignMessage(id, message, realsignature);
00711 nKrawall::ReadScrambledPassword(m, receivedsignature);
00712 if (!nKrawall::ArePasswordsEqual(realsignature, receivedsignature))
00713 {
00714 con << "Rejecting league message " << id << " from " << senderAdr << ":" << senderPort << " : invalid signature.\n";
00715 return;
00716 }
00717
00718
00719 nLastLeagueMessage* lastFromThisSender = NULL;
00720 for (i=S_LLM.Len()-1; i>=0 && !lastFromThisSender; i--)
00721 if (S_LLM(i).adr == senderAdr && S_LLM(i).port == senderPort)
00722 lastFromThisSender = &(S_LLM(i));
00723
00724
00725 if (!lastFromThisSender)
00726 {
00727 lastFromThisSender = &(S_LLM[S_LLM.Len()]);
00728 lastFromThisSender->adr = senderAdr;
00729 lastFromThisSender->port = senderPort;
00730 for (i = STOREBACK-1; i>=0; i--)
00731 lastFromThisSender->ids[i] = id - i - 10000;
00732 }
00733
00734
00735
00736
00737 for (i = STOREBACK-1; i>=0; i--)
00738 if (lastFromThisSender->ids[i] == id)
00739 {
00740 con << "Ignoring league message " << id << " from " << senderAdr << ":" << senderPort << " : already processed.\n";
00741 return;
00742 }
00743
00744
00745 for (i = STOREBACK-2; i>=0; i--)
00746 lastFromThisSender->ids[i+1] = lastFromThisSender->ids[i];
00747 lastFromThisSender->ids[0] = id;
00748
00749 #ifdef DEBUG
00750 con << "Receiving league message " << id << "\n";
00751 #endif
00752
00753
00754 nKrawall::ReceiveLeagueMessage(message);
00755 }
00756
00757
00758
00759
00760
00761
00762
00763 void ReceiveLeagueMessageAck(nMessage &m)
00764 {
00765
00766 unsigned int id;
00767 m >> id;
00768
00769 for (int i=S_WFA.Len()-1; i>=0; i--)
00770 {
00771 nLM& resend = S_WFA(i);
00772 if (resend.id == id)
00773 {
00774
00775 S_WFA(i) = S_WFA(S_WFA.Len()-1);
00776 S_WFA.SetLen(S_WFA.Len()-1);
00777
00778 return;
00779 }
00780 }
00781 }
00782
00783 #endif
00784 #endif
00785
00786