123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 |
- /**
- * @file lluserauth.cpp
- * @brief LLUserAuth class implementation
- *
- * $LicenseInfo:firstyear=2003&license=viewergpl$
- *
- * Copyright (c) 2003-2009, Linden Research, Inc.
- * Copyright (c) 2009-2024, Henri Beauchamp.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- #include "linden_common.h"
- #include "curl/curl.h"
- #include "lluserauth.h"
- #include "llsdutil.h" // For ll_pretty_print_sd
- #include "llxmlrpctransaction.h"
- // Do not define PLATFORM_STRING for unknown platforms: they need to get added
- // to the login.cgi script, so we want this to cause an error if we get
- // compiled for a different platform.
- #if LL_WINDOWS
- static const char* PLATFORM_STRING = "Win";
- #elif LL_DARWIN
- static const char* PLATFORM_STRING = "Mac";
- #elif LL_LINUX
- static const char* PLATFORM_STRING = "Lnx";
- #else
- # error("Unknown platform !")
- #endif
- LLUserAuth gUserAuth;
- LLUserAuth::LLUserAuth()
- : mTransaction(NULL),
- mAuthResponse(E_NO_RESPONSE_YET),
- mUseMFA(false)
- {
- }
- LLUserAuth::~LLUserAuth()
- {
- reset();
- }
- void LLUserAuth::reset()
- {
- delete mTransaction;
- mTransaction = NULL;
- mResponses.clear();
- }
- void LLUserAuth::init(const std::string& platform_version,
- const std::string& os_string,
- const std::string& version, const std::string& channel,
- const std::string& serial_hash,
- const std::string& mac_hash)
- {
- mPlatformVersion = platform_version;
- mPlatformOSString = os_string;
- mViewerVersion = version;
- mViewerChannel = channel;
- mHashedSerial = serial_hash;
- mHashedMAC = mac_hash;
- }
- void LLUserAuth::setMFA(bool use_mfa, const std::string& mfa_hash,
- const std::string& mfa_token)
- {
- mUseMFA = use_mfa;
- if (!use_mfa)
- {
- mMFAHash.clear();
- mMFAToken.clear();
- }
- // When replying to a MFA challenge (i.e. the token string is not empty),
- // we pass the token and an empty hash. Else, we use any last known good
- // MFA hash we got, with an empty token. HB
- // See: https://wiki.secondlife.com/wiki/User:Brad_Linden/Login_MFA
- else if (mfa_token.empty())
- {
- mMFAHash = mfa_hash;
- mMFAToken.clear();
- }
- else
- {
- mMFAHash.clear();
- mMFAToken = mfa_token;
- }
- }
- void LLUserAuth::authenticate(const std::string& auth_uri,
- const std::string& method,
- const std::string& firstname,
- const std::string& lastname,
- const std::string& passwd,
- const std::string& start,
- bool skip_optional,
- bool accept_tos, bool accept_critical_message,
- S32 last_exec_event,
- const std::vector<const char*>& req_options)
- {
- if (mHashedSerial.empty())
- {
- llerrs << "LLUserAuth was not properly initialized !" << llendl;
- }
- llinfos << "Authenticating: " << firstname << " " << lastname << llendl;
- // NOTE: passwd is already MD5 hashed by the time we get to it.
- std::string dpasswd("$1$");
- dpasswd.append(passwd);
- std::ostringstream option_str;
- option_str << "Options: ";
- std::ostream_iterator<const char*> appender(option_str, ", ");
- std::copy(req_options.begin(), req_options.end(), appender);
- option_str << "END";
- llinfos << option_str.str().c_str() << llendl;
- mResponses.clear();
- mAuthResponse = E_NO_RESPONSE_YET;
- //mDownloadTimer.reset();
- // Create the request parameters bloc
- LLSD params;
- params["first"] = firstname;
- params["last"] = lastname;
- params["passwd"] = dpasswd;
- params["start"] = start;
- params["version"] = mViewerVersion;
- params["channel"] = mViewerChannel;
- params["platform"] = PLATFORM_STRING;
- params["address_size"] = 64;
- params["platform_version"] = mPlatformVersion;
- params["platform_string"] = mPlatformOSString;
- params["mac"] = mHashedMAC;
- params["id0"] = mHashedSerial;
- if (mUseMFA)
- {
- params["mfa_hash"] = mMFAHash;
- params["token"] = mMFAToken;
- }
- if (skip_optional)
- {
- params["skipoptional"] = "true";
- }
- if (accept_tos)
- {
- params["agree_to_tos"] = "true";
- }
- if (accept_critical_message)
- {
- params["read_critical"] = "true";
- }
- params["last_exec_event"] = last_exec_event;
- // Append optional requests in an array
- LLSD options;
- for (std::vector<const char*>::const_iterator it = req_options.begin(),
- end = req_options.end();
- it < end; ++it)
- {
- options.append(*it);
- }
- params.insert("options", options);
- #if LL_DEBUG
- // Note: this shows password and MFA hashes, so only enabled for debug
- // builds. HB
- LL_DEBUGS("UserAuth") << "Request LLSD:\n" << ll_pretty_print_sd(params)
- << LL_ENDL;
- #endif
- if (mTransaction)
- {
- delete mTransaction;
- }
- mTransaction = new LLXMLRPCTransaction(auth_uri, method, params);
- llinfos << "URI: " << auth_uri << llendl;
- }
- LLUserAuth::UserAuthcode LLUserAuth::authResponse()
- {
- if (!mTransaction)
- {
- return mAuthResponse;
- }
- if (!mTransaction->process()) // All done ?
- {
- if (mTransaction->status(0) == LLXMLRPCTransaction::StatusDownloading)
- {
- mAuthResponse = E_DOWNLOADING;
- }
- return mAuthResponse;
- }
- S32 result;
- mTransaction->status(&result);
- mErrorMessage = mTransaction->statusMessage();
- // If curl was ok, parse the download area.
- switch (result)
- {
- case CURLE_OK:
- mResponses = mTransaction->response();
- mAuthResponse = E_OK;
- LL_DEBUGS("UserAuth") << "Responses LLSD:\n"
- << ll_pretty_print_sd(mResponses) << LL_ENDL;
- break;
- case CURLE_COULDNT_RESOLVE_HOST:
- mAuthResponse = E_COULDNT_RESOLVE_HOST;
- LL_DEBUGS("UserAuth") << "Could not resolve host" << LL_ENDL;
- break;
- #if CURLE_SSL_CACERT != CURLE_SSL_PEER_CERTIFICATE
- // Note: CURLE_SSL_CACERT and CURLE_SSL_CACERT may expand to the same
- // value in recent curl versions (seen with curl v7.68).
- case CURLE_SSL_PEER_CERTIFICATE:
- mAuthResponse = E_SSL_PEER_CERTIFICATE;
- LL_DEBUGS("UserAuth") << "Invalid peer SSL certificate" << LL_ENDL;
- break;
- #endif
- case CURLE_SSL_CACERT:
- mAuthResponse = E_SSL_CACERT;
- LL_DEBUGS("UserAuth") << "Invalid SSL certificate" << LL_ENDL;
- break;
- case CURLE_SSL_CONNECT_ERROR:
- mAuthResponse = E_SSL_CONNECT_ERROR;
- LL_DEBUGS("UserAuth") << "Connection error" << LL_ENDL;
- break;
- default:
- mAuthResponse = E_UNHANDLED_ERROR;
- LL_DEBUGS("UserAuth") << "Unhandled error: " << result << LL_ENDL;
- }
- llinfos << "Processed response: " << result << llendl;
- delete mTransaction;
- mTransaction = NULL;
- return mAuthResponse;
- }
- const LLSD& LLUserAuth::getResponse1stMap(const std::string& name) const
- {
- if (mResponses.has(name) && mResponses[name].isArray() &&
- mResponses[name][0].isMap())
- {
- return mResponses[name][0];
- }
- static const LLSD empty;
- return empty;
- }
|