00001
00032 #include "llviewerprecompiledheaders.h"
00033
00034 #include "lluserauth.h"
00035
00036 #include <sstream>
00037 #include <iterator>
00038
00039 #include "lldir.h"
00040 #include "llversionviewer.h"
00041 #include "viewer.h"
00042 #include "llviewerbuild.h"
00043 #include "llviewercontrol.h"
00044 #include "llxmlrpctransaction.h"
00045
00046
00047 #include <curl/curl.h>
00048 #include <xmlrpc-epi/xmlrpc.h>
00049
00050
00051
00052
00053
00054
00055
00056
00057 #if LL_WINDOWS || LL_LINUX
00058 static const char* PLATFORM_STRING = "Win";
00059 #elif LL_DARWIN
00060 static const char* PLATFORM_STRING = "Mac";
00061 #elif LL_LINUX
00062 static const char* PLATFORM_STRING = "Lnx";
00063 #elif LL_SOLARIS
00064 static const char* PLATFORM_STRING = "Sol";
00065 #else
00066 #error("Unknown platform defined!")
00067 #endif
00068
00069 LLUserAuth *gUserAuthp = NULL;
00070
00071
00072 LLUserAuth::LLUserAuth() :
00073 mTransaction(NULL),
00074 mLastTransferRateBPS(0)
00075 {
00076 mAuthResponse = E_NO_RESPONSE_YET;
00077 }
00078
00079 LLUserAuth::~LLUserAuth()
00080 {
00081 delete mTransaction;
00082 mTransaction = NULL;
00083 }
00084
00085
00086 void LLUserAuth::authenticate(
00087 const char* auth_uri,
00088 const char* method,
00089 const char* firstname,
00090 const char* lastname,
00091 const char* passwd,
00092 const char* start,
00093 BOOL skip_optional,
00094 BOOL accept_tos,
00095 BOOL accept_critical_message,
00096 const LLUUID& viewer_digest,
00097 BOOL last_exec_froze,
00098 const std::vector<const char*>& requested_options,
00099 const std::string& hashed_mac,
00100 const std::string& hashed_volume_serial)
00101 {
00102 std::string dpasswd("$1$");
00103 dpasswd.append(passwd);
00104 llinfos << "Authenticating: " << firstname << " " << lastname << ", "
00105 << llendl;
00106 std::ostringstream option_str;
00107 option_str << "Options: ";
00108 std::ostream_iterator<const char*> appender(option_str, ", ");
00109 std::copy(requested_options.begin(), requested_options.end(), appender);
00110 option_str << "END";
00111 llinfos << option_str.str().c_str() << llendl;
00112
00113 mAuthResponse = E_NO_RESPONSE_YET;
00114
00115
00116
00117 XMLRPC_REQUEST request = XMLRPC_RequestNew();
00118 XMLRPC_RequestSetMethodName(request, method);
00119 XMLRPC_RequestSetRequestType(request, xmlrpc_request_call);
00120
00121
00122 XMLRPC_VALUE params = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct);
00123 XMLRPC_VectorAppendString(params, "first", firstname, 0);
00124 XMLRPC_VectorAppendString(params, "last", lastname, 0);
00125 XMLRPC_VectorAppendString(params, "passwd", dpasswd.c_str(), 0);
00126 XMLRPC_VectorAppendString(params, "start", start, 0);
00127 XMLRPC_VectorAppendString(params, "version", gCurrentVersion.c_str(), 0);
00128 XMLRPC_VectorAppendString(params, "channel", gChannelName.c_str(), 0);
00129 XMLRPC_VectorAppendString(params, "platform", PLATFORM_STRING, 0);
00130 XMLRPC_VectorAppendString(params, "mac", hashed_mac.c_str(), 0);
00131
00132 XMLRPC_VectorAppendString(params, "id0", hashed_volume_serial.c_str(), 0);
00133 if (skip_optional)
00134 {
00135 XMLRPC_VectorAppendString(params, "skipoptional", "true", 0);
00136 }
00137 if (accept_tos)
00138 {
00139 XMLRPC_VectorAppendString(params, "agree_to_tos", "true", 0);
00140 }
00141 if (accept_critical_message)
00142 {
00143 XMLRPC_VectorAppendString(params, "read_critical", "true", 0);
00144 }
00145 XMLRPC_VectorAppendString(params, "viewer_digest", viewer_digest.asString().c_str(), 0);
00146 XMLRPC_VectorAppendInt(params, "last_exec_event", (int) last_exec_froze);
00147
00148
00149 XMLRPC_VALUE options = XMLRPC_CreateVector("options", xmlrpc_vector_array);
00150 std::vector<const char*>::const_iterator it = requested_options.begin();
00151 std::vector<const char*>::const_iterator end = requested_options.end();
00152 for( ; it < end; ++it)
00153 {
00154 XMLRPC_VectorAppendString(options, NULL, (*it), 0);
00155 }
00156 XMLRPC_AddValueToVector(params, options);
00157
00158
00159 XMLRPC_RequestSetData(request, params);
00160
00161 mTransaction = new LLXMLRPCTransaction(auth_uri, request);
00162
00163 XMLRPC_RequestFree(request, 1);
00164
00165 llinfos << "LLUserAuth::authenticate: uri=" << auth_uri << llendl;
00166 }
00167
00168 LLUserAuth::UserAuthcode LLUserAuth::authResponse()
00169 {
00170 if (!mTransaction)
00171 {
00172 return mAuthResponse;
00173 }
00174
00175 bool done = mTransaction->process();
00176
00177 if (!done) {
00178 if (LLXMLRPCTransaction::StatusDownloading == mTransaction->status(0))
00179 {
00180 mAuthResponse = E_DOWNLOADING;
00181 }
00182
00183 return mAuthResponse;
00184 }
00185
00186
00187 mLastTransferRateBPS = mTransaction->transferRate();
00188
00189 int result;
00190 mTransaction->status(&result);
00191 mErrorMessage = mTransaction->statusMessage();
00192
00193
00194 switch (result)
00195 {
00196 case CURLE_OK:
00197 mAuthResponse = parseResponse();
00198 break;
00199 case CURLE_COULDNT_RESOLVE_HOST:
00200 mAuthResponse = E_COULDNT_RESOLVE_HOST;
00201 break;
00202 case CURLE_SSL_PEER_CERTIFICATE:
00203 mAuthResponse = E_SSL_PEER_CERTIFICATE;
00204 break;
00205 case CURLE_SSL_CACERT:
00206 mAuthResponse = E_SSL_CACERT;
00207 break;
00208 case CURLE_SSL_CONNECT_ERROR:
00209 mAuthResponse = E_SSL_CONNECT_ERROR;
00210 break;
00211 default:
00212 mAuthResponse = E_UNHANDLED_ERROR;
00213 break;
00214 }
00215
00216 llinfos << "Processed response: " << result << llendl;
00217
00218 delete mTransaction;
00219 mTransaction = NULL;
00220
00221 return mAuthResponse;
00222 }
00223
00224 static void parseOptionInto(
00225 const std::string& id, XMLRPC_VALUE option, LLUserAuth::options_t& options)
00226 {
00227 std::string key;
00228 std::string val;
00229 XMLRPC_VALUE_TYPE_EASY type;
00230 XMLRPC_VALUE row = XMLRPC_VectorRewind(option);
00231 while(row)
00232 {
00233 XMLRPC_VALUE opt = XMLRPC_VectorRewind(row);
00234 LLUserAuth::response_t responses;
00235 while(opt)
00236 {
00237 key.assign(XMLRPC_GetValueID(opt));
00238
00239 type = XMLRPC_GetValueTypeEasy(opt);
00240 if(xmlrpc_type_string == type)
00241 {
00242 val.assign(XMLRPC_GetValueString(opt));
00243 }
00244 else if(xmlrpc_type_int == type)
00245 {
00246 val = llformat("%d", XMLRPC_GetValueInt(opt));
00247 }
00248
00249 responses.insert(LLUserAuth::response_t::value_type(key, val));
00250 opt = XMLRPC_VectorNext(row);
00251 }
00252 options.push_back(responses);
00253 row = XMLRPC_VectorNext(option);
00254 }
00255 }
00256
00257 LLUserAuth::UserAuthcode LLUserAuth::parseResponse()
00258 {
00259
00260
00261
00262
00263 UserAuthcode rv = E_UNHANDLED_ERROR;
00264 XMLRPC_REQUEST response = mTransaction->response();
00265 if(!response) return rv;
00266
00267
00268 mResponses.clear();
00269 mOptions.clear();
00270
00271
00272 std::string key;
00273 std::string val;
00274 XMLRPC_VALUE param = NULL;
00275 XMLRPC_VALUE current = NULL;
00276 XMLRPC_VALUE_TYPE_EASY type;
00277 param = XMLRPC_RequestGetData(response);
00278 if(!param) goto exit;
00279 current = XMLRPC_VectorRewind(param);
00280 while(current)
00281 {
00282 key.assign(XMLRPC_GetValueID(current));
00283 lldebugs << "key: " << key << llendl;
00284 type = XMLRPC_GetValueTypeEasy(current);
00285 if(xmlrpc_type_string == type)
00286 {
00287 val.assign(XMLRPC_GetValueString(current));
00288 lldebugs << "val: " << val << llendl;
00289 mResponses.insert(response_t::value_type(key, val));
00290 }
00291 else if(xmlrpc_type_int == type)
00292 {
00293 char buf[MAX_STRING];
00294 snprintf(buf, MAX_STRING, "%d", XMLRPC_GetValueInt(current));
00295 val.assign(buf);
00296 lldebugs << "val: " << val << llendl;
00297 mResponses.insert(response_t::value_type(key, val));
00298 }
00299 else if(xmlrpc_type_array == type)
00300 {
00301 options_t options;
00302 parseOptionInto(key, current, options);
00303 mOptions.insert(all_options_t::value_type(key, options));
00304 }
00305 else
00306 {
00307
00308 llwarns << "Unhandled xmlrpc type, key, value: " << type << " "
00309 << key << " " << val << "." << llendl;
00310 rv = E_UNHANDLED_ERROR;
00311 break;
00312 }
00313 current = XMLRPC_VectorNext(param);
00314 rv = E_OK;
00315 }
00316
00317 exit:
00318 return rv;
00319 }
00320
00321 const char* LLUserAuth::getResponse(const char* name) const
00322 {
00323 if(!name) return NULL;
00324 std::string key(name);
00325 response_t::const_iterator it = mResponses.find(key);
00326 if(it != mResponses.end())
00327 {
00328 return((*it).second.c_str());
00329 }
00330 return NULL;
00331 }
00332
00333 BOOL LLUserAuth::getOptions(const char* name, options_t& options) const
00334 {
00335 if(!name) return FALSE;
00336 std::string key(name);
00337 all_options_t::const_iterator it = mOptions.find(key);
00338 if(it != mOptions.end())
00339 {
00340
00341 std::back_insert_iterator<options_t> ii(options);
00342 std::copy((*it).second.begin(), (*it).second.end(), ii);
00343 return TRUE;
00344 }
00345 return FALSE;
00346 }
00347
00348