A few options I missed with the last commit, and some minor patching because it's in the same file.
454 lines
13 KiB
C++
454 lines
13 KiB
C++
/**
|
|
* @file lluserauth.cpp
|
|
* @brief LLUserAuth class implementation
|
|
*
|
|
* $LicenseInfo:firstyear=2003&license=viewergpl$
|
|
*
|
|
* Copyright (c) 2003-2009, Linden Research, Inc.
|
|
*
|
|
* 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 "llviewerprecompiledheaders.h"
|
|
|
|
#include "lluserauth.h"
|
|
|
|
#include <sstream>
|
|
#include <iterator>
|
|
|
|
#include "lldir.h"
|
|
#include "llversionviewer.h"
|
|
#include "llappviewer.h"
|
|
#include "llviewerbuild.h"
|
|
#include "llviewercontrol.h"
|
|
#include "llxmlrpctransaction.h"
|
|
#include "llsdutil.h"
|
|
|
|
// NOTE: MUST include these after otherincludes since queue gets redefined!?!!
|
|
#include <curl/curl.h>
|
|
#include <xmlrpc-epi/xmlrpc.h>
|
|
|
|
|
|
// Don't 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.
|
|
// *FIX: This is misreporting on linux. Change this so that linux is
|
|
// in fact reporting linux.
|
|
#if LL_WINDOWS || LL_LINUX
|
|
static const char* PLATFORM_STRING = "Win";
|
|
#elif LL_DARWIN
|
|
static const char* PLATFORM_STRING = "Mac";
|
|
#elif LL_LINUX
|
|
static const char* PLATFORM_STRING = "Lnx";
|
|
#elif LL_SOLARIS
|
|
static const char* PLATFORM_STRING = "Sol";
|
|
#else
|
|
#error("Unknown platform defined!")
|
|
#endif
|
|
|
|
|
|
LLUserAuth::LLUserAuth() :
|
|
mTransaction(NULL),
|
|
mLastTransferRateBPS(0),
|
|
mResult(LLSD())
|
|
{
|
|
mAuthResponse = E_NO_RESPONSE_YET;
|
|
}
|
|
|
|
LLUserAuth::~LLUserAuth()
|
|
{
|
|
reset();
|
|
}
|
|
|
|
void LLUserAuth::reset()
|
|
{
|
|
delete mTransaction;
|
|
mTransaction = NULL;
|
|
mResponses.clear();
|
|
mOptions.clear();
|
|
mResult.clear();
|
|
}
|
|
|
|
|
|
void LLUserAuth::authenticate(
|
|
const std::string& auth_uri,
|
|
const std::string& method,
|
|
const std::string& firstname,
|
|
const std::string& lastname,
|
|
LLUUID web_login_key,
|
|
const std::string& start,
|
|
BOOL skip_optional,
|
|
BOOL accept_tos,
|
|
BOOL accept_critical_message,
|
|
BOOL last_exec_froze,
|
|
const std::vector<const char*>& requested_options,
|
|
const std::string& hashed_mac,
|
|
const std::string& hashed_volume_serial)
|
|
{
|
|
LL_INFOS2("AppInit", "Authentication") << "Authenticating: " << firstname << " " << lastname << ", "
|
|
<< /*dpasswd.c_str() <<*/ LL_ENDL;
|
|
std::ostringstream option_str;
|
|
option_str << "Options: ";
|
|
std::ostream_iterator<const char*> appender(option_str, ", ");
|
|
std::copy(requested_options.begin(), requested_options.end(), appender);
|
|
option_str << "END";
|
|
|
|
LL_INFOS2("AppInit", "Authentication") << option_str.str() << LL_ENDL;
|
|
|
|
mAuthResponse = E_NO_RESPONSE_YET;
|
|
//mDownloadTimer.reset();
|
|
|
|
// create the request
|
|
XMLRPC_REQUEST request = XMLRPC_RequestNew();
|
|
XMLRPC_RequestSetMethodName(request, method.c_str());
|
|
XMLRPC_RequestSetRequestType(request, xmlrpc_request_call);
|
|
|
|
// stuff the parameters
|
|
XMLRPC_VALUE params = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct);
|
|
XMLRPC_VectorAppendString(params, "first", firstname.c_str(), 0);
|
|
XMLRPC_VectorAppendString(params, "last", lastname.c_str(), 0);
|
|
XMLRPC_VectorAppendString(params, "web_login_key", web_login_key.getString().c_str(), 0);
|
|
XMLRPC_VectorAppendString(params, "start", start.c_str(), 0);
|
|
XMLRPC_VectorAppendString(params, "version", gCurrentVersion.c_str(), 0); // Includes channel name
|
|
XMLRPC_VectorAppendString(params, "channel", LL_CHANNEL, 0);
|
|
XMLRPC_VectorAppendString(params, "platform", PLATFORM_STRING, 0);
|
|
|
|
XMLRPC_VectorAppendString(params, "mac", hashed_mac.c_str(), 0);
|
|
// A bit of security through obscurity: id0 is volume_serial
|
|
|
|
XMLRPC_VectorAppendString(params, "id0", hashed_volume_serial.c_str(), 0);
|
|
if (skip_optional)
|
|
{
|
|
XMLRPC_VectorAppendString(params, "skipoptional", "true", 0);
|
|
}
|
|
if (accept_tos)
|
|
{
|
|
XMLRPC_VectorAppendString(params, "agree_to_tos", "true", 0);
|
|
}
|
|
if (accept_critical_message)
|
|
{
|
|
XMLRPC_VectorAppendString(params, "read_critical", "true", 0);
|
|
}
|
|
XMLRPC_VectorAppendInt(params, "last_exec_event", (int) last_exec_froze);
|
|
|
|
// append optional requests in an array
|
|
XMLRPC_VALUE options = XMLRPC_CreateVector("options", xmlrpc_vector_array);
|
|
std::vector<const char*>::const_iterator it = requested_options.begin();
|
|
std::vector<const char*>::const_iterator end = requested_options.end();
|
|
for( ; it < end; ++it)
|
|
{
|
|
XMLRPC_VectorAppendString(options, NULL, (*it), 0);
|
|
}
|
|
XMLRPC_AddValueToVector(params, options);
|
|
|
|
// put the parameters on the request
|
|
XMLRPC_RequestSetData(request, params);
|
|
|
|
mTransaction = new LLXMLRPCTransaction(auth_uri, request);
|
|
|
|
XMLRPC_RequestFree(request, 1);
|
|
|
|
LL_INFOS2("AppInit", "Authentication") << "LLUserAuth::authenticate: uri=" << auth_uri << LL_ENDL;
|
|
}
|
|
|
|
|
|
|
|
// Legacy version of constructor
|
|
|
|
// passwd is already MD5 hashed by the time we get to it.
|
|
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,
|
|
BOOL last_exec_froze,
|
|
const std::vector<const char*>& requested_options,
|
|
const std::string& hashed_mac,
|
|
const std::string& hashed_volume_serial)
|
|
{
|
|
std::string dpasswd("$1$");
|
|
dpasswd.append(passwd);
|
|
LL_INFOS2("AppInit", "Authentication") << "Authenticating: " << firstname << " " << lastname << ", "
|
|
<< /*dpasswd.c_str() <<*/ LL_ENDL;
|
|
std::ostringstream option_str;
|
|
option_str << "Options: ";
|
|
std::ostream_iterator<const char*> appender(option_str, ", ");
|
|
std::copy(requested_options.begin(), requested_options.end(), appender);
|
|
option_str << "END";
|
|
|
|
LL_INFOS2("AppInit", "Authentication") << option_str.str().c_str() << LL_ENDL;
|
|
|
|
mAuthResponse = E_NO_RESPONSE_YET;
|
|
//mDownloadTimer.reset();
|
|
|
|
// create the request
|
|
XMLRPC_REQUEST request = XMLRPC_RequestNew();
|
|
XMLRPC_RequestSetMethodName(request, method.c_str());
|
|
XMLRPC_RequestSetRequestType(request, xmlrpc_request_call);
|
|
|
|
// stuff the parameters
|
|
XMLRPC_VALUE params = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct);
|
|
XMLRPC_VectorAppendString(params, "first", firstname.c_str(), 0);
|
|
XMLRPC_VectorAppendString(params, "last", lastname.c_str(), 0);
|
|
XMLRPC_VectorAppendString(params, "passwd", dpasswd.c_str(), 0);
|
|
XMLRPC_VectorAppendString(params, "start", start.c_str(), 0);
|
|
XMLRPC_VectorAppendString(params, "version", gCurrentVersion.c_str(), 0); // Includes channel name
|
|
XMLRPC_VectorAppendString(params, "channel", LL_CHANNEL, 0);
|
|
XMLRPC_VectorAppendString(params, "platform", PLATFORM_STRING, 0);
|
|
|
|
XMLRPC_VectorAppendString(params, "mac", hashed_mac.c_str(), 0);
|
|
// A bit of security through obscurity: id0 is volume_serial
|
|
// ^^^^^^^^^^^^^^^^^^^^
|
|
// you fucking idiot - charbl
|
|
|
|
XMLRPC_VectorAppendString(params, "id0", hashed_volume_serial.c_str(), 0);
|
|
if (skip_optional)
|
|
{
|
|
XMLRPC_VectorAppendString(params, "skipoptional", "true", 0);
|
|
}
|
|
if (accept_tos)
|
|
{
|
|
XMLRPC_VectorAppendString(params, "agree_to_tos", "true", 0);
|
|
}
|
|
if (accept_critical_message)
|
|
{
|
|
XMLRPC_VectorAppendString(params, "read_critical", "true", 0);
|
|
}
|
|
XMLRPC_VectorAppendInt(params, "last_exec_event", (int) last_exec_froze);
|
|
|
|
// append optional requests in an array
|
|
XMLRPC_VALUE options = XMLRPC_CreateVector("options", xmlrpc_vector_array);
|
|
std::vector<const char*>::const_iterator it = requested_options.begin();
|
|
std::vector<const char*>::const_iterator end = requested_options.end();
|
|
for( ; it < end; ++it)
|
|
{
|
|
XMLRPC_VectorAppendString(options, NULL, (*it), 0);
|
|
}
|
|
XMLRPC_AddValueToVector(params, options);
|
|
|
|
// put the parameters on the request
|
|
XMLRPC_RequestSetData(request, params);
|
|
|
|
mTransaction = new LLXMLRPCTransaction(auth_uri, request);
|
|
|
|
XMLRPC_RequestFree(request, 1);
|
|
|
|
LL_INFOS2("AppInit", "Authentication") << "LLUserAuth::authenticate: uri=" << auth_uri << LL_ENDL;
|
|
}
|
|
|
|
|
|
LLUserAuth::UserAuthcode LLUserAuth::authResponse()
|
|
{
|
|
if (!mTransaction)
|
|
{
|
|
return mAuthResponse;
|
|
}
|
|
|
|
bool done = mTransaction->process();
|
|
|
|
if (!done) {
|
|
if (LLXMLRPCTransaction::StatusDownloading == mTransaction->status(0))
|
|
{
|
|
mAuthResponse = E_DOWNLOADING;
|
|
}
|
|
|
|
return mAuthResponse;
|
|
}
|
|
|
|
|
|
mLastTransferRateBPS = mTransaction->transferRate();
|
|
|
|
int result;
|
|
mTransaction->status(&result);
|
|
mErrorMessage = mTransaction->statusMessage();
|
|
|
|
// if curl was ok, parse the download area.
|
|
switch (result)
|
|
{
|
|
case CURLE_OK:
|
|
mAuthResponse = parseResponse();
|
|
break;
|
|
case CURLE_COULDNT_RESOLVE_HOST:
|
|
mAuthResponse = E_COULDNT_RESOLVE_HOST;
|
|
break;
|
|
case CURLE_SSL_PEER_CERTIFICATE:
|
|
mAuthResponse = E_SSL_PEER_CERTIFICATE;
|
|
break;
|
|
case CURLE_SSL_CACERT:
|
|
mAuthResponse = E_SSL_CACERT;
|
|
break;
|
|
case CURLE_SSL_CONNECT_ERROR:
|
|
mAuthResponse = E_SSL_CONNECT_ERROR;
|
|
break;
|
|
default:
|
|
mAuthResponse = E_UNHANDLED_ERROR;
|
|
break;
|
|
}
|
|
|
|
LL_INFOS2("AppInit", "Authentication") << "Processed response: " << result << LL_ENDL;
|
|
|
|
delete mTransaction;
|
|
mTransaction = NULL;
|
|
|
|
return mAuthResponse;
|
|
}
|
|
|
|
static void parseOptionInto(
|
|
const std::string& id, XMLRPC_VALUE option, LLUserAuth::options_t& options)
|
|
{
|
|
std::string key;
|
|
std::string val;
|
|
XMLRPC_VALUE_TYPE_EASY type;
|
|
XMLRPC_VALUE row = XMLRPC_VectorRewind(option);
|
|
while(row)
|
|
{
|
|
XMLRPC_VALUE opt = XMLRPC_VectorRewind(row);
|
|
LLUserAuth::response_t responses;
|
|
while(opt)
|
|
{
|
|
key.assign(XMLRPC_GetValueID(opt));
|
|
//llinfos << "option key: " << key << llendl;
|
|
type = XMLRPC_GetValueTypeEasy(opt);
|
|
if(xmlrpc_type_string == type)
|
|
{
|
|
val.assign(XMLRPC_GetValueString(opt));
|
|
//llinfos << "string val: " << val << llendl;
|
|
}
|
|
else if(xmlrpc_type_int == type)
|
|
{
|
|
val = llformat("%d", XMLRPC_GetValueInt(opt));
|
|
//llinfos << "int val: " << val << llendl;
|
|
}
|
|
else if(xmlrpc_type_double == type)
|
|
{
|
|
val = llformat("%g", XMLRPC_GetValueDouble(opt));
|
|
//llinfos << "double val: " << val << llendl;
|
|
}
|
|
else
|
|
{ // Can't understand the type
|
|
val = "???";
|
|
//llinfos << "unknown value type: " << type << llendl;
|
|
}
|
|
|
|
responses.insert(LLUserAuth::response_t::value_type(key, val));
|
|
opt = XMLRPC_VectorNext(row);
|
|
}
|
|
options.push_back(responses);
|
|
row = XMLRPC_VectorNext(option);
|
|
}
|
|
}
|
|
|
|
LLUserAuth::UserAuthcode LLUserAuth::parseResponse()
|
|
{
|
|
// The job of this function is to parse sCurlDownloadArea and
|
|
// extract every member into either the mResponses or
|
|
// mOptions. For now, we will only be looking at mResponses, which
|
|
// will all be string => string pairs.
|
|
UserAuthcode rv = E_UNHANDLED_ERROR;
|
|
XMLRPC_REQUEST response = mTransaction->response();
|
|
if(!response) return rv;
|
|
|
|
// clear out any old parsing
|
|
mResponses.clear();
|
|
mOptions.clear();
|
|
|
|
// Now, parse everything
|
|
std::string key;
|
|
std::string val;
|
|
XMLRPC_VALUE param = NULL;
|
|
XMLRPC_VALUE current = NULL;
|
|
XMLRPC_VALUE_TYPE_EASY type;
|
|
param = XMLRPC_RequestGetData(response);
|
|
if(!param) goto exit;
|
|
current = XMLRPC_VectorRewind(param);
|
|
while(current)
|
|
{
|
|
key.assign(XMLRPC_GetValueID(current));
|
|
lldebugs << "key: " << key << llendl;
|
|
type = XMLRPC_GetValueTypeEasy(current);
|
|
if(xmlrpc_type_string == type)
|
|
{
|
|
val.assign(XMLRPC_GetValueString(current));
|
|
lldebugs << "val: " << val << llendl;
|
|
mResponses.insert(response_t::value_type(key, val));
|
|
}
|
|
else if(xmlrpc_type_int == type)
|
|
{
|
|
val = llformat( "%d", XMLRPC_GetValueInt(current));
|
|
lldebugs << "val: " << val << llendl;
|
|
mResponses.insert(response_t::value_type(key, val));
|
|
}
|
|
else if(xmlrpc_type_array == type)
|
|
{
|
|
options_t options;
|
|
parseOptionInto(key, current, options);
|
|
mOptions.insert(all_options_t::value_type(key, options));
|
|
}
|
|
else
|
|
{
|
|
// whoops - bad response
|
|
llwarns << "Unhandled xmlrpc type, key, value: " << type << " "
|
|
<< key << " " << val << "." << llendl;
|
|
rv = E_UNHANDLED_ERROR;
|
|
break;
|
|
}
|
|
current = XMLRPC_VectorNext(param);
|
|
rv = E_OK;
|
|
}
|
|
|
|
exit:
|
|
return rv;
|
|
}
|
|
|
|
const std::string& LLUserAuth::getResponse(const std::string& key) const
|
|
{
|
|
response_t::const_iterator it = mResponses.find(key);
|
|
if(it != mResponses.end())
|
|
{
|
|
return((*it).second);
|
|
}
|
|
return LLStringUtil::null;
|
|
}
|
|
|
|
BOOL LLUserAuth::getOptions(const std::string& key, options_t& options) const
|
|
{
|
|
all_options_t::const_iterator it = mOptions.find(key);
|
|
if(it != mOptions.end())
|
|
{
|
|
// found the option set, copy them onto the container.
|
|
std::back_insert_iterator<options_t> ii(options);
|
|
std::copy((*it).second.begin(), (*it).second.end(), ii);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|