PageRenderTime 51ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/multiwinia/contrib/systemiv/lib/metaserver/authentication.cpp

https://gitlab.com/matt81093/Darwinia-and-Multiwinia-Source-Code
C++ | 507 lines | 375 code | 110 blank | 22 comment | 54 complexity | 683a38ae83adb6d6ea087617549fc40e MD5 | raw file
  1. #include "lib/universal_include.h"
  2. #include <time.h>
  3. #include "lib/math/random_number.h"
  4. #include "lib/math/hash.h"
  5. #include "lib/debug_utils.h"
  6. #include "lib/tosser/directory.h"
  7. #include "lib/tosser/llist.h"
  8. #include "lib/netlib/net_mutex.h"
  9. #include "metaserver.h"
  10. #include "metaserver_defines.h"
  11. #include "authentication.h"
  12. static char s_authKey[256];
  13. const static char *s_invalidKeys[] = {
  14. "ATHETA-DKFOPQ-OGPUSS-CCKOPL-TNF",
  15. "OWRGIO-CLMQEE-URWUDL-SUVUCC-WYQ",
  16. NULL
  17. };
  18. class AuthenticationResult
  19. {
  20. public:
  21. char m_ip[256];
  22. char m_authKey[256];
  23. int m_keyId;
  24. int m_authResult;
  25. int m_numTries;
  26. AuthenticationResult()
  27. : m_keyId(-1),
  28. m_authResult(AuthenticationUnknown),
  29. m_numTries(0)
  30. {
  31. }
  32. };
  33. static LList<AuthenticationResult *> s_authResults;
  34. static NetMutex s_authResultsMutex;
  35. static bool s_authThreadRunning = false;
  36. static int s_hashToken = 0;
  37. static bool s_enforceDemo = false;
  38. void Authentication_GenerateKey( char *_key, int _gameType /* 2 = Defcon, 4 = Multiwinia, ... */, bool _demoKey, bool _steamKey )
  39. {
  40. strcpy( _key, "DEMOTP-AXYVLW-SGIZLU-DNLXPK-OJS" );
  41. }
  42. int Authentication_SimpleKeyCheck( const char *_key, int _gameType )
  43. {
  44. if( Authentication_IsHashKey(_key) )
  45. {
  46. // This is a hash of a key
  47. // No way to perform a simple check, so must assume its ok
  48. return AuthenticationAccepted;
  49. }
  50. return strlen(_key) == AUTHENTICATION_KEYLEN - 1
  51. ? AuthenticationAccepted
  52. : AuthenticationKeyInvalid;
  53. }
  54. void Authentication_SaveKey( const char *_key, const char *_filename )
  55. {
  56. FILE *file = fopen(_filename, "wt");
  57. if( !file )
  58. {
  59. AppDebugOut( "Failed to save AuthKey" );
  60. return;
  61. }
  62. fprintf( file, "%s\n", _key );
  63. fclose(file);
  64. }
  65. void Authentication_LoadKey( char *_key, const char *_filename )
  66. {
  67. FILE *file = fopen(_filename, "rt" );
  68. if( file )
  69. {
  70. fscanf( file, "%s", _key );
  71. fclose(file);
  72. }
  73. else
  74. {
  75. AppDebugOut( "Failed to load AuthKey : '%s'\n", _filename );
  76. sprintf( _key, "authkey not found" );
  77. }
  78. if( s_enforceDemo &&
  79. !Authentication_IsDemoKey(_key) )
  80. {
  81. strcpy( _key, "authkey not found" );
  82. }
  83. }
  84. void Authentication_SetKey( const char *_key )
  85. {
  86. strcpy( s_authKey, _key );
  87. // Trim end whitespace
  88. // In fact trim anything not valid from the end
  89. int keyLen = strlen(s_authKey);
  90. for( int i = keyLen-1; i >= 0; --i )
  91. {
  92. if( (s_authKey[i] >= 'a' && s_authKey[i] <= 'z') ||
  93. (s_authKey[i] >= 'A' && s_authKey[i] <= 'Z') ||
  94. s_authKey[i] == '-' )
  95. {
  96. break;
  97. }
  98. else
  99. {
  100. s_authKey[i] = '\x0';
  101. }
  102. }
  103. if( s_enforceDemo &&
  104. !Authentication_IsDemoKey(s_authKey) )
  105. {
  106. strcpy( s_authKey, "authkey not found" );
  107. }
  108. AppDebugOut( "Authentication key set : " );
  109. AppDebugOut( "'%s'\n", s_authKey );
  110. }
  111. bool Authentication_IsKeyFound()
  112. {
  113. if( s_enforceDemo &&
  114. !Authentication_IsDemoKey(s_authKey) )
  115. {
  116. return false;
  117. }
  118. return true;
  119. }
  120. void Authentication_GetKey( char *_key )
  121. {
  122. if( Authentication_IsKeyFound() )
  123. {
  124. strcpy( _key, s_authKey );
  125. }
  126. else
  127. {
  128. strcpy( _key, "authkey not found" );
  129. }
  130. }
  131. void Authentication_SetHashToken( int _hashToken )
  132. {
  133. if( _hashToken != s_hashToken )
  134. {
  135. AppDebugOut( "Authentication HashToken set to %d\n", _hashToken );
  136. }
  137. s_hashToken = _hashToken;
  138. }
  139. int Authentication_GetHashToken()
  140. {
  141. return s_hashToken;
  142. }
  143. void Authentication_GetKeyHash( char *_sourceKey, char *_destKey, int _hashToken )
  144. {
  145. HashData( _sourceKey, _hashToken, _destKey );
  146. }
  147. bool Authentication_IsHashKey( const char *_key )
  148. {
  149. return( strncmp(_key, "hsh", 3) == 0);
  150. }
  151. void Authentication_GetKeyHash( char *_key )
  152. {
  153. char keyTemp[256];
  154. Authentication_GetKey(keyTemp);
  155. Authentication_GetKeyHash( keyTemp, _key, s_hashToken );
  156. }
  157. bool Authentication_IsDemoKey( const char *_key )
  158. {
  159. for( int i = 0; s_invalidKeys[i]; ++i )
  160. {
  161. if( stricmp( _key, s_invalidKeys[i] ) == 0 )
  162. {
  163. return true;
  164. }
  165. }
  166. if( Authentication_GetStatus( _key ) == AuthenticationKeyNotFound )
  167. {
  168. return true;
  169. }
  170. if( Authentication_IsHashKey(_key) )
  171. {
  172. // We can't tell in this case
  173. return false;
  174. }
  175. return( strncmp( _key, "DEMO", 4) == 0 );
  176. }
  177. void Anthentication_EnforceDemo()
  178. {
  179. s_enforceDemo = true;
  180. }
  181. bool Authentication_IsAmbrosiaKey( const char *_key )
  182. {
  183. if( Authentication_IsHashKey(_key) )
  184. {
  185. // We can't tell in this case
  186. return false;
  187. }
  188. return( strncmp( _key, "AMBR", 4) == 0 );
  189. }
  190. static NetCallBackRetType AuthenticationThread(void *_args)
  191. {
  192. int gameType = (int) _args;
  193. #ifdef WAN_PLAY_ENABLED
  194. //
  195. // Every few seconds request the next key to be authenticated
  196. while( true )
  197. {
  198. NetSleep( PERIOD_AUTHENTICATION_RETRY );
  199. if( MetaServer_IsConnected() )
  200. {
  201. char unknownKey[256];
  202. char clientIp[256];
  203. int keyId = -1;
  204. bool unknownKeyFound = false;
  205. //
  206. // Look for a key that isnt yet authenticated
  207. s_authResultsMutex.Lock();
  208. for( int i = 0; i < s_authResults.Size(); ++i )
  209. {
  210. AuthenticationResult *authResult = s_authResults[i];
  211. if( authResult->m_authResult == AuthenticationUnknown &&
  212. authResult->m_numTries < 5 )
  213. {
  214. strcpy( unknownKey, authResult->m_authKey );
  215. strcpy( clientIp, authResult->m_ip );
  216. keyId = authResult->m_keyId;
  217. authResult->m_numTries++;
  218. unknownKeyFound = true;
  219. break;
  220. }
  221. }
  222. s_authResultsMutex.Unlock();
  223. //
  224. // Check the key out
  225. if( unknownKeyFound )
  226. {
  227. int basicResult = Authentication_SimpleKeyCheck(unknownKey, gameType);
  228. if( basicResult < 0 )
  229. {
  230. // The key is in the wrong format
  231. Authentication_SetStatus( unknownKey, keyId, basicResult );
  232. const char *resultString = Authentication_GetStatusString(basicResult);
  233. AppDebugOut( "Key failed basic check : %s (result=%s)\n", unknownKey, resultString );
  234. }
  235. else if( Authentication_IsDemoKey(unknownKey) )
  236. {
  237. // This is a demo key, and has passed the simple check
  238. // Assume its valid from now on
  239. Authentication_SetStatus( unknownKey, -1, AuthenticationAccepted );
  240. AppDebugOut( "Auth Key accepted as DEMOKEY : %s\n", unknownKey );
  241. }
  242. else
  243. {
  244. // Request a proper auth check from the metaserver
  245. Directory directory;
  246. directory.SetName( NET_METASERVER_MESSAGE );
  247. directory.CreateData( NET_METASERVER_COMMAND, NET_METASERVER_REQUEST_AUTH );
  248. directory.CreateData( NET_METASERVER_AUTHKEY, unknownKey );
  249. directory.CreateData( NET_METASERVER_AUTHKEYID, keyId );
  250. directory.CreateData( NET_METASERVER_GAMENAME, APP_NAME );
  251. directory.CreateData( NET_METASERVER_GAMEVERSION, APP_VERSION );
  252. if( strcmp(clientIp, "unknown") != 0 )
  253. {
  254. directory.CreateData( NET_METASERVER_IP, clientIp );
  255. }
  256. MetaServer_SendToMetaServer( &directory );
  257. AppDebugOut( "Requesting authentication of key %s\n", unknownKey );
  258. }
  259. }
  260. }
  261. }
  262. #endif
  263. return 0;
  264. }
  265. int Authentication_GetKeyId( char *_key )
  266. {
  267. int result = 0;
  268. s_authResultsMutex.Lock();
  269. for( int i = 0; i < s_authResults.Size(); ++i )
  270. {
  271. AuthenticationResult *authResult = s_authResults[i];
  272. if( strcmp(authResult->m_authKey, _key) == 0 )
  273. {
  274. result = authResult->m_keyId;
  275. break;
  276. }
  277. }
  278. s_authResultsMutex.Unlock();
  279. return result;
  280. }
  281. void Authentication_RequestStatus( const char *_key, int _gameType, int _keyId, const char *_ip )
  282. {
  283. //
  284. // Does the key already exist in our list?
  285. s_authResultsMutex.Lock();
  286. AuthenticationResult *result = NULL;
  287. for( int i = 0; i < s_authResults.Size(); ++i )
  288. {
  289. AuthenticationResult *authResult = s_authResults[i];
  290. if( strcmp(authResult->m_authKey, _key) == 0 )
  291. {
  292. result = authResult;
  293. break;
  294. }
  295. }
  296. //
  297. // Add the key to our list if required
  298. if( !result )
  299. {
  300. result = new AuthenticationResult();
  301. strcpy( result->m_authKey, _key );
  302. result->m_keyId = _keyId;
  303. if( _ip ) strcpy( result->m_ip, _ip );
  304. else strcpy( result->m_ip, "unknown" );
  305. s_authResults.PutData( result );
  306. }
  307. s_authResultsMutex.Unlock();
  308. //
  309. // Start the authorisation thread if required
  310. if( !s_authThreadRunning )
  311. {
  312. s_authThreadRunning = true;
  313. NetStartThread( AuthenticationThread, (void *) _gameType );
  314. }
  315. }
  316. int Authentication_GetStatus( const char *_key )
  317. {
  318. int result = AuthenticationUnknown;
  319. s_authResultsMutex.Lock();
  320. for( int i = 0; i < s_authResults.Size(); ++i )
  321. {
  322. AuthenticationResult *authResult = s_authResults[i];
  323. if( strcmp(authResult->m_authKey, _key) == 0 )
  324. {
  325. result = authResult->m_authResult;
  326. break;
  327. }
  328. }
  329. s_authResultsMutex.Unlock();
  330. return result;
  331. }
  332. void Authentication_SetStatus( const char *_key, int _keyId, int _status )
  333. {
  334. s_authResultsMutex.Lock();
  335. AuthenticationResult *result = NULL;
  336. for( int i = 0; i < s_authResults.Size(); ++i )
  337. {
  338. AuthenticationResult *authResult = s_authResults[i];
  339. if( strcmp(authResult->m_authKey, _key) == 0 )
  340. {
  341. result = authResult;
  342. break;
  343. }
  344. }
  345. if( !result )
  346. {
  347. result = new AuthenticationResult();
  348. strcpy( result->m_authKey, _key );
  349. s_authResults.PutData( result );
  350. }
  351. if( result->m_authResult != _status )
  352. {
  353. const char *authString = Authentication_GetStatusString(_status);
  354. AppDebugOut( "Received Authentication : %s : (keyID %d) : %s\n", _key, _keyId, authString );
  355. }
  356. result->m_authResult = _status;
  357. result->m_keyId = _keyId;
  358. s_authResultsMutex.Unlock();
  359. }
  360. const char *Authentication_GetStatusString ( int _status )
  361. {
  362. switch( _status )
  363. {
  364. case AuthenticationUnknownGame: return "Unknown Game";
  365. case AuthenticationWrongPlatform: return "Wrong platform";
  366. case AuthenticationKeyDead: return "Key dead";
  367. case AuthenticationVersionNotFound: return "Version not found";
  368. case AuthenticationKeyInactive: return "Key inactive";
  369. case AuthenticationVersionRevoked: return "Version revoked";
  370. case AuthenticationKeyNotFound: return "Key not found";
  371. case AuthenticationKeyRevoked: return "Key revoked";
  372. case AuthenticationKeyBanned: return "Key banned";
  373. case AuthenticationKeyInvalid: return "Key invalid";
  374. case AuthenticationUnknown: return "Unknown";
  375. case AuthenticationAccepted: return "Accepted";
  376. default: return "Unknown";
  377. }
  378. }
  379. const char *Authentication_GetStatusStringLanguagePhrase ( int _status )
  380. {
  381. switch( _status )
  382. {
  383. case AuthenticationUnknownGame: return "dialog_auth_unknown_game";
  384. case AuthenticationWrongPlatform: return "dialog_auth_wrong_platform";
  385. case AuthenticationKeyDead: return "dialog_auth_key_dead";
  386. case AuthenticationVersionNotFound: return "dialog_auth_version_not_found";
  387. case AuthenticationKeyInactive: return "dialog_auth_key_inactive";
  388. case AuthenticationVersionRevoked: return "dialog_auth_version_revoked";
  389. case AuthenticationKeyNotFound: return "dialog_auth_key_not_found";
  390. case AuthenticationKeyRevoked: return "dialog_auth_key_revoked";
  391. case AuthenticationKeyBanned: return "dialog_auth_key_banned";
  392. case AuthenticationKeyInvalid: return "dialog_auth_key_invalid";
  393. case AuthenticationUnknown: return "dialog_auth_unknown";
  394. case AuthenticationAccepted: return "dialog_auth_accepted";
  395. default: return "dialog_auth_unknown";
  396. }
  397. }