//======== (C) Copyright 2002 Charles G. Cleveland All rights reserved. ========= // // The copyright to the contents herein is the property of Charles G. Cleveland. // The contents may be used and/or copied only with the written permission of // Charles G. Cleveland, or in accordance with the terms and conditions stipulated in // the agreement/contract under which the contents have been supplied. // // Purpose: // // $Workfile: AvHCurl.cpp $ // $Date: $ // //------------------------------------------------------------------------------- // $Log: $ //=============================================================================== #include "../build.h" #if defined(USE_OLDAUTH) // forget entire file if we're using UPP instead #include "../util/nowarnings.h" #include "../dlls/extdll.h" #include "../dlls/util.h" #include "../util/Tokenizer.h" #include "AvHGamerules.h" #include "AvHServerUtil.h" ///////////////////////////////////////////////////////////////////////////////////////////////////// ////// 2021 - Unused library removal. Uncomment and reinclude libcurl to add back. //// //////////////////////////////////////////////////////////////////////////////////////////////////// ////@2014 curl 32/64 bit problems //#ifndef LINUX //#define CURL_STATICLIB //#endif // //#include ////#define CURL_SIZEOF_LONG 4 extern cvar_t avh_serverops; extern unsigned int gTimeLastUpdatedUplink; extern AuthMaskListType gAuthMaskList; extern const char* kSteamIDPending; extern const char* kSteamIDPrefix; //const char* kWebStatusURL = "https://www.natural-selection.org/cgi-bin/VictoryStats.pl"; //const char* kWebStatusURL = "http://www.natural-selection.org/cgi-bin/ikonboard/ikonboard.cgi"; void AvHGamerules::PostVictoryStatsToWeb(const string& inFormParams) const { // CURL* curl; // CURLcode res; // // curl = curl_easy_init(); // if(curl) // { // /* First set the URL that is about to receive our POST. This URL can // just as well be a https:// URL if that is what should receive the // data. */ // curl_easy_setopt(curl, CURLOPT_URL, kWebStatusURL); // // /* Now specify the POST data */ // curl_easy_setopt(curl, CURLOPT_POSTFIELDS, inFormParams.c_str()); // // /* Perform the request, res will get the return code */ // res = curl_easy_perform(curl); // // /* always cleanup */ // curl_easy_cleanup(curl); // } //struct soap soap; // allocate gSOAP runtime environment //soap; /* char *sym; float q; if (argc <= 1) sym = "IBM"; else sym = argv[1]; soap_init(&soap); // must initialize if (soap_call_ns__getQuote(&soap, "http://services.xmethods.net/soap", "", sym, &q) == 0) printf("\nCompany - %s Quote - %f\n", sym, q); else { soap_print_fault(&soap, stderr); soap_print_fault_location(&soap, stderr); } */ } // This authID could be either a WONID or a STEAMID int AvHGamerules::GetAuthenticationMask(const string& inAuthID) const { // Iterate through each mask type, oring it into the mask if id is found int theMask = 0; if(inAuthID == kSteamIDPending) { theMask = PLAYERAUTH_PENDING; } else { // Error check the incoming authID if(AvHSUGetIsValidAuthID(inAuthID)) { for(AuthMaskListType::const_iterator theIter = gAuthMaskList.begin(); theIter != gAuthMaskList.end(); theIter++) { const AuthIDListType& theAuthIDList = theIter->second; for(AuthIDListType::const_iterator theAuthListIter = theAuthIDList.begin(); theAuthListIter != theAuthIDList.end(); theAuthListIter++) { // Check if incoming authID is equal to this record's WONID _or_ STEAMID. This is kind of sloppy, but it allows backwards compatibility. if((theAuthListIter->first == inAuthID) || (theAuthListIter->second == inAuthID)) { AvHPlayerAuthentication theCurrentAuthMask = theIter->first; theMask |= theCurrentAuthMask; break; } } } // Check if any players are server ops const AuthIDListType& theServerOps = this->GetServerOpList(); for(AuthIDListType::const_iterator theAuthListIter = theServerOps.begin(); theAuthListIter != theServerOps.end(); theAuthListIter++) { if((inAuthID == theAuthListIter->first) || (inAuthID == theAuthListIter->second)) { theMask |= PLAYERAUTH_SERVEROP; break; } } } } return theMask; } void AvHGamerules::AddAuthStatus(AvHPlayerAuthentication inAuthMask, const string& inWONID, const string& inSteamID) { // int theData = 0; // Not sure why this is needed, but it seems to ("warning, decorated name length exceeded) #pragma warning (disable: 4503) AuthIDListType& theAuthList = gAuthMaskList[inAuthMask]; bool theFoundEntry = false; for(AuthIDListType::iterator theIter = theAuthList.begin(); theIter != theAuthList.end(); theIter++) { // Allow duplicate WONids but not SteamIDs if(inSteamID == theIter->second) { theFoundEntry = true; break; } } if(!theFoundEntry) { // Add entry for this id theAuthList.push_back( make_pair(inWONID, inSteamID) ); } } struct MemoryStruct { char *memory; size_t size; }; size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) { register int realsize = size * nmemb; struct MemoryStruct *mem = (struct MemoryStruct *)data; mem->memory = (char *)realloc(mem->memory, mem->size + realsize + 1); if (mem->memory) { memcpy(&(mem->memory[mem->size]), ptr, realsize); mem->size += realsize; mem->memory[mem->size] = 0; } return realsize; } bool TagToAuthMask(const string& inTag, AvHPlayerAuthentication& outMask) { bool theSuccess = false; if(inTag == "dev") { outMask = PLAYERAUTH_DEVELOPER; theSuccess = true; } else if(inTag == "guide") { outMask = PLAYERAUTH_GUIDE; theSuccess = true; } else if(inTag == "op") { outMask = PLAYERAUTH_SERVEROP; theSuccess = true; } else if(inTag == "pt") { outMask = PLAYERAUTH_PLAYTESTER; theSuccess = true; } else if(inTag == "const") { outMask = PLAYERAUTH_CONTRIBUTOR; theSuccess = true; } else if(inTag == "vet") { outMask = PLAYERAUTH_VETERAN; theSuccess = true; } else if(inTag == "betaop") { outMask = PLAYERAUTH_BETASERVEROP; theSuccess = true; } return theSuccess; } // Build string in obfuscated procedural way so it can't be scanned for and hacked. Build URL using IP instead of domain to // make sure proxy can't change it either. string BuildAuthenticationURL() { // "http://www.natural-selection.org/auth.php"; // (backwards-compatibly for pre-2.1 servers use: (http://www.natural-selection.org/auth/) string kAuthURL = "h"; kAuthURL += "t"; kAuthURL += "t"; kAuthURL += "p"; //kAuthURL += "s"; kAuthURL += ":"; kAuthURL += "/"; kAuthURL += "/"; kAuthURL += "w"; kAuthURL += "w"; kAuthURL += "w"; kAuthURL += "."; kAuthURL += "n"; kAuthURL += "a"; kAuthURL += "t"; kAuthURL += "u"; kAuthURL += "r"; kAuthURL += "a"; kAuthURL += "l"; kAuthURL += "-"; kAuthURL += "s"; kAuthURL += "e"; kAuthURL += "l"; kAuthURL += "e"; kAuthURL += "c"; kAuthURL += "t"; kAuthURL += "i"; kAuthURL += "o"; kAuthURL += "n"; kAuthURL += "."; kAuthURL += "o"; kAuthURL += "r"; kAuthURL += "g"; kAuthURL += "/"; kAuthURL += "a"; kAuthURL += "u"; kAuthURL += "t"; kAuthURL += "h"; kAuthURL += "/"; kAuthURL += "a"; kAuthURL += "u"; kAuthURL += "t"; kAuthURL += "h"; kAuthURL += "."; kAuthURL += "p"; kAuthURL += "h"; kAuthURL += "p"; return kAuthURL; } string BuildVersionURL() { // "http://207.44.144.68/auth.txt"; string kAuthURL = "h"; kAuthURL += "t"; kAuthURL += "t"; kAuthURL += "p"; //kAuthURL += "s"; kAuthURL += ":"; kAuthURL += "/"; kAuthURL += "/"; kAuthURL += "w"; kAuthURL += "w"; kAuthURL += "w"; kAuthURL += "."; kAuthURL += "n"; kAuthURL += "a"; kAuthURL += "t"; kAuthURL += "u"; kAuthURL += "r"; kAuthURL += "a"; kAuthURL += "l"; kAuthURL += "-"; kAuthURL += "s"; kAuthURL += "e"; kAuthURL += "l"; kAuthURL += "e"; kAuthURL += "c"; kAuthURL += "t"; kAuthURL += "i"; kAuthURL += "o"; kAuthURL += "n"; kAuthURL += "."; kAuthURL += "o"; kAuthURL += "r"; kAuthURL += "g"; kAuthURL += "/"; kAuthURL += "a"; kAuthURL += "u"; kAuthURL += "t"; kAuthURL += "h"; kAuthURL += "/"; kAuthURL += "v"; kAuthURL += "e"; kAuthURL += "r"; kAuthURL += "s"; kAuthURL += "i"; kAuthURL += "o"; kAuthURL += "n"; kAuthURL += "."; kAuthURL += "t"; kAuthURL += "x"; kAuthURL += "t"; return kAuthURL; } string BuildUserPassword() { string theUserPassword; // auth:mnbv5tgb theUserPassword += "a"; theUserPassword += "u"; theUserPassword += "t"; theUserPassword += "h"; theUserPassword += ":"; theUserPassword += "m"; theUserPassword += "n"; theUserPassword += "b"; theUserPassword += "v"; theUserPassword += "5"; theUserPassword += "t"; theUserPassword += "g"; theUserPassword += "b"; return theUserPassword; } ///////////////////////////////////////////////////////////////////////////////////////////////////// ////// 2021 - Unused library removal. Uncomment and reinclude libcurl to add back. //// //////////////////////////////////////////////////////////////////////////////////////////////////// //CURLcode PopulateChunkFromURL(const string& inURL, MemoryStruct& outChunk) //{ // const int kCurlTimeout = 8; // // // init the curl session // CURL* theCurlHandle = curl_easy_init(); // // // specify URL to get // curl_easy_setopt(theCurlHandle, CURLOPT_URL, inURL.c_str()); // // // send all data to this function // curl_easy_setopt(theCurlHandle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); // // // Ignore header and progress so there isn't extra stuff at the beginning of the data returned // //curl_easy_setopt(theCurlHandle, CURLOPT_HEADER, 0); // //curl_easy_setopt(theCurlHandle, CURLOPT_NOPROGRESS, 1); // //curl_easy_setopt(theCurlHandle, CURLOPT_VERBOSE, 0); // //curl_easy_setopt(theCurlHandle, CURLOPT_NOBODY, 1); // // // timeout (3 seconds) // curl_easy_setopt(theCurlHandle, CURLOPT_CONNECTTIMEOUT, kCurlTimeout); // curl_easy_setopt(theCurlHandle, CURLOPT_TIMEOUT, kCurlTimeout); // curl_easy_setopt(theCurlHandle, CURLOPT_NOSIGNAL, true); // // CURLOPT_LOW_SPEED_LIMIT? // // CURLOPT_LOW_SPEED_TIME? // // // Specify the user name and password // string kUserPassword = BuildUserPassword(); // curl_easy_setopt(theCurlHandle, CURLOPT_USERPWD, kUserPassword.c_str()); // // // we pass our 'theChunk' struct to the callback function // outChunk.memory=NULL; /* we expect realloc(NULL, size) to work */ // outChunk.size = 0; /* no data at this point */ // curl_easy_setopt(theCurlHandle, CURLOPT_FILE, (void *)&outChunk); // // // get it! // CURLcode theCode = curl_easy_perform(theCurlHandle); // // // cleanup curl stuff // curl_easy_cleanup(theCurlHandle); // // return theCode; //} void AvHGamerules::InitializeAuthentication() { bool theSuccess = false; ALERT(at_console, "\tReading authentication data..."); ///////////////////////////////////////////////////////////////////////////////////////////////////// ////// 2021 - Unused library removal. Uncomment and reinclude libcurl to add back. //// //////////////////////////////////////////////////////////////////////////////////////////////////// // struct MemoryStruct theChunk; // CURLcode theCode = PopulateChunkFromURL(BuildAuthenticationURL(), theChunk); // // // Now parse data and add users for each mask // if((theCode == CURLE_OK) && theChunk.memory) // { // // Clear existing authentication data, only after lookup succeeds // gAuthMaskList.clear(); // // string theString(theChunk.memory); // string theDelimiters("\r\n"); // StringVector theLines; // Tokenizer::split(theString, theDelimiters, theLines); // // // Run through each line // int theNumConstellationMembers = 0; // for(StringVector::const_iterator theIter = theLines.begin(); theIter != theLines.end(); theIter++) // { // char *msg=(char *)(*theIter).c_str(); // // If it's not empty and not a comment // char theFirstChar = (*theIter)[0]; // if((theFirstChar != '/') && (theFirstChar != '#')) // { // // Split up tag and number // StringVector theTokens; // if(Tokenizer::split(*theIter, " ", theTokens) == 3) // { // // Translate tag to auth mask // string theTag = theTokens[0]; // string theWONID = theTokens[1]; // string theSteamID = theTokens[2]; // // // Upper-case prefix // UppercaseString(theSteamID); // // // Make sure it starts with "STEAM_X:Y" // if(strncmp(theSteamID.c_str(), kSteamIDPrefix, strlen(kSteamIDPrefix))) // { // string theNewSteamID = kSteamIDPrefix + theSteamID; // theSteamID = theNewSteamID; // } // // // Add auth status // AvHPlayerAuthentication theMask = PLAYERAUTH_NONE; // if(TagToAuthMask(theTag, theMask)) // { // // Count Constellation members fyi // if(theMask & PLAYERAUTH_CONTRIBUTOR) // { // theNumConstellationMembers++; // } // // if((theWONID != "") || (theSteamID != "")) // { //#ifdef DEBUG // char theMessage[512]; // sprintf(theMessage, " Adding auth mask: %s %s %s\n", theTag.c_str(), theWONID.c_str(), theSteamID.c_str()); // ALERT(at_logged, theMessage); //#endif // // this->AddAuthStatus(theMask, theWONID, theSteamID); // theSuccess = true; // } // } // } // } // } // // // Breakpoint to see how many Constellation members there are (don't even think of printing or logging) // int a = 0; // } // else // { // int a = 0; // } // Now build server op list this->mServerOpList.clear(); // Parse contents server op variable string theServerOpsString(avh_serverops.string); // Tokenize string StringVector theServerOpsStrings; Tokenizer::split(theServerOpsString, ";", theServerOpsStrings); // For each in list, add as an int to our list for(StringVector::const_iterator theIter = theServerOpsStrings.begin(); theIter != theServerOpsStrings.end(); theIter++) { // Add whatever the put in this line as both the WONID and SteamID string theCurrentAuthID = *theIter; this->mServerOpList.push_back( make_pair(theCurrentAuthID, theCurrentAuthID)); } if(theSuccess) { ALERT(at_console, "success.\n"); } else { ALERT(at_console, "failure.\n"); } gTimeLastUpdatedUplink = AvHSUTimeGetTime(); } void AvHGamerules::DisplayVersioning() { ///////////////////////////////////////////////////////////////////////////////////////////////////// ////// 2021 - Unused library removal. Uncomment and reinclude libcurl to add back. //// //////////////////////////////////////////////////////////////////////////////////////////////////// //struct MemoryStruct theChunk; //CURLcode theCode = PopulateChunkFromURL(BuildVersionURL(), theChunk); //// Now parse data and add users for each mask //if((theCode == CURLE_OK) && theChunk.memory) //{ // string theString(theChunk.memory, theChunk.size); // string theDelimiters("\r\n"); // StringVector theLines; // Tokenizer::split(theString, theDelimiters, theLines); // if(theLines.size() > 0) // { // string theCurrentVersion(theLines[0]); // string theCurrentGameVersion = AvHSUGetGameVersionString(); // char theMessage[1024]; // if(theCurrentGameVersion != theCurrentVersion) // { // sprintf(theMessage, "\tServer out of date. NS version %s is now available!\n", theCurrentVersion.c_str()); // ALERT(at_console, theMessage); // } // else // { // sprintf(theMessage, "\tServer version is up to date.\n"); // ALERT(at_console, theMessage); // } // } //} } #endif //defined(USE_OLDAUTH)