From 658ccc3e85487f9f24ff3b5926e60d6cce7f42e0 Mon Sep 17 00:00:00 2001 From: Roxie Linden Date: Wed, 7 Apr 2010 11:08:04 -0700 Subject: Re-insert backed out SLE checkin so we can fix it --- indra/newview/llstartup.cpp | 722 ++++++++++++++++++++++---------------------- 1 file changed, 369 insertions(+), 353 deletions(-) (limited to 'indra/newview/llstartup.cpp') diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index b5a73a3143..4f1bcde302 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -147,7 +147,7 @@ #include "lltrans.h" #include "llui.h" #include "llurldispatcher.h" -#include "llurlsimstring.h" +#include "llslurl.h" #include "llurlhistory.h" #include "llurlwhitelist.h" #include "llvieweraudio.h" @@ -192,6 +192,7 @@ #include "llinventorybridge.h" #include "llappearancemgr.h" #include "llavatariconctrl.h" +#include "llvoicechannel.h" #include "lllogin.h" #include "llevents.h" @@ -228,11 +229,11 @@ static std::string sInitialOutfitGender; // "male" or "female" static bool gUseCircuitCallbackCalled = false; EStartupState LLStartUp::gStartupState = STATE_FIRST; +LLSLURL LLStartUp::sStartSLURL; -// *NOTE:Mani - to reconcile with giab changes... -static std::string gFirstname; -static std::string gLastname; -static std::string gPassword; +static LLPointer gUserCredential; +static std::string gDisplayName; +static BOOL gRememberPassword = TRUE; static U64 gFirstSimHandle = 0; static LLHost gFirstSim; @@ -249,7 +250,6 @@ boost::scoped_ptr LLStartUp::sListener(new LLStartupListener( void login_show(); void login_callback(S32 option, void* userdata); -bool is_hex_string(U8* str, S32 len); void show_first_run_dialog(); bool first_run_dialog_callback(const LLSD& notification, const LLSD& response); void set_startup_status(const F32 frac, const std::string& string, const std::string& msg); @@ -262,6 +262,9 @@ bool callback_choose_gender(const LLSD& notification, const LLSD& response); void init_start_screen(S32 location_id); void release_start_screen(); void reset_login(); +LLSD transform_cert_args(LLPointer cert); +void general_cert_done(const LLSD& notification, const LLSD& response); +void trust_cert_done(const LLSD& notification, const LLSD& response); void apply_udp_blacklist(const std::string& csv); bool process_login_success_response(); void transition_back_to_login_panel(const std::string& emsg); @@ -364,7 +367,7 @@ bool idle_startup() if ( STATE_FIRST == LLStartUp::getStartupState() ) { - gViewerWindow->showCursor(); + gViewerWindow->showCursor(); gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT); ///////////////////////////////////////////////// @@ -662,69 +665,25 @@ bool idle_startup() // // Log on to system // - if (!LLStartUp::sSLURLCommand.empty()) - { - // this might be a secondlife:///app/login URL - gLoginHandler.parseDirectLogin(LLStartUp::sSLURLCommand); - } - if (!gLoginHandler.getFirstName().empty() - || !gLoginHandler.getLastName().empty() - /*|| !gLoginHandler.getWebLoginKey().isNull()*/ ) - { - // We have at least some login information on a SLURL - gFirstname = gLoginHandler.getFirstName(); - gLastname = gLoginHandler.getLastName(); - LL_DEBUGS("LLStartup") << "STATE_FIRST: setting gFirstname, gLastname from gLoginHandler: '" << gFirstname << "' '" << gLastname << "'" << LL_ENDL; - - // Show the login screen if we don't have everything - show_connect_box = - gFirstname.empty() || gLastname.empty(); - } - else if(gSavedSettings.getLLSD("UserLoginInfo").size() == 3) - { - LLSD cmd_line_login = gSavedSettings.getLLSD("UserLoginInfo"); - gFirstname = cmd_line_login[0].asString(); - gLastname = cmd_line_login[1].asString(); - LL_DEBUGS("LLStartup") << "Setting gFirstname, gLastname from gSavedSettings(\"UserLoginInfo\"): '" << gFirstname << "' '" << gLastname << "'" << LL_ENDL; - - LLMD5 pass((unsigned char*)cmd_line_login[2].asString().c_str()); - char md5pass[33]; /* Flawfinder: ignore */ - pass.hex_digest(md5pass); - gPassword = md5pass; - -#ifdef USE_VIEWER_AUTH - show_connect_box = true; -#else - show_connect_box = false; -#endif - gSavedSettings.setBOOL("AutoLogin", TRUE); - } - else if (gSavedSettings.getBOOL("AutoLogin")) - { - gFirstname = gSavedSettings.getString("FirstName"); - gLastname = gSavedSettings.getString("LastName"); - LL_DEBUGS("LLStartup") << "AutoLogin: setting gFirstname, gLastname from gSavedSettings(\"First|LastName\"): '" << gFirstname << "' '" << gLastname << "'" << LL_ENDL; - gPassword = LLStartUp::loadPasswordFromDisk(); - gSavedSettings.setBOOL("RememberPassword", TRUE); - -#ifdef USE_VIEWER_AUTH - show_connect_box = true; -#else - show_connect_box = false; -#endif + if (gUserCredential.isNull()) + { + gUserCredential = gLoginHandler.initializeLoginInfo(); } - else + if (gUserCredential.isNull()) { - // if not automatically logging in, display login dialog - // a valid grid is selected - gFirstname = gSavedSettings.getString("FirstName"); - gLastname = gSavedSettings.getString("LastName"); - LL_DEBUGS("LLStartup") << "normal login: setting gFirstname, gLastname from gSavedSettings(\"First|LastName\"): '" << gFirstname << "' '" << gLastname << "'" << LL_ENDL; - gPassword = LLStartUp::loadPasswordFromDisk(); - show_connect_box = true; + show_connect_box = TRUE; + } + else if (gSavedSettings.getBOOL("AutoLogin")) + { + gRememberPassword = TRUE; + gSavedSettings.setBOOL("RememberPassword", TRUE); + show_connect_box = false; + } + else + { + gRememberPassword = gSavedSettings.getBOOL("RememberPassword"); + show_connect_box = TRUE; } - - // Go to the next startup state LLStartUp::setStartupState( STATE_BROWSER_INIT ); return FALSE; @@ -756,8 +715,10 @@ bool idle_startup() // Load all the name information out of the login view // NOTE: Hits "Attempted getFields with no login view shown" warning, since we don't // show the login view until login_show() is called below. - // LLPanelLogin::getFields(gFirstname, gLastname, gPassword); - + if (gUserCredential.isNull()) + { + gUserCredential = gLoginHandler.initializeLoginInfo(); + } if (gNoRender) { LL_ERRS("AppInit") << "Need to autologin or use command line with norender!" << LL_ENDL; @@ -768,8 +729,10 @@ bool idle_startup() // Show the login dialog login_show(); // connect dialog is already shown, so fill in the names - LLPanelLogin::setFields( gFirstname, gLastname, gPassword); - + if (gUserCredential.notNull()) + { + LLPanelLogin::setFields( gUserCredential, gRememberPassword); + } LLPanelLogin::giveFocus(); gSavedSettings.setBOOL("FirstRunThisInstall", FALSE); @@ -839,39 +802,36 @@ bool idle_startup() // DEV-42215: Make sure they're not empty -- gFirstname and gLastname // might already have been set from gSavedSettings, and it's too bad // to overwrite valid values with empty strings. - if (! gLoginHandler.getFirstName().empty() && ! gLoginHandler.getLastName().empty()) - { - gFirstname = gLoginHandler.getFirstName(); - gLastname = gLoginHandler.getLastName(); - LL_DEBUGS("LLStartup") << "STATE_LOGIN_CLEANUP: setting gFirstname, gLastname from gLoginHandler: '" << gFirstname << "' '" << gLastname << "'" << LL_ENDL; - } if (show_connect_box) { // TODO if not use viewer auth // Load all the name information out of the login view - LLPanelLogin::getFields(&gFirstname, &gLastname, &gPassword); + LLPanelLogin::getFields(gUserCredential, gRememberPassword); // end TODO // HACK: Try to make not jump on login gKeyboard->resetKeys(); } - if (!gFirstname.empty() && !gLastname.empty()) - { - gSavedSettings.setString("FirstName", gFirstname); - gSavedSettings.setString("LastName", gLastname); - - LL_INFOS("AppInit") << "Attempting login as: " << gFirstname << " " << gLastname << LL_ENDL; - gDebugInfo["LoginName"] = gFirstname + " " + gLastname; + // save the credentials + std::string userid = "unknown"; + if(gUserCredential.notNull()) + { + userid = gUserCredential->userID(); + gSecAPIHandler->saveCredential(gUserCredential, gRememberPassword); } - + gSavedSettings.setBOOL("RememberPassword", gRememberPassword); + LL_INFOS("AppInit") << "Attempting login as: " << userid << LL_ENDL; + gDebugInfo["LoginName"] = userid; + // create necessary directories // *FIX: these mkdir's should error check - gDirUtilp->setLindenUserDir(gFirstname, gLastname); + gDirUtilp->setLindenUserDir(userid); LLFile::mkdir(gDirUtilp->getLindenUserDir()); - + // Set PerAccountSettingsFile to the default value. + std::string per_account_settings_file = LLAppViewer::instance()->getSettingsFilename("Default", "PerAccount"); gSavedSettings.setString("PerAccountSettingsFile", gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, LLAppViewer::instance()->getSettingsFilename("Default", "PerAccount"))); @@ -901,9 +861,8 @@ bool idle_startup() { gDirUtilp->setChatLogsDir(gSavedPerAccountSettings.getString("InstantMessageLogPath")); } + gDirUtilp->setPerAccountChatLogsDir(userid); - gDirUtilp->setPerAccountChatLogsDir(gFirstname, gLastname); - LLFile::mkdir(gDirUtilp->getChatLogsDir()); LLFile::mkdir(gDirUtilp->getPerAccountChatLogsDir()); @@ -924,11 +883,7 @@ bool idle_startup() if (show_connect_box) { - std::string location; - LLPanelLogin::getLocation( location ); - LLURLSimString::setString( location ); - - // END TODO + LLSLURL slurl; LLPanelLogin::closePanel(); } @@ -952,26 +907,21 @@ bool idle_startup() // their last location, or some URL "-url //sim/x/y[/z]" // All accounts have both a home and a last location, and we don't support // more locations than that. Choose the appropriate one. JC - if (LLURLSimString::parse()) - { - // a startup URL was specified - agent_location_id = START_LOCATION_ID_URL; - - // doesn't really matter what location_which is, since - // gAgentStartLookAt will be overwritten when the - // UserLoginLocationReply arrives - location_which = START_LOCATION_ID_LAST; - } - else if (gSavedSettings.getString("LoginLocation") == "last" ) - { - agent_location_id = START_LOCATION_ID_LAST; // last location - location_which = START_LOCATION_ID_LAST; - } - else - { - agent_location_id = START_LOCATION_ID_HOME; // home - location_which = START_LOCATION_ID_HOME; - } + switch (LLStartUp::getStartSLURL().getType()) + { + case LLSLURL::LOCATION: + agent_location_id = START_LOCATION_ID_URL; + location_which = START_LOCATION_ID_LAST; + break; + case LLSLURL::LAST_LOCATION: + agent_location_id = START_LOCATION_ID_LAST; + location_which = START_LOCATION_ID_LAST; + break; + default: + agent_location_id = START_LOCATION_ID_HOME; + location_which = START_LOCATION_ID_HOME; + break; + } gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT); @@ -998,7 +948,7 @@ bool idle_startup() if(STATE_LOGIN_AUTH_INIT == LLStartUp::getStartupState()) { - gDebugInfo["GridName"] = LLViewerLogin::getInstance()->getGridLabel(); + gDebugInfo["GridName"] = LLGridManager::getInstance()->getGridLabel(); // Update progress status and the display loop. auth_desc = LLTrans::getString("LoginInProgress"); @@ -1022,11 +972,7 @@ bool idle_startup() // This call to LLLoginInstance::connect() starts the // authentication process. - LLSD credentials; - credentials["first"] = gFirstname; - credentials["last"] = gLastname; - credentials["passwd"] = gPassword; - login->connect(credentials); + login->connect(gUserCredential); LLStartUp::setStartupState( STATE_LOGIN_CURL_UNSTUCK ); return FALSE; @@ -1051,10 +997,11 @@ bool idle_startup() { LL_INFOS("LLStartup") << "Login failed, LLLoginInstance::getResponse(): " << LLLoginInstance::getInstance()->getResponse() << LL_ENDL; + LLSD response = LLLoginInstance::getInstance()->getResponse(); // Still have error conditions that may need some // sort of handling. - std::string reason_response = LLLoginInstance::getInstance()->getResponse("reason"); - std::string message_response = LLLoginInstance::getInstance()->getResponse("message"); + std::string reason_response = response["reason"]; + std::string message_response = response["message"]; if(!message_response.empty()) { @@ -1074,8 +1021,8 @@ bool idle_startup() if(reason_response == "key") { // Couldn't login because user/password is wrong - // Clear the password - gPassword = ""; + // Clear the credential + gUserCredential->clearAuthenticator(); } if(reason_response == "update" @@ -1088,18 +1035,65 @@ bool idle_startup() LLLoginInstance::getInstance()->disconnect(); LLAppViewer::instance()->forceQuit(); } - else + else { - // Don't pop up a notification in the TOS case because - // LLFloaterTOS::onCancel() already scolded the user. - if (reason_response != "tos") + if (reason_response != "tos") { - LLSD args; - args["ERROR_MESSAGE"] = emsg.str(); - LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL; - LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done); + // Don't pop up a notification in the TOS case because + // LLFloaterTOS::onCancel() already scolded the user. + std::string error_code; + if(response.has("errorcode")) + { + error_code = response["errorcode"].asString(); + } + if ((reason_response == "CURLError") && + (error_code == "SSL_CACERT" || error_code == "SSL_PEER_CERTIFICATE") && + response.has("certificate")) + { + // This was a certificate error, so grab the certificate + // and throw up the appropriate dialog. + LLPointer certificate = gSecAPIHandler->getCertificate(response["certificate"]); + if(certificate) + { + LLSD args = transform_cert_args(certificate); + + if(error_code == "SSL_CACERT") + { + // if we are handling an untrusted CA, throw up the dialog + // with the 'trust this CA' button. + LLNotificationsUtil::add("TrustCertificateError", args, response, + trust_cert_done); + + show_connect_box = true; + } + else + { + // the certificate exception returns a unique string for each type of exception. + // we grab this string via the LLUserAuth object, and use that to grab the localized + // string. + args["REASON"] = LLTrans::getString(message_response); + + LLNotificationsUtil::add("GeneralCertificateError", args, response, + general_cert_done); + + reset_login(); + gSavedSettings.setBOOL("AutoLogin", FALSE); + show_connect_box = true; + + } + + } + } + else + { + // This wasn't a certificate error, so throw up the normal + // notificatioin message. + LLSD args; + args["ERROR_MESSAGE"] = emsg.str(); + LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL; + LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done); + } } - //setup map of datetime strings to codes and slt & local time offset from utc // *TODO: Does this need to be here? LLStringOps::setupDatetimeInfo (false); @@ -1112,7 +1106,12 @@ bool idle_startup() if(process_login_success_response()) { // Pass the user information to the voice chat server interface. - gVoiceClient->userAuthorized(gFirstname, gLastname, gAgentID); + LLVoiceClient::getInstance()->userAuthorized(gUserCredential->userID(), gAgentID); + // create the default proximal channel + LLVoiceChannel::initClass(); + // update the voice settings + LLVoiceClient::getInstance()->updateSettings(); + LLGridManager::getInstance()->setFavorite(); LLStartUp::setStartupState( STATE_WORLD_INIT); } else @@ -1123,6 +1122,7 @@ bool idle_startup() LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done); transition_back_to_login_panel(emsg.str()); show_connect_box = true; + return FALSE; } } return FALSE; @@ -1807,9 +1807,12 @@ bool idle_startup() // thus, do not show this alert. if (!gAgent.isFirstLogin()) { - bool url_ok = LLURLSimString::sInstance.parse(); - if ((url_ok && gAgentStartLocation == "url") || - (!url_ok && ((gAgentStartLocation == gSavedSettings.getString("LoginLocation"))))) + llinfos << "gAgentStartLocation : " << gAgentStartLocation << llendl; + LLSLURL start_slurl = LLStartUp::getStartSLURL(); + + if (((start_slurl.getType() == LLSLURL::LOCATION) && (gAgentStartLocation == "url")) || + ((start_slurl.getType() == LLSLURL::LAST_LOCATION) && (gAgentStartLocation == "last")) || + ((start_slurl.getType() == LLSLURL::HOME_LOCATION) && (gAgentStartLocation == "home"))) { // Start location is OK // Disabled code to restore camera location and focus if logging in to default location @@ -1831,17 +1834,23 @@ bool idle_startup() else { std::string msg; - if (url_ok) - { - msg = "AvatarMovedDesired"; - } - else if (gSavedSettings.getString("LoginLocation") == "home") - { - msg = "AvatarMovedHome"; - } - else + switch(start_slurl.getType()) { - msg = "AvatarMovedLast"; + case LLSLURL::LOCATION: + { + + msg = "AvatarMovedDesired"; + break; + } + case LLSLURL::HOME_LOCATION: + { + msg = "AvatarMovedHome"; + break; + } + default: + { + msg = "AvatarMovedLast"; + } } LLNotificationsUtil::add(msg); } @@ -2057,20 +2066,9 @@ void login_show() #endif LLPanelLogin::show( gViewerWindow->getWindowRectScaled(), - bUseDebugLogin, + bUseDebugLogin || gSavedSettings.getBOOL("SecondLifeEnterprise"), login_callback, NULL ); - // UI textures have been previously loaded in doPreloadImages() - - LL_DEBUGS("AppInit") << "Setting Servers" << LL_ENDL; - - LLPanelLogin::addServer(LLViewerLogin::getInstance()->getGridLabel(), LLViewerLogin::getInstance()->getGridChoice()); - - LLViewerLogin* vl = LLViewerLogin::getInstance(); - for(int grid_index = GRID_INFO_ADITI; grid_index < GRID_INFO_OTHER; ++grid_index) - { - LLPanelLogin::addServer(vl->getKnownGridLabel((EGridInfo)grid_index), grid_index); - } } // Callback for when login screen is closed. Option 0 = connect, option 1 = quit. @@ -2086,9 +2084,6 @@ void login_callback(S32 option, void *userdata) } else if (QUIT_OPTION == option) // *TODO: THIS CODE SEEMS TO BE UNREACHABLE!!!!! login_callback is never called with option equal to QUIT_OPTION { - // Make sure we don't save the password if the user is trying to clear it. - std::string first, last, password; - LLPanelLogin::getFields(&first, &last, &password); if (!gSavedSettings.getBOOL("RememberPassword")) { // turn off the setting and write out to disk @@ -2111,142 +2106,6 @@ void login_callback(S32 option, void *userdata) } } - -// static -std::string LLStartUp::loadPasswordFromDisk() -{ - // Only load password if we also intend to save it (otherwise the user - // wonders what we're doing behind his back). JC - BOOL remember_password = gSavedSettings.getBOOL("RememberPassword"); - if (!remember_password) - { - return std::string(""); - } - - std::string hashed_password(""); - - // Look for legacy "marker" password from settings.ini - hashed_password = gSavedSettings.getString("Marker"); - if (!hashed_password.empty()) - { - // Stomp the Marker entry. - gSavedSettings.setString("Marker", ""); - - // Return that password. - return hashed_password; - } - - std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, - "password.dat"); - LLFILE* fp = LLFile::fopen(filepath, "rb"); /* Flawfinder: ignore */ - if (!fp) - { - return hashed_password; - } - - // UUID is 16 bytes, written into ASCII is 32 characters - // without trailing \0 - const S32 HASHED_LENGTH = 32; - U8 buffer[HASHED_LENGTH+1]; - - if (1 != fread(buffer, HASHED_LENGTH, 1, fp)) - { - return hashed_password; - } - - fclose(fp); - - // Decipher with MAC address - LLXORCipher cipher(gMACAddress, 6); - cipher.decrypt(buffer, HASHED_LENGTH); - - buffer[HASHED_LENGTH] = '\0'; - - // Check to see if the mac address generated a bad hashed - // password. It should be a hex-string or else the mac adress has - // changed. This is a security feature to make sure that if you - // get someone's password.dat file, you cannot hack their account. - if(is_hex_string(buffer, HASHED_LENGTH)) - { - hashed_password.assign((char*)buffer); - } - - return hashed_password; -} - - -// static -void LLStartUp::savePasswordToDisk(const std::string& hashed_password) -{ - std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, - "password.dat"); - LLFILE* fp = LLFile::fopen(filepath, "wb"); /* Flawfinder: ignore */ - if (!fp) - { - return; - } - - // Encipher with MAC address - const S32 HASHED_LENGTH = 32; - U8 buffer[HASHED_LENGTH+1]; - - LLStringUtil::copy((char*)buffer, hashed_password.c_str(), HASHED_LENGTH+1); - - LLXORCipher cipher(gMACAddress, 6); - cipher.encrypt(buffer, HASHED_LENGTH); - - if (fwrite(buffer, HASHED_LENGTH, 1, fp) != 1) - { - LL_WARNS("AppInit") << "Short write" << LL_ENDL; - } - - fclose(fp); -} - - -// static -void LLStartUp::deletePasswordFromDisk() -{ - std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, - "password.dat"); - LLFile::remove(filepath); -} - - -bool is_hex_string(U8* str, S32 len) -{ - bool rv = true; - U8* c = str; - while(rv && len--) - { - switch(*c) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - ++c; - break; - default: - rv = false; - break; - } - } - return rv; -} - void show_first_run_dialog() { LLNotificationsUtil::add("FirstRun", LLSD(), LLSD(), first_run_dialog_callback); @@ -2288,7 +2147,7 @@ bool login_alert_status(const LLSD& notification, const LLSD& response) // break; case 2: // Teleport // Restart the login process, starting at our home locaton - LLURLSimString::setString("home"); + LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME)); LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); break; default: @@ -2508,30 +2367,35 @@ void asset_callback_nothing(LLVFS*, const LLUUID&, LLAssetType::EType, void*, S3 const std::string COMMON_GESTURES_FOLDER = "Common Gestures"; const std::string MALE_GESTURES_FOLDER = "Male Gestures"; const std::string FEMALE_GESTURES_FOLDER = "Female Gestures"; -const std::string MALE_OUTFIT_FOLDER = "Male Shape & Outfit"; -const std::string FEMALE_OUTFIT_FOLDER = "Female Shape & Outfit"; const S32 OPT_CLOSED_WINDOW = -1; const S32 OPT_MALE = 0; const S32 OPT_FEMALE = 1; - +const S32 OPT_TRUST_CERT = 0; +const S32 OPT_CANCEL_TRUST = 1; + bool callback_choose_gender(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); +{ + + // These defaults are returned from the server on login. They are set in login.xml. + // If no default is returned from the server, they are retrieved from settings.xml. + + S32 option = LLNotification::getSelectedOption(notification, response); switch(option) { - case OPT_MALE: - LLStartUp::loadInitialOutfit( MALE_OUTFIT_FOLDER, "male" ); - break; - - case OPT_FEMALE: - case OPT_CLOSED_WINDOW: - default: - LLStartUp::loadInitialOutfit( FEMALE_OUTFIT_FOLDER, "female" ); - break; + case OPT_MALE: + LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultMaleAvatar"), "male" ); + break; + + case OPT_FEMALE: + case OPT_CLOSED_WINDOW: + default: + LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultFemaleAvatar"), "female" ); + break; } return false; } + void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name, const std::string& gender_name ) { @@ -2746,7 +2610,6 @@ void reset_login() //--------------------------------------------------------------------------- -std::string LLStartUp::sSLURLCommand; bool LLStartUp::canGoFullscreen() { @@ -2779,41 +2642,145 @@ void LLStartUp::fontInit() bool LLStartUp::dispatchURL() { // ok, if we've gotten this far and have a startup URL - if (!sSLURLCommand.empty()) + if (!getStartSLURL().isValid()) { - LLMediaCtrl* web = NULL; - const bool trusted_browser = false; - LLURLDispatcher::dispatch(sSLURLCommand, web, trusted_browser); + return false; } - else if (LLURLSimString::parse()) - { + if(getStartSLURL().getType() != LLSLURL::APP) + { + // If we started with a location, but we're already // at that location, don't pop dialogs open. LLVector3 pos = gAgent.getPositionAgent(); - F32 dx = pos.mV[VX] - (F32)LLURLSimString::sInstance.mX; - F32 dy = pos.mV[VY] - (F32)LLURLSimString::sInstance.mY; + LLVector3 slurlpos = getStartSLURL().getPosition(); + F32 dx = pos.mV[VX] - slurlpos.mV[VX]; + F32 dy = pos.mV[VY] - slurlpos.mV[VY]; const F32 SLOP = 2.f; // meters - if( LLURLSimString::sInstance.mSimName != gAgent.getRegion()->getName() + if( getStartSLURL().getRegion() != gAgent.getRegion()->getName() || (dx*dx > SLOP*SLOP) || (dy*dy > SLOP*SLOP) ) { - std::string url = LLURLSimString::getURL(); - LLMediaCtrl* web = NULL; - const bool trusted_browser = false; - LLURLDispatcher::dispatch(url, web, trusted_browser); + LLURLDispatcher::dispatch(getStartSLURL().getSLURLString(), + NULL, false); } return true; } return false; } +void LLStartUp::setStartSLURL(const LLSLURL& slurl) +{ + sStartSLURL = slurl; + switch(slurl.getType()) + { + case LLSLURL::HOME_LOCATION: + { + gSavedSettings.setString("LoginLocation", LLSLURL::SIM_LOCATION_HOME); + break; + } + case LLSLURL::LAST_LOCATION: + { + gSavedSettings.setString("LoginLocation", LLSLURL::SIM_LOCATION_LAST); + break; + } + default: + LLGridManager::getInstance()->setGridChoice(slurl.getGrid()); + break; + } +} + bool login_alert_done(const LLSD& notification, const LLSD& response) { LLPanelLogin::giveFocus(); return false; } +// parse the certificate information into args for the +// certificate notifications +LLSD transform_cert_args(LLPointer cert) +{ + LLSD args = LLSD::emptyMap(); + std::string value; + LLSD cert_info = cert->getLLSD(); + // convert all of the elements in the cert into + // args for the xml dialog, so we have flexability to + // display various parts of the cert by only modifying + // the cert alert dialog xml. + for(LLSD::map_iterator iter = cert_info.beginMap(); + iter != cert_info.endMap(); + iter++) + { + // key usage and extended key usage + // are actually arrays, and we want to format them as comma separated + // strings, so special case those. + LLSDSerialize::toXML(cert_info[iter->first], std::cout); + if((iter->first== std::string(CERT_KEY_USAGE)) | + (iter->first == std::string(CERT_EXTENDED_KEY_USAGE))) + { + value = ""; + LLSD usage = cert_info[iter->first]; + for (LLSD::array_iterator usage_iter = usage.beginArray(); + usage_iter != usage.endArray(); + usage_iter++) + { + + if(usage_iter != usage.beginArray()) + { + value += ", "; + } + + value += (*usage_iter).asString(); + } + + } + else + { + value = iter->second.asString(); + } + + std::string name = iter->first; + std::transform(name.begin(), name.end(), name.begin(), + (int(*)(int))toupper); + args[name.c_str()] = value; + } + return args; +} + + +// when we handle a cert error, give focus back to the login panel +void general_cert_done(const LLSD& notification, const LLSD& response) +{ + LLStartUp::setStartupState( STATE_LOGIN_SHOW ); + LLPanelLogin::giveFocus(); +} + +// check to see if the user wants to trust the cert. +// if they do, add it to the cert store and +void trust_cert_done(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + switch(option) + { + case OPT_TRUST_CERT: + { + LLPointer cert = gSecAPIHandler->getCertificate(notification["payload"]["certificate"]); + LLPointer store = gSecAPIHandler->getCertificateStore(gSavedSettings.getString("CertStore")); + store->add(cert); + store->save(); + LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); + break; + } + case OPT_CANCEL_TRUST: + reset_login(); + gSavedSettings.setBOOL("AutoLogin", FALSE); + LLStartUp::setStartupState( STATE_LOGIN_SHOW ); + default: + LLPanelLogin::giveFocus(); + break; + } + +} void apply_udp_blacklist(const std::string& csv) { @@ -2861,33 +2828,45 @@ bool process_login_success_response() text = response["secure_session_id"].asString(); if(!text.empty()) gAgent.mSecureSessionID.set(text); - text = response["first_name"].asString(); - if(!text.empty()) - { - // Remove quotes from string. Login.cgi sends these to force - // names that look like numbers into strings. - gFirstname.assign(text); - LLStringUtil::replaceChar(gFirstname, '"', ' '); - LLStringUtil::trim(gFirstname); - } - text = response["last_name"].asString(); - if(!text.empty()) + // if the response contains a display name, use that, + // otherwise if the response contains a first and/or last name, + // use those. Otherwise use the credential identifier + + gDisplayName = ""; + if (response.has("display_name")) { - gLastname.assign(text); + gDisplayName.assign(response["display_name"].asString()); + if(!gDisplayName.empty()) + { + // Remove quotes from string. Login.cgi sends these to force + // names that look like numbers into strings. + LLStringUtil::replaceChar(gDisplayName, '"', ' '); + LLStringUtil::trim(gDisplayName); + } } - gSavedSettings.setString("FirstName", gFirstname); - gSavedSettings.setString("LastName", gLastname); - - if (gSavedSettings.getBOOL("RememberPassword")) + if(gDisplayName.empty()) { - // Successful login means the password is valid, so save it. - LLStartUp::savePasswordToDisk(gPassword); + if(response.has("first_name")) + { + gDisplayName.assign(response["first_name"].asString()); + LLStringUtil::replaceChar(gDisplayName, '"', ' '); + LLStringUtil::trim(gDisplayName); + } + if(response.has("last_name")) + { + text.assign(response["last_name"].asString()); + LLStringUtil::replaceChar(text, '"', ' '); + LLStringUtil::trim(text); + if(!gDisplayName.empty()) + { + gDisplayName += " "; + } + gDisplayName += text; + } } - else + if(gDisplayName.empty()) { - // Don't leave password from previous session sitting around - // during this login session. - LLStartUp::deletePasswordFromDisk(); + gDisplayName.assign(gUserCredential->asString()); } // this is their actual ability to access content @@ -2981,7 +2960,7 @@ bool process_login_success_response() // replace the default help URL format gSavedSettings.setString("HelpURLFormat",text); - // don't fall back to Nebraska's pre-connection static help + // don't fall back to Standalone's pre-connection static help gSavedSettings.setBOOL("HelpUseLocal", false); } @@ -3043,7 +3022,44 @@ bool process_login_success_response() //setup map of datetime strings to codes and slt & local time offset from utc LLStringOps::setupDatetimeInfo(pacific_daylight_time); } - + + static const char* CONFIG_OPTIONS[] = {"voice-config", "newuser-config"}; + for (int i = 0; i < sizeof(CONFIG_OPTIONS)/sizeof(CONFIG_OPTIONS[0]); i++) + { + LLSD options = response[CONFIG_OPTIONS[i]]; + if (!options.isArray() && (options.size() < 1) && !options[0].isMap()) + { + continue; + } + llinfos << "config option " << CONFIG_OPTIONS[i][0] << "response " << options << llendl; + for(LLSD::map_iterator option_it = options[0].beginMap(); + option_it != options[0].endMap(); + option_it++) + { + llinfos << "trying option " << option_it->first << llendl; + LLPointer control = gSavedSettings.getControl(option_it->first); + if(control.notNull()) + { + if(control->isType(TYPE_BOOLEAN)) + { + llinfos << "Setting BOOL from login " << option_it->first << " " << option_it->second << llendl; + + gSavedSettings.setBOOL(option_it->first, !((option_it->second == "F") || + (option_it->second == "false") || + (!option_it->second))); + } + else if (control->isType(TYPE_STRING)) + { + llinfos << "Setting String from login " << option_it->first << " " << option_it->second << llendl; + gSavedSettings.setString(option_it->first, option_it->second); + } + // we don't support other types now + + } + + } + } + LLSD initial_outfit = response["initial-outfit"][0]; if(initial_outfit.size()) { @@ -3097,7 +3113,7 @@ bool process_login_success_response() bool success = false; // JC: gesture loading done below, when we have an asset system - // in place. Don't delete/clear user_credentials until then. + // in place. Don't delete/clear gUserCredentials until then. if(gAgentID.notNull() && gAgentSessionID.notNull() && gMessageSystem->mOurCircuitCode -- cgit v1.3 From 5e727964dbd6d5e55dd3a0921e8e1f0f77a99747 Mon Sep 17 00:00:00 2001 From: Roxie Linden Date: Thu, 22 Apr 2010 15:09:34 -0700 Subject: DEV-49332 - cryptic error message when typing in single username when logging into maingrid. Needs to be changed when IE is checked in, of course. Now we check the expected credential formats for a given grid against the format that is typed in, and throw an error if it's invalid. --- indra/newview/llpanellogin.cpp | 42 ++++++++++++++--- indra/newview/llpanellogin.h | 2 +- indra/newview/llsecapi.cpp | 52 +++++++++++++++++----- indra/newview/llsecapi.h | 6 +++ indra/newview/llstartup.cpp | 2 +- indra/newview/llviewernetwork.cpp | 18 ++++++-- indra/newview/llviewernetwork.h | 6 +-- .../newview/skins/default/xui/en/notifications.xml | 8 ++++ indra/newview/tests/lllogininstance_test.cpp | 7 +++ indra/newview/tests/llviewernetwork_test.cpp | 10 ++--- 10 files changed, 122 insertions(+), 31 deletions(-) (limited to 'indra/newview/llstartup.cpp') diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 22fb70de73..63fe7bfa91 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -571,7 +571,7 @@ void LLPanelLogin::setFields(LLPointer credential, // static void LLPanelLogin::getFields(LLPointer& credential, - BOOL remember) + BOOL& remember) { if (!sInstance) { @@ -603,14 +603,14 @@ void LLPanelLogin::getFields(LLPointer& credential, { LL_INFOS2("Credentials", "Authentication") << "account: " << username << LL_ENDL; // single username, so this is a 'clear' identifier - identifier["type"] = "account"; + identifier["type"] = CRED_IDENTIFIER_TYPE_ACCOUNT; identifier["account_name"] = username; if (LLPanelLogin::sInstance->mPasswordModified) { authenticator = LLSD::emptyMap(); // password is plaintext - authenticator["type"] = "clear"; + authenticator["type"] = CRED_AUTHENTICATOR_TYPE_CLEAR; authenticator["secret"] = password; } } @@ -618,14 +618,14 @@ void LLPanelLogin::getFields(LLPointer& credential, { LL_INFOS2("Credentials", "Authentication") << "agent: " << username << LL_ENDL; // traditional firstname / lastname - identifier["type"] = "agent"; + identifier["type"] = CRED_IDENTIFIER_TYPE_AGENT; identifier["first_name"] = username.substr(0, separator_index); identifier["last_name"] = username.substr(separator_index+1, username.npos); if (LLPanelLogin::sInstance->mPasswordModified) { authenticator = LLSD::emptyMap(); - authenticator["type"] = "hash"; + authenticator["type"] = CRED_AUTHENTICATOR_TYPE_HASH; authenticator["algorithm"] = "md5"; LLMD5 pass((const U8 *)password.c_str()); char md5pass[33]; /* Flawfinder: ignore */ @@ -978,14 +978,42 @@ void LLPanelLogin::onClickConnect(void *) } updateStartSLURL(); std::string username = sInstance->childGetText("username_edit"); + + if(username.empty()) { + // user must type in something into the username field LLNotificationsUtil::add("MustHaveAccountToLogIn"); } else { - // has both first and last name typed - sInstance->mCallback(0, sInstance->mCallbackData); + LLPointer cred; + BOOL remember; + getFields(cred, remember); + std::string identifier_type; + cred->identifierType(identifier_type); + LLSD allowed_credential_types; + LLGridManager::getInstance()->getLoginIdentifierTypes(allowed_credential_types); + + // check the typed in credential type against the credential types expected by the server. + for(LLSD::array_iterator i = allowed_credential_types.beginArray(); + i != allowed_credential_types.endArray(); + i++) + { + + if(i->asString() == identifier_type) + { + // yay correct credential type + sInstance->mCallback(0, sInstance->mCallbackData); + return; + } + } + + // Right now, maingrid is the only thing that is picky about + // credential format, as it doesn't yet allow account (single username) + // format creds. - Rox. James, we wanna fix the message when we change + // this. + LLNotificationsUtil::add("InvalidCredentialFormat"); } } } diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index bca051691b..aa6884ea97 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -69,7 +69,7 @@ public: static void setFields(LLPointer credential, BOOL remember); - static void getFields(LLPointer& credential, BOOL remember); + static void getFields(LLPointer& credential, BOOL& remember); static BOOL isGridComboDirty(); static BOOL areCredentialFieldsDirty(); diff --git a/indra/newview/llsecapi.cpp b/indra/newview/llsecapi.cpp index ba343f5387..b3e96298d2 100644 --- a/indra/newview/llsecapi.cpp +++ b/indra/newview/llsecapi.cpp @@ -143,19 +143,51 @@ int secapiSSLCertVerifyCallback(X509_STORE_CTX *ctx, void *param) LLSD LLCredential::getLoginParams() { LLSD result = LLSD::emptyMap(); - if (mIdentifier["type"].asString() == "agent") + try { - // legacy credential - result["passwd"] = "$1$" + mAuthenticator["secret"].asString(); - result["first"] = mIdentifier["first_name"]; - result["last"] = mIdentifier["last_name"]; - + if (mIdentifier["type"].asString() == "agent") + { + // legacy credential + result["passwd"] = "$1$" + mAuthenticator["secret"].asString(); + result["first"] = mIdentifier["first_name"]; + result["last"] = mIdentifier["last_name"]; + + } + else if (mIdentifier["type"].asString() == "account") + { + result["username"] = mIdentifier["account_name"]; + result["passwd"] = mAuthenticator["secret"]; + + } } - else if (mIdentifier["type"].asString() == "account") + catch (...) { - result["username"] = mIdentifier["account_name"]; - result["passwd"] = mAuthenticator["secret"]; - + // we could have corrupt data, so simply return a null login param if so + LL_WARNS("AppInit") << "Invalid credential" << LL_ENDL; } return result; } + +void LLCredential::identifierType(std::string &idType) +{ + if(mIdentifier.has("type")) + { + idType = mIdentifier["type"].asString(); + } + else { + idType = std::string(); + + } +} + +void LLCredential::authenticatorType(std::string &idType) +{ + if(mAuthenticator.has("type")) + { + idType = mAuthenticator["type"].asString(); + } + else { + idType = std::string(); + + } +} \ No newline at end of file diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h index 5211dc2699..59a1e1eff0 100644 --- a/indra/newview/llsecapi.h +++ b/indra/newview/llsecapi.h @@ -286,6 +286,10 @@ bool operator!=(const LLCertificateVector::iterator& _lhs, const LLCertificateVe } +#define CRED_IDENTIFIER_TYPE_ACCOUNT "account" +#define CRED_IDENTIFIER_TYPE_AGENT "agent" +#define CRED_AUTHENTICATOR_TYPE_CLEAR "clear" +#define CRED_AUTHENTICATOR_TYPE_HASH "hash" // // LLCredential - interface for credentials providing the following functionality: // * persistance of credential information based on grid (for saving username/password) @@ -312,7 +316,9 @@ public: mAuthenticator = authenticator; } virtual LLSD getIdentifier() { return mIdentifier; } + virtual void identifierType(std::string& idType); virtual LLSD getAuthenticator() { return mAuthenticator; } + virtual void authenticatorType(std::string& authType); virtual LLSD getLoginParams(); virtual std::string getGrid() { return mGrid; } diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index eee92ac413..8e2097762a 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -799,7 +799,7 @@ bool idle_startup() gViewerWindow->moveProgressViewToFront(); //reset the values that could have come in from a slurl - // DEV-42215: Make sure they're not empty -- gFirstname and gLastname + // DEV-42215: Make sure they're not empty -- gUserCredential // might already have been set from gSavedSettings, and it's too bad // to overwrite valid values with empty strings. diff --git a/indra/newview/llviewernetwork.cpp b/indra/newview/llviewernetwork.cpp index 2673ba4e17..a160572f7a 100644 --- a/indra/newview/llviewernetwork.cpp +++ b/indra/newview/llviewernetwork.cpp @@ -35,6 +35,7 @@ #include "llviewernetwork.h" #include "llviewercontrol.h" #include "llsdserialize.h" +#include "llsecapi.h" #include "llweb.h" @@ -92,7 +93,7 @@ void LLGridManager::initialize(const std::string& grid_file) - addSystemGrid("Secondlife.com (Agni)", + addSystemGrid("Agni", MAINGRID, "https://login.agni.lindenlab.com/cgi-bin/login.cgi", "https://secondlife.com/helpers/", @@ -361,7 +362,17 @@ void LLGridManager::addGrid(LLSD& grid_data) if (!grid_data.has(GRID_HELPER_URI_VALUE)) { grid_data[GRID_HELPER_URI_VALUE] = std::string("https://") + grid + "/helpers/"; - } + } + + if (!grid_data.has(GRID_LOGIN_IDENTIFIER_TYPES)) + { + // non system grids and grids that haven't already been configured with values + // get both types of credentials. + grid_data[GRID_LOGIN_IDENTIFIER_TYPES] = LLSD::emptyArray(); + grid_data[GRID_LOGIN_IDENTIFIER_TYPES].append(CRED_IDENTIFIER_TYPE_AGENT); + grid_data[GRID_LOGIN_IDENTIFIER_TYPES].append(CRED_IDENTIFIER_TYPE_ACCOUNT); + } + LL_INFOS("GridManager") << "ADDING: " << grid << LL_ENDL; mGridList[grid] = grid_data; } @@ -384,7 +395,8 @@ void LLGridManager::addSystemGrid(const std::string& label, grid[GRID_LOGIN_URI_VALUE].append(login); grid[GRID_LOGIN_PAGE_VALUE] = login_page; grid[GRID_IS_SYSTEM_GRID_VALUE] = TRUE; - grid[GRID_LOGIN_CREDENTIAL_PAGE_TYPE_VALUE] = GRID_LOGIN_CREDENTIAL_PAGE_TYPE_AGENT; + grid[GRID_LOGIN_IDENTIFIER_TYPES] = LLSD::emptyArray(); + grid[GRID_LOGIN_IDENTIFIER_TYPES].append(CRED_IDENTIFIER_TYPE_AGENT); grid[GRID_APP_SLURL_BASE] = SYSTEM_GRID_APP_SLURL_BASE; if (login_id.empty()) diff --git a/indra/newview/llviewernetwork.h b/indra/newview/llviewernetwork.h index 46f21bf20f..0271e7a7a5 100644 --- a/indra/newview/llviewernetwork.h +++ b/indra/newview/llviewernetwork.h @@ -43,11 +43,8 @@ extern const char* DEFAULT_LOGIN_PAGE; #define GRID_LOGIN_PAGE_VALUE "login_page" #define GRID_IS_SYSTEM_GRID_VALUE "system_grid" #define GRID_IS_FAVORITE_VALUE "favorite" -#define GRID_LOGIN_CREDENTIAL_PAGE_TYPE_VALUE "credential_type" -#define GRID_LOGIN_CREDENTIAL_PAGE_TYPE_AGENT "agent" -#define GRID_LOGIN_CREDENTIAL_PAGE_TYPE_ACCOUNT "account" #define MAINGRID "util.agni.lindenlab.com" - +#define GRID_LOGIN_IDENTIFIER_TYPES "login_identifier_types" // defines slurl formats associated with various grids. // we need to continue to support existing forms, as slurls // are shared between viewers that may not understand newer @@ -119,6 +116,7 @@ public: std::string getLoginPage() {return mGridList[mGrid][GRID_LOGIN_PAGE_VALUE];} std::string getGridLoginID() { return mGridList[mGrid][GRID_ID_VALUE]; } std::string getLoginPage(const std::string& grid) { return mGridList[grid][GRID_LOGIN_PAGE_VALUE]; } + void getLoginIdentifierTypes(LLSD& idTypes) { idTypes = mGridList[mGrid][GRID_LOGIN_IDENTIFIER_TYPES]; } // build a slurl for the given region within the selected grid std::string getSLURLBase(const std::string& grid); diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index e06f36c823..a0a1113b4d 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -733,6 +733,14 @@ You need an account to enter [SECOND_LIFE]. Would you like to create one now? yestext="Create a new account"/> + +You need to enter both the First and Last name of your avatar into the Username field, then login again. + + + known_grids = manager->getKnownGrids(); ensure_equals("Known grids is a string-string map of size 18", known_grids.size(), 18); ensure_equals("Agni has the right name and label", - known_grids[std::string("util.agni.lindenlab.com")], std::string("Secondlife.com (Agni)")); + known_grids[std::string("util.agni.lindenlab.com")], std::string("Agni")); ensure_equals("None exists", known_grids[""], "None"); LLSD grid = LLGridManager::getInstance()->getGridInfo("util.agni.lindenlab.com"); @@ -153,7 +153,7 @@ namespace tut ensure_equals("name is correct for agni", grid[GRID_VALUE].asString(), std::string("util.agni.lindenlab.com")); ensure_equals("label is correct for agni", - grid[GRID_LABEL_VALUE].asString(), std::string("Secondlife.com (Agni)")); + grid[GRID_LABEL_VALUE].asString(), std::string("Agni")); ensure("Login URI is an array", grid[GRID_LOGIN_URI_VALUE].isArray()); ensure_equals("Agni login uri is correct", @@ -186,14 +186,14 @@ namespace tut ensure_equals("adding a grid via a grid file increases known grid size", known_grids.size(), 19); ensure_equals("Agni is still there after we've added a grid via a grid file", - known_grids["util.agni.lindenlab.com"], std::string("Secondlife.com (Agni)")); + known_grids["util.agni.lindenlab.com"], std::string("Agni")); // assure Agni doesn't get overwritten LLSD grid = LLGridManager::getInstance()->getGridInfo("util.agni.lindenlab.com"); ensure_equals("Agni grid label was not modified by grid file", - grid[GRID_LABEL_VALUE].asString(), std::string("Secondlife.com (Agni)")); + grid[GRID_LABEL_VALUE].asString(), std::string("Agni")); ensure_equals("Agni name wasn't modified by grid file", grid[GRID_VALUE].asString(), std::string("util.agni.lindenlab.com")); @@ -320,7 +320,7 @@ namespace tut LLGridManager::getInstance()->initialize("grid_test.xml"); LLGridManager::getInstance()->addGrid(grid); LLGridManager::getInstance()->setGridChoice("util.agni.lindenlab.com"); - ensure_equals("getGridLabel", LLGridManager::getInstance()->getGridLabel(), std::string("Secondlife.com (Agni)")); + ensure_equals("getGridLabel", LLGridManager::getInstance()->getGridLabel(), std::string("Agni")); ensure_equals("getGrid", LLGridManager::getInstance()->getGrid(), std::string("util.agni.lindenlab.com")); ensure_equals("getHelperURI", LLGridManager::getInstance()->getHelperURI(), -- cgit v1.3 From e1b3919a4fec68f57be6d6de2839dc31b654609f Mon Sep 17 00:00:00 2001 From: Roxie Linden Date: Fri, 23 Apr 2010 12:15:22 -0700 Subject: DEV-49362 - SLE: Generic passing of settings up from the server allows attacker to overwrite saved settings when user logs into some other non secondlife grid. We now do it the old-skool way, simply checking if the specific values exist --- indra/newview/llstartup.cpp | 55 +++++++++++++++++---------------------------- 1 file changed, 21 insertions(+), 34 deletions(-) (limited to 'indra/newview/llstartup.cpp') diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 8e2097762a..8157e7fe8b 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -3022,44 +3022,31 @@ bool process_login_success_response() //setup map of datetime strings to codes and slt & local time offset from utc LLStringOps::setupDatetimeInfo(pacific_daylight_time); } + + // set up the voice configuration. Ultimately, we should pass this up as part of each voice + // channel if we need to move to multiple voice servers per grid. + LLSD voice_config_info = response["voice-config"]; + if(voice_config_info.has("VoiceServerType")) + { + gSavedSettings.setString("VoiceServerType", voice_config_info["VoiceServerType"].asString()); + } - static const char* CONFIG_OPTIONS[] = {"voice-config", "newuser-config"}; - for (int i = 0; i < sizeof(CONFIG_OPTIONS)/sizeof(CONFIG_OPTIONS[0]); i++) + // Default male and female avatars allowing the user to choose their avatar on first login. + // These may be passed up by SLE to allow choice of enterprise avatars instead of the standard + // "new ruth." Not to be confused with 'initial-outfit' below + LLSD newuser_config = response["newuser-config"]; + if(newuser_config.has("DefaultFemaleAvatar")) { - LLSD options = response[CONFIG_OPTIONS[i]]; - if (!options.isArray() && (options.size() < 1) && !options[0].isMap()) - { - continue; - } - llinfos << "config option " << CONFIG_OPTIONS[i][0] << "response " << options << llendl; - for(LLSD::map_iterator option_it = options[0].beginMap(); - option_it != options[0].endMap(); - option_it++) - { - llinfos << "trying option " << option_it->first << llendl; - LLPointer control = gSavedSettings.getControl(option_it->first); - if(control.notNull()) - { - if(control->isType(TYPE_BOOLEAN)) - { - llinfos << "Setting BOOL from login " << option_it->first << " " << option_it->second << llendl; - - gSavedSettings.setBOOL(option_it->first, !((option_it->second == "F") || - (option_it->second == "false") || - (!option_it->second))); - } - else if (control->isType(TYPE_STRING)) - { - llinfos << "Setting String from login " << option_it->first << " " << option_it->second << llendl; - gSavedSettings.setString(option_it->first, option_it->second); - } - // we don't support other types now - - } - - } + gSavedSettings.setString("DefaultFemaleAvatar", newuser_config["DefaultFemaleAvatar"].asString()); + } + if(newuser_config.has("DefaultMaleAvatar")) + { + gSavedSettings.setString("DefaultMaleAvatar", newuser_config["DefaultMaleAvatar"].asString()); } + // Initial outfit for the user. + // QUESTION: Why can't we simply simply set the users outfit directly + // from a web page into the user info on the server? - Roxie LLSD initial_outfit = response["initial-outfit"][0]; if(initial_outfit.size()) { -- cgit v1.3 From 2a2930d24559c4d33470099807ade5f29d460210 Mon Sep 17 00:00:00 2001 From: Roxie Linden Date: Tue, 4 May 2010 10:37:32 -0700 Subject: DEV-45807 - worldmap doesn't work against non maingrid servers The code used to retrieve the tiles for the world map was hardcoded to retrieve the map tiles via s3. However, non-maingrid servers do not necessarily publish their map tiles to s3. The URL was in the form http://map.secondlife.com.s3.amazonaws.com/map----objects.jpg This change removes the hard coding and places the default s3 URL in the settings.xml file via MapServerURL. Login retrieves the specific grids URL via a map-server-url option. The url is still expected to contain jpegs named like map----objects.jpg CR: Karina Linden --- indra/newview/app_settings/settings.xml | 11 +++++++++++ indra/newview/lllogininstance.cpp | 1 + indra/newview/llstartup.cpp | 7 +++++++ indra/newview/llworldmipmap.cpp | 5 +++-- 4 files changed, 22 insertions(+), 2 deletions(-) (limited to 'indra/newview/llstartup.cpp') diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 75ace99806..02530485de 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -4470,6 +4470,17 @@ Value 128.0 + MapServerURL + + Comment + World map URL template for locating map tiles + Persist + 0 + Type + String + Value + http://map.secondlife.com.s3.amazonaws.com/ + MapShowEvents Comment diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index 848cc8ec93..71604291e1 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -151,6 +151,7 @@ void LLLoginInstance::constructAuthParams(LLPointer user_credentia requested_options.append("newuser-config"); requested_options.append("ui-config"); #endif + requested_options.append("map-server-url"); requested_options.append("voice-config"); requested_options.append("tutorial_setting"); requested_options.append("login-flags"); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 8157e7fe8b..a84bb98a90 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -3030,6 +3030,13 @@ bool process_login_success_response() { gSavedSettings.setString("VoiceServerType", voice_config_info["VoiceServerType"].asString()); } + + // Request the map server url + std::string map_server_url = response["map-server-url"]; + if(!map_server_url.empty()) + { + gSavedSettings.setString("MapServerURL", map_server_url); + } // Default male and female avatars allowing the user to choose their avatar on first login. // These may be passed up by SLE to allow choice of enterprise avatars instead of the standard diff --git a/indra/newview/llworldmipmap.cpp b/indra/newview/llworldmipmap.cpp index 1cdccd2baa..debd6b611f 100644 --- a/indra/newview/llworldmipmap.cpp +++ b/indra/newview/llworldmipmap.cpp @@ -33,6 +33,7 @@ #include "llviewerprecompiledheaders.h" #include "llworldmipmap.h" +#include "llviewercontrol.h" // LLControlGroup #include "llviewertexturelist.h" #include "math.h" // log() @@ -186,8 +187,8 @@ LLPointer LLWorldMipmap::getObjectsTile(U32 grid_x, U32 LLPointer LLWorldMipmap::loadObjectsTile(U32 grid_x, U32 grid_y, S32 level) { // Get the grid coordinates - std::string imageurl = llformat("http://map.secondlife.com.s3.amazonaws.com/map-%d-%d-%d-objects.jpg", - level, grid_x, grid_y); + std::string imageurl = gSavedSettings.getString("MapServerURL") + llformat("map-%d-%d-%d-objects.jpg", level, grid_x, grid_y); + // DO NOT COMMIT!! DEBUG ONLY!!! // Use a local jpeg for every tile to test map speed without S3 access -- cgit v1.3 From 1f02c1dd32cb5ebb2eb6e9186d1f62710ceb09cf Mon Sep 17 00:00:00 2001 From: Roxie Linden Date: Wed, 19 May 2010 01:15:15 -0700 Subject: DEV-50239 - windows 2.0 viewer using 'ruth' as default avatar on SLE grids The problem, llstartup was parsing the login response indicating the newuser-config (which contains the default avs) incorrectly. The response is returned as a map within an array (...) We were parsing it as a simple map. --- indra/newview/llstartup.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llstartup.cpp') diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index a84bb98a90..0a464b3b6c 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -3041,7 +3041,7 @@ bool process_login_success_response() // Default male and female avatars allowing the user to choose their avatar on first login. // These may be passed up by SLE to allow choice of enterprise avatars instead of the standard // "new ruth." Not to be confused with 'initial-outfit' below - LLSD newuser_config = response["newuser-config"]; + LLSD newuser_config = response["newuser-config"][0]; if(newuser_config.has("DefaultFemaleAvatar")) { gSavedSettings.setString("DefaultFemaleAvatar", newuser_config["DefaultFemaleAvatar"].asString()); -- cgit v1.3 From e3753ed8b2c52e98e282e82ea5169bda0b34a2a6 Mon Sep 17 00:00:00 2001 From: "Karl Stiefvater (qarl)" Date: Fri, 21 May 2010 16:11:21 -0500 Subject: S3 feature/gpu table implementation. reviewed by palmer and davep. --- indra/newview/app_settings/settings.xml | 11 +++ indra/newview/llfeaturemanager.cpp | 144 ++++++++++++++++++++++++++++---- indra/newview/llfeaturemanager.h | 6 ++ indra/newview/llstartup.cpp | 9 ++ indra/newview/llviewerwindow.cpp | 1 + 5 files changed, 156 insertions(+), 15 deletions(-) (limited to 'indra/newview/llstartup.cpp') diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 418032c554..a79e07bdb6 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -4150,6 +4150,17 @@ Value 1 + LastGPUClass + + Comment + [DO NOT MODIFY] previous GPU class for tracking hardware changes + Persist + 1 + Type + S32 + Value + -1 + LastFeatureVersion Comment diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index 50b08f782a..4fdb010162 100644 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -45,10 +45,13 @@ #include "llsecondlifeurls.h" #include "llappviewer.h" +#include "llhttpclient.h" +#include "llnotificationsutil.h" #include "llviewercontrol.h" #include "llworld.h" #include "lldrawpoolterrain.h" #include "llviewertexturelist.h" +#include "llversioninfo.h" #include "llwindow.h" #include "llui.h" #include "llcontrol.h" @@ -62,15 +65,20 @@ #if LL_DARWIN const char FEATURE_TABLE_FILENAME[] = "featuretable_mac.txt"; +const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_mac.%s.txt"; #elif LL_LINUX const char FEATURE_TABLE_FILENAME[] = "featuretable_linux.txt"; +const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_linux.%s.txt"; #elif LL_SOLARIS const char FEATURE_TABLE_FILENAME[] = "featuretable_solaris.txt"; +const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_solaris.%s.txt"; #else const char FEATURE_TABLE_FILENAME[] = "featuretable.txt"; +const char FEATURE_TABLE_VER_FILENAME[] = "featuretable.%s.txt"; #endif const char GPU_TABLE_FILENAME[] = "gpu_table.txt"; +const char GPU_TABLE_VER_FILENAME[] = "gpu_table.%s.txt"; LLFeatureInfo::LLFeatureInfo(const std::string& name, const BOOL available, const F32 level) : mValid(TRUE), mName(name), mAvailable(available), mRecommendedLevel(level) @@ -215,22 +223,44 @@ BOOL LLFeatureManager::loadFeatureTables() mSkippedFeatures.insert("RenderVBOEnable"); mSkippedFeatures.insert("RenderFogRatio"); - std::string data_path = gDirUtilp->getAppRODataDir(); + // first table is install with app + std::string app_path = gDirUtilp->getAppRODataDir(); + app_path += gDirUtilp->getDirDelimiter(); + app_path += FEATURE_TABLE_FILENAME; - data_path += gDirUtilp->getDirDelimiter(); + // second table is downloaded with HTTP + std::string http_filename = llformat(FEATURE_TABLE_VER_FILENAME, LLVersionInfo::getVersion().c_str()); + std::string http_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, http_filename); - data_path += FEATURE_TABLE_FILENAME; - lldebugs << "Looking for feature table in " << data_path << llendl; + // use HTTP table if it exists + std::string path; + if (gDirUtilp->fileExists(http_path)) + { + path = http_path; + } + else + { + path = app_path; + } + + + return parseFeatureTable(path); +} + + +BOOL LLFeatureManager::parseFeatureTable(std::string filename) +{ + llinfos << "Looking for feature table in " << filename << llendl; llifstream file; std::string name; U32 version; - file.open(data_path); /*Flawfinder: ignore*/ + file.open(filename); /*Flawfinder: ignore*/ if (!file) { - LL_WARNS("RenderInit") << "Unable to open feature table!" << LL_ENDL; + LL_WARNS("RenderInit") << "Unable to open feature table " << filename << LL_ENDL; return FALSE; } @@ -239,7 +269,7 @@ BOOL LLFeatureManager::loadFeatureTables() file >> version; if (name != "version") { - LL_WARNS("RenderInit") << data_path << " does not appear to be a valid feature table!" << LL_ENDL; + LL_WARNS("RenderInit") << filename << " does not appear to be a valid feature table!" << LL_ENDL; return FALSE; } @@ -302,24 +332,44 @@ BOOL LLFeatureManager::loadFeatureTables() void LLFeatureManager::loadGPUClass() { - std::string data_path = gDirUtilp->getAppRODataDir(); - - data_path += gDirUtilp->getDirDelimiter(); - - data_path += GPU_TABLE_FILENAME; - // defaults mGPUClass = GPU_CLASS_UNKNOWN; mGPUString = gGLManager.getRawGLString(); mGPUSupported = FALSE; + // first table is in the app dir + std::string app_path = gDirUtilp->getAppRODataDir(); + app_path += gDirUtilp->getDirDelimiter(); + app_path += GPU_TABLE_FILENAME; + + // second table is downloaded with HTTP + std::string http_filename = llformat(GPU_TABLE_VER_FILENAME, LLVersionInfo::getVersion().c_str()); + std::string http_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, http_filename); + + // use HTTP table if it exists + std::string path; + if (gDirUtilp->fileExists(http_path)) + { + path = http_path; + } + else + { + path = app_path; + } + + parseGPUTable(path); +} + + +void LLFeatureManager::parseGPUTable(std::string filename) +{ llifstream file; - file.open(data_path); /*Flawfinder: ignore*/ + file.open(filename); if (!file) { - LL_WARNS("RenderInit") << "Unable to open GPU table: " << data_path << "!" << LL_ENDL; + LL_WARNS("RenderInit") << "Unable to open GPU table: " << filename << "!" << LL_ENDL; return; } @@ -403,6 +453,70 @@ void LLFeatureManager::loadGPUClass() LL_WARNS("RenderInit") << "Couldn't match GPU to a class: " << gGLManager.getRawGLString() << LL_ENDL; } +// responder saves table into file +class LLHTTPFeatureTableResponder : public LLHTTPClient::Responder +{ +public: + + LLHTTPFeatureTableResponder(std::string filename) : + mFilename(filename) + { + } + + + virtual void completedRaw(U32 status, const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) + { + if (isGoodStatus(status)) + { + // write to file + + llinfos << "writing feature table to " << mFilename << llendl; + + S32 file_size = buffer->countAfter(channels.in(), NULL); + if (file_size > 0) + { + // read from buffer + U8* copy_buffer = new U8[file_size]; + buffer->readAfter(channels.in(), NULL, copy_buffer, file_size); + + // write to file + LLAPRFile out(mFilename, LL_APR_WB); + out.write(copy_buffer, file_size); + out.close(); + } + } + + } + +private: + std::string mFilename; +}; + +void fetch_table(std::string table) +{ + const std::string base = "http://viewer-settings.s3.amazonaws.com/"; + + const std::string filename = llformat(table.c_str(), LLVersionInfo::getVersion().c_str()); + + const std::string url = base + filename; + + const std::string path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename); + + llinfos << "LLFeatureManager fetching " << url << " into " << path << llendl; + + LLHTTPClient::get(url, new LLHTTPFeatureTableResponder(path)); +} + +// fetch table(s) from a website (S3) +void LLFeatureManager::fetchHTTPTables() +{ + fetch_table(FEATURE_TABLE_VER_FILENAME); + fetch_table(GPU_TABLE_VER_FILENAME); +} + + void LLFeatureManager::cleanupFeatureTables() { std::for_each(mMaskList.begin(), mMaskList.end(), DeletePairedPointer()); diff --git a/indra/newview/llfeaturemanager.h b/indra/newview/llfeaturemanager.h index dd218d428f..c2ecede2c5 100644 --- a/indra/newview/llfeaturemanager.h +++ b/indra/newview/llfeaturemanager.h @@ -48,6 +48,7 @@ typedef enum EGPUClass GPU_CLASS_3 = 3 } EGPUClass; + class LLFeatureInfo { public: @@ -144,8 +145,13 @@ public: // in the skip list if true void applyFeatures(bool skipFeatures); + // load the dynamic GPU/feature table from a website + void fetchHTTPTables(); + protected: void loadGPUClass(); + BOOL parseFeatureTable(std::string filename); + void parseGPUTable(std::string filename); void initBaseMask(); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 0a464b3b6c..b28377e591 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -384,13 +384,22 @@ bool idle_startup() { LLNotificationsUtil::add("DisplaySetToRecommended"); } + else if ((gSavedSettings.getS32("LastGPUClass") != LLFeatureManager::getInstance()->getGPUClass()) && + (gSavedSettings.getS32("LastGPUClass") != -1)) + { + LLNotificationsUtil::add("DisplaySetToRecommended"); + } else if (!gViewerWindow->getInitAlert().empty()) { LLNotificationsUtil::add(gViewerWindow->getInitAlert()); } gSavedSettings.setS32("LastFeatureVersion", LLFeatureManager::getInstance()->getVersion()); + gSavedSettings.setS32("LastGPUClass", LLFeatureManager::getInstance()->getGPUClass()); + // load dynamic GPU/feature tables from website (S3) + LLFeatureManager::getInstance()->fetchHTTPTables(); + std::string xml_file = LLUI::locateSkin("xui_version.xml"); LLXMLNodePtr root; bool xml_ok = false; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index e0463e3c4a..9fc7d6a56d 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1433,6 +1433,7 @@ LLViewerWindow::LLViewerWindow( if (LLFeatureManager::getInstance()->isSafe() || (gSavedSettings.getS32("LastFeatureVersion") != LLFeatureManager::getInstance()->getVersion()) + || (gSavedSettings.getS32("LastGPUClass") != LLFeatureManager::getInstance()->getGPUClass()) || (gSavedSettings.getBOOL("ProbeHardwareOnStartup"))) { LLFeatureManager::getInstance()->applyRecommendedSettings(); -- cgit v1.3 From 1ad46b5cd0fcac0d3224d37d555092258593eabd Mon Sep 17 00:00:00 2001 From: Roxie Linden Date: Mon, 24 May 2010 13:59:10 -0700 Subject: DEV-50173 - investigate certificate code performance DEV-50166 - LLBasicCertificateChain::validate calls in log Added caching of certificates that have been validated. The sha1 hash for the certificate is stored and is associated with the from and to times. When the certificate is validated, the code determines whether the certificate has successfully been validated before by looking for it in the cache, and then checks the date of the cert. If that is successful, the validation calls with success. Otherwise, it proceeds to do a full validation of the certificate. --- indra/newview/llsecapi.cpp | 2 +- indra/newview/llsecapi.h | 31 ++++--- indra/newview/llsechandler_basic.cpp | 114 +++++++++++++++++------- indra/newview/llsechandler_basic.h | 23 +++-- indra/newview/llstartup.cpp | 3 +- indra/newview/llxmlrpctransaction.cpp | 3 +- indra/newview/tests/llsechandler_basic_test.cpp | 34 +++---- 7 files changed, 134 insertions(+), 76 deletions(-) (limited to 'indra/newview/llstartup.cpp') diff --git a/indra/newview/llsecapi.cpp b/indra/newview/llsecapi.cpp index 1caeec5b04..9e636f38c0 100644 --- a/indra/newview/llsecapi.cpp +++ b/indra/newview/llsecapi.cpp @@ -124,7 +124,7 @@ int secapiSSLCertVerifyCallback(X509_STORE_CTX *ctx, void *param) // we rely on libcurl to validate the hostname, as libcurl does more extensive validation // leaving our hostname validation call mechanism for future additions with respect to // OS native (Mac keyring, windows CAPI) validation. - chain->validate(VALIDATION_POLICY_SSL & (~VALIDATION_POLICY_HOSTNAME), store, validation_params); + store->validate(VALIDATION_POLICY_SSL & (~VALIDATION_POLICY_HOSTNAME), chain, validation_params); } catch (LLCertValidationTrustException& cert_exception) { diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h index 59a1e1eff0..5a1a3879d4 100644 --- a/indra/newview/llsecapi.h +++ b/indra/newview/llsecapi.h @@ -154,7 +154,7 @@ public: // return an LLSD object containing information about the certificate // such as its name, signature, expiry time, serial number - virtual LLSD getLLSD() const=0; + virtual void getLLSD(LLSD& llsd)=0; // return an openSSL X509 struct for the certificate virtual X509* getOpenSSLX509() const=0; @@ -231,6 +231,18 @@ public: virtual LLPointer erase(iterator cert)=0; }; +// class LLCertificateChain +// Class representing a chain of certificates in order, with the +// first element being the child cert. +class LLCertificateChain : virtual public LLCertificateVector +{ + +public: + LLCertificateChain() {} + + virtual ~LLCertificateChain() {} + +}; // class LLCertificateStore // represents a store of certificates, typically a store of root CA @@ -250,30 +262,17 @@ public: // return the store id virtual std::string storeId() const=0; -}; - -// class LLCertificateChain -// Class representing a chain of certificates in order, with the -// first element being the child cert. -class LLCertificateChain : virtual public LLCertificateVector -{ - -public: - LLCertificateChain() {} - virtual ~LLCertificateChain() {} - // validate a certificate chain given the params. // Will throw exceptions on error virtual void validate(int validation_policy, - LLPointer ca_store, + LLPointer cert_chain, const LLSD& validation_params) =0; + }; - - inline bool operator==(const LLCertificateVector::iterator& _lhs, const LLCertificateVector::iterator& _rhs) { diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp index edf5ce9b60..84ab9b9175 100644 --- a/indra/newview/llsechandler_basic.cpp +++ b/indra/newview/llsechandler_basic.cpp @@ -85,7 +85,6 @@ LLBasicCertificate::LLBasicCertificate(const std::string& pem_cert) { throw LLInvalidCertificate(this); } - _initLLSD(); } @@ -96,7 +95,6 @@ LLBasicCertificate::LLBasicCertificate(X509* pCert) throw LLInvalidCertificate(this); } mCert = X509_dup(pCert); - _initLLSD(); } LLBasicCertificate::~LLBasicCertificate() @@ -150,9 +148,13 @@ std::vector LLBasicCertificate::getBinary() const } -LLSD LLBasicCertificate::getLLSD() const +void LLBasicCertificate::getLLSD(LLSD &llsd) { - return mLLSDInfo; + if (mLLSDInfo.isUndefined()) + { + _initLLSD(); + } + llsd = mLLSDInfo; } // Initialize the LLSD info for the certificate @@ -516,8 +518,9 @@ LLBasicCertificateVector::iterator LLBasicCertificateVector::find(const LLSD& pa cert++) { - found= TRUE; - LLSD cert_info = (*cert)->getLLSD(); + found= TRUE; + LLSD cert_info; + (*cert)->getLLSD(cert_info); for (LLSD::map_const_iterator param = params.beginMap(); param != params.endMap(); param++) @@ -543,7 +546,8 @@ LLBasicCertificateVector::iterator LLBasicCertificateVector::find(const LLSD& pa void LLBasicCertificateVector::insert(iterator _iter, LLPointer cert) { - LLSD cert_info = cert->getLLSD(); + LLSD cert_info; + cert->getLLSD(cert_info); if (cert_info.isMap() && cert_info.has(CERT_SHA1_DIGEST)) { LLSD existing_cert_info = LLSD::emptyMap(); @@ -691,7 +695,8 @@ LLBasicCertificateChain::LLBasicCertificateChain(const X509_STORE_CTX* store) while(untrusted_certs.size() > 0) { LLSD find_data = LLSD::emptyMap(); - LLSD cert_data = current->getLLSD(); + LLSD cert_data; + current->getLLSD(cert_data); // we simply build the chain via subject/issuer name as the // client should not have passed in multiple CA's with the same // subject name. If they did, it'll come out in the wash during @@ -850,12 +855,13 @@ bool _LLSDArrayIncludesValue(const LLSD& llsd_set, LLSD llsd_value) } void _validateCert(int validation_policy, - const LLPointer cert, + LLPointer cert, const LLSD& validation_params, int depth) { - LLSD current_cert_info = cert->getLLSD(); + LLSD current_cert_info; + cert->getLLSD(current_cert_info); // check basic properties exist in the cert if(!current_cert_info.has(CERT_SUBJECT_NAME) || !current_cert_info.has(CERT_SUBJECT_NAME_STRING)) { @@ -943,8 +949,9 @@ bool _verify_signature(LLPointer parent, LLPointer child) { bool verify_result = FALSE; - LLSD cert1 = parent->getLLSD(); - LLSD cert2 = child->getLLSD(); + LLSD cert1, cert2; + parent->getLLSD(cert1); + child->getLLSD(cert2); X509 *signing_cert = parent->getOpenSSLX509(); X509 *child_cert = child->getOpenSSLX509(); if((signing_cert != NULL) && (child_cert != NULL)) @@ -979,6 +986,7 @@ bool _verify_signature(LLPointer parent, return verify_result; } + // validate the certificate chain against a store. // There are many aspects of cert validatioin policy involved in // trust validation. The policies in this validation algorithm include @@ -993,8 +1001,8 @@ bool _verify_signature(LLPointer parent, // and verify the last cert is in the certificate store, or points // to a cert in the store. It validates whether any cert in the chain // is trusted in the store, even if it's not the last one. -void LLBasicCertificateChain::validate(int validation_policy, - LLPointer ca_store, +void LLBasicCertificateStore::validate(int validation_policy, + LLPointer cert_chain, const LLSD& validation_params) { @@ -1002,8 +1010,8 @@ void LLBasicCertificateChain::validate(int validation_policy, { throw LLCertException(NULL, "No certs in chain"); } - iterator current_cert = begin(); - LLSD current_cert_info = (*current_cert)->getLLSD(); + iterator current_cert = cert_chain->begin(); + LLSD current_cert_info; LLSD validation_date; if (validation_params.has(CERT_VALIDATION_DATE)) { @@ -1012,6 +1020,7 @@ void LLBasicCertificateChain::validate(int validation_policy, if (validation_policy & VALIDATION_POLICY_HOSTNAME) { + (*current_cert)->getLLSD(current_cert_info); if(!validation_params.has(CERT_HOSTNAME)) { throw LLCertException((*current_cert), "No hostname passed in for validation"); @@ -1021,7 +1030,7 @@ void LLBasicCertificateChain::validate(int validation_policy, throw LLInvalidCertificate((*current_cert)); } - LL_INFOS("SECAPI") << "Validating the hostname " << validation_params[CERT_HOSTNAME].asString() << + LL_DEBUGS("SECAPI") << "Validating the hostname " << validation_params[CERT_HOSTNAME].asString() << "against the cert CN " << current_cert_info[CERT_SUBJECT_NAME][CERT_NAME_CN].asString() << LL_ENDL; if(!_cert_hostname_wildcard_match(validation_params[CERT_HOSTNAME].asString(), current_cert_info[CERT_SUBJECT_NAME][CERT_NAME_CN].asString())) @@ -1030,16 +1039,50 @@ void LLBasicCertificateChain::validate(int validation_policy, (*current_cert)); } } - + // check the cache of already validated certs + X509* cert_x509 = (*current_cert)->getOpenSSLX509(); + if(!cert_x509) + { + throw LLInvalidCertificate((*current_cert)); + } + std::string sha1_hash((const char *)cert_x509->sha1_hash, SHA_DIGEST_LENGTH); + t_cert_cache::iterator cache_entry = mTrustedCertCache.find(sha1_hash); + if(cache_entry != mTrustedCertCache.end()) + { + LL_DEBUGS("SECAPI") << "Found cert in cache" << LL_ENDL; + // this cert is in the cache, so validate the time. + if (validation_policy & VALIDATION_POLICY_TIME) + { + LLDate validation_date(time(NULL)); + if(validation_params.has(CERT_VALIDATION_DATE)) + { + validation_date = validation_params[CERT_VALIDATION_DATE]; + } + + if((validation_date < cache_entry->second.first) || + (validation_date > cache_entry->second.second)) + { + throw LLCertValidationExpirationException((*current_cert), validation_date); + } + } + // successfully found in cache + return; + } + if(current_cert_info.isUndefined()) + { + (*current_cert)->getLLSD(current_cert_info); + } + LLDate from_time = current_cert_info[CERT_VALID_FROM].asDate(); + LLDate to_time = current_cert_info[CERT_VALID_TO].asDate(); int depth = 0; LLPointer previous_cert; // loop through the cert chain, validating the current cert against the next one. - while(current_cert != end()) + while(current_cert != cert_chain->end()) { int local_validation_policy = validation_policy; - if(current_cert == begin()) + if(current_cert == cert_chain->begin()) { // for the child cert, we don't validate CA stuff local_validation_policy &= ~(VALIDATION_POLICY_CA_KU | @@ -1061,23 +1104,23 @@ void LLBasicCertificateChain::validate(int validation_policy, depth); // look for a CA in the CA store that may belong to this chain. - LLSD cert_llsd = (*current_cert)->getLLSD(); LLSD cert_search_params = LLSD::emptyMap(); // is the cert itself in the store? - cert_search_params[CERT_SHA1_DIGEST] = cert_llsd[CERT_SHA1_DIGEST]; - LLCertificateStore::iterator found_store_cert = ca_store->find(cert_search_params); - if(found_store_cert != ca_store->end()) + cert_search_params[CERT_SHA1_DIGEST] = current_cert_info[CERT_SHA1_DIGEST]; + LLCertificateStore::iterator found_store_cert = find(cert_search_params); + if(found_store_cert != end()) { + mTrustedCertCache[sha1_hash] = std::pair(from_time, to_time); return; } // is the parent in the cert store? cert_search_params = LLSD::emptyMap(); - cert_search_params[CERT_SUBJECT_NAME_STRING] = cert_llsd[CERT_ISSUER_NAME_STRING]; - if (cert_llsd.has(CERT_AUTHORITY_KEY_IDENTIFIER)) + cert_search_params[CERT_SUBJECT_NAME_STRING] = current_cert_info[CERT_ISSUER_NAME_STRING]; + if (current_cert_info.has(CERT_AUTHORITY_KEY_IDENTIFIER)) { - LLSD cert_aki = cert_llsd[CERT_AUTHORITY_KEY_IDENTIFIER]; + LLSD cert_aki = current_cert_info[CERT_AUTHORITY_KEY_IDENTIFIER]; if(cert_aki.has(CERT_AUTHORITY_KEY_IDENTIFIER_ID)) { cert_search_params[CERT_SUBJECT_KEY_IDENTFIER] = cert_aki[CERT_AUTHORITY_KEY_IDENTIFIER_ID]; @@ -1087,11 +1130,10 @@ void LLBasicCertificateChain::validate(int validation_policy, cert_search_params[CERT_SERIAL_NUMBER] = cert_aki[CERT_AUTHORITY_KEY_IDENTIFIER_SERIAL]; } } - found_store_cert = ca_store->find(cert_search_params); + found_store_cert = find(cert_search_params); - if(found_store_cert != ca_store->end()) + if(found_store_cert != end()) { - LLSD foo = (*found_store_cert)->getLLSD(); // validate the store cert against the depth _validateCert(validation_policy & VALIDATION_POLICY_CA_BASIC_CONSTRAINTS, (*found_store_cert), @@ -1105,11 +1147,16 @@ void LLBasicCertificateChain::validate(int validation_policy, throw LLCertValidationInvalidSignatureException(*current_cert); } // successfully validated. + mTrustedCertCache[sha1_hash] = std::pair(from_time, to_time); return; } previous_cert = (*current_cert); current_cert++; - depth++; + depth++; + if(current_cert != current_cert != cert_chain->end()) + { + (*current_cert)->getLLSD(current_cert_info); + } } if (validation_policy & VALIDATION_POLICY_TRUSTED) { @@ -1118,6 +1165,7 @@ void LLBasicCertificateChain::validate(int validation_policy, throw LLCertValidationTrustException((*this)[size()-1]); } + mTrustedCertCache[sha1_hash] = std::pair(from_time, to_time); } @@ -1155,7 +1203,7 @@ void LLSecAPIBasicHandler::init() "CA.pem"); - LL_INFOS("SECAPI") << "Loading certificate store from " << store_file << LL_ENDL; + LL_DEBUGS("SECAPI") << "Loading certificate store from " << store_file << LL_ENDL; mStore = new LLBasicCertificateStore(store_file); // grab the application CA.pem file that contains the well-known certs shipped @@ -1465,7 +1513,7 @@ void LLSecAPIBasicHandler::saveCredential(LLPointer cred, bool sav { credential["authenticator"] = cred->getAuthenticator(); } - LL_INFOS("SECAPI") << "Saving Credential " << cred->getGrid() << ":" << cred->userID() << " " << save_authenticator << LL_ENDL; + LL_DEBUGS("SECAPI") << "Saving Credential " << cred->getGrid() << ":" << cred->userID() << " " << save_authenticator << LL_ENDL; setProtectedData("credential", cred->getGrid(), credential); //*TODO: If we're saving Agni credentials, should we write the // credentials to the legacy password.dat/etc? diff --git a/indra/newview/llsechandler_basic.h b/indra/newview/llsechandler_basic.h index 4bbb73f062..3ddd36a81a 100644 --- a/indra/newview/llsechandler_basic.h +++ b/indra/newview/llsechandler_basic.h @@ -59,12 +59,13 @@ public: virtual std::string getPem() const; virtual std::vector getBinary() const; - virtual LLSD getLLSD() const; + virtual void getLLSD(LLSD &llsd); virtual X509* getOpenSSLX509() const; // set llsd elements for testing void setLLSD(const std::string name, const LLSD& value) { mLLSDInfo[name] = value; } + protected: // certificates are stored as X509 objects, as validation and @@ -173,8 +174,21 @@ public: // return the store id virtual std::string storeId() const; + // validate a certificate chain against a certificate store, using the + // given validation policy. + virtual void validate(int validation_policy, + LLPointer ca_chain, + const LLSD& validation_params); + protected: - std::vector >mCerts; + std::vector > mCerts; + + // cache of cert sha1 hashes to from/to date pairs, to improve + // performance of cert trust. Note, these are not the CA certs, + // but the certs that have been validated against this store. + typedef std::map > t_cert_cache; + t_cert_cache mTrustedCertCache; + std::string mFilename; }; @@ -189,11 +203,6 @@ public: virtual ~LLBasicCertificateChain() {} - // validate a certificate chain against a certificate store, using the - // given validation policy. - virtual void validate(int validation_policy, - LLPointer ca_store, - const LLSD& validation_params); }; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 0a464b3b6c..7022d83868 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -2702,7 +2702,8 @@ LLSD transform_cert_args(LLPointer cert) { LLSD args = LLSD::emptyMap(); std::string value; - LLSD cert_info = cert->getLLSD(); + LLSD cert_info; + cert->getLLSD(cert_info); // convert all of the elements in the cert into // args for the xml dialog, so we have flexability to // display various parts of the cert by only modifying diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index da61840761..bc1a48e26a 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -247,7 +247,8 @@ int LLXMLRPCTransaction::Impl::_sslCertVerifyCallback(X509_STORE_CTX *ctx, void validation_params[CERT_HOSTNAME] = uri.hostName(); try { - chain->validate(VALIDATION_POLICY_SSL, store, validation_params); + // don't validate hostname. Let libcurl do it instead. That way, it'll handle redirects + store->validate(VALIDATION_POLICY_SSL & (~VALIDATION_POLICY_HOSTNAME), chain, validation_params); } catch (LLCertValidationTrustException& cert_exception) { diff --git a/indra/newview/tests/llsechandler_basic_test.cpp b/indra/newview/tests/llsechandler_basic_test.cpp index fd680b24f0..d1330e2270 100644 --- a/indra/newview/tests/llsechandler_basic_test.cpp +++ b/indra/newview/tests/llsechandler_basic_test.cpp @@ -950,15 +950,15 @@ namespace tut test_chain->add(new LLBasicCertificate(mX509IntermediateCert)); - test_chain->validate(0, test_store, validation_params); + test_store->validate(0, test_chain, validation_params); // add the root certificate to the chain and revalidate test_chain->add(new LLBasicCertificate(mX509RootCert)); - test_chain->validate(0, test_store, validation_params); + test_store->validate(0, test_chain, validation_params); // add the child cert at the head of the chain, and revalidate (3 deep chain) test_chain->insert(test_chain->begin(), new LLBasicCertificate(mX509ChildCert)); - test_chain->validate(0, test_store, validation_params); + test_store->validate(0, test_chain, validation_params); // basic failure cases test_chain = new LLBasicCertificateChain(NULL); @@ -967,14 +967,14 @@ namespace tut ensure_throws("no CA, with only a child cert", LLCertValidationTrustException, (*test_chain)[0], - test_chain->validate, + test_store->validate, VALIDATION_POLICY_TRUSTED, - test_store, + test_chain, validation_params); // validate without the trust flag. - test_chain->validate(0, test_store, validation_params); + test_store->validate(0, test_chain, validation_params); // clear out the store test_store = new LLBasicCertificateStore("mycertstore.pem"); @@ -983,9 +983,9 @@ namespace tut ensure_throws("no CA, with child and intermediate certs", LLCertValidationTrustException, (*test_chain)[1], - test_chain->validate, + test_store->validate, VALIDATION_POLICY_TRUSTED, - test_store, + test_chain, validation_params); // validate without the trust flag test_chain->validate(0, test_store, validation_params); @@ -994,7 +994,7 @@ namespace tut LLSD child_info = (*test_chain)[0]->getLLSD(); validation_params = LLSD::emptyMap(); validation_params[CERT_VALIDATION_DATE] = LLDate(child_info[CERT_VALID_FROM].asDate().secondsSinceEpoch() + 1.0); - test_chain->validate(VALIDATION_POLICY_TIME, test_store, validation_params); + test_store->validate(VALIDATION_POLICY_TIME, test_chain, validation_params); validation_params = LLSD::emptyMap(); validation_params[CERT_VALIDATION_DATE] = child_info[CERT_VALID_FROM].asDate(); @@ -1005,9 +1005,9 @@ namespace tut ensure_throws("Child cert not yet valid" , LLCertValidationExpirationException, (*test_chain)[0], - test_chain->validate, + test_store->validate, VALIDATION_POLICY_TIME, - test_store, + test_chain, validation_params); validation_params = LLSD::emptyMap(); validation_params[CERT_VALIDATION_DATE] = LLDate(child_info[CERT_VALID_TO].asDate().secondsSinceEpoch() + 1.0); @@ -1016,9 +1016,9 @@ namespace tut ensure_throws("Child cert expired", LLCertValidationExpirationException, (*test_chain)[0], - test_chain->validate, + test_store->validate, VALIDATION_POLICY_TIME, - test_store, + test_chain, validation_params); // test SSL KU @@ -1026,7 +1026,7 @@ namespace tut test_chain = new LLBasicCertificateChain(NULL); test_chain->add(new LLBasicCertificate(mX509ChildCert)); test_chain->add(new LLBasicCertificate(mX509IntermediateCert)); - test_chain->validate(VALIDATION_POLICY_SSL_KU, test_store, validation_params); + test_store->validate(VALIDATION_POLICY_SSL_KU, test_chain, validation_params); test_chain = new LLBasicCertificateChain(NULL); test_chain->add(new LLBasicCertificate(mX509TestCert)); @@ -1034,9 +1034,9 @@ namespace tut ensure_throws("Cert doesn't have ku", LLCertKeyUsageValidationException, (*test_chain)[0], - test_chain->validate, + test_store->validate, VALIDATION_POLICY_SSL_KU, - test_store, + test_chain, validation_params); // test sha1RSA validation @@ -1044,7 +1044,7 @@ namespace tut test_chain->add(new LLBasicCertificate(mSha1RSATestCert)); test_chain->add(new LLBasicCertificate(mSha1RSATestCA)); - test_chain->validate(0, test_store, validation_params); + test_store->validate(0, test_chain, validation_params); } }; -- cgit v1.3 From 07dba9ae377d216e049aa9c3019bc51571b48488 Mon Sep 17 00:00:00 2001 From: Igor Borovkov Date: Thu, 27 May 2010 13:24:06 +0300 Subject: EXT-7422 FIXED saving initial outfit in My Outfits on very first login added saving initial outfit in My Outfits when wearables got loaded Reviewed by Neal Orman at https://codereview.productengine.com/secondlife/r/450/ --HG-- branch : product-engine --- indra/newview/llagentwearablesfetch.cpp | 12 ++++++++++-- indra/newview/llstartup.cpp | 21 +++++++++++++++++++++ indra/newview/llstartup.h | 4 ++++ 3 files changed, 35 insertions(+), 2 deletions(-) (limited to 'indra/newview/llstartup.cpp') diff --git a/indra/newview/llagentwearablesfetch.cpp b/indra/newview/llagentwearablesfetch.cpp index 03d09a3798..43a0d48d8b 100644 --- a/indra/newview/llagentwearablesfetch.cpp +++ b/indra/newview/llagentwearablesfetch.cpp @@ -37,6 +37,7 @@ #include "llagentwearables.h" #include "llappearancemgr.h" #include "llinventoryfunctions.h" +#include "llstartup.h" #include "llvoavatarself.h" LLInitialWearablesFetch::LLInitialWearablesFetch(const LLUUID& cof_id) : @@ -260,8 +261,11 @@ void LLLibraryOutfitsFetch::folderDone() LLInventoryModel::item_array_t wearable_array; gInventory.collectDescendents(mMyOutfitsID, cat_array, wearable_array, LLInventoryModel::EXCLUDE_TRASH); - // Early out if we already have items in My Outfits. - if (cat_array.count() > 0 || wearable_array.count() > 0) + + // Early out if we already have items in My Outfits + // except the case when My Outfits contains just initial outfit + if (cat_array.count() > 1 || + cat_array.count() == 1 && cat_array[0]->getUUID() != LLAppearanceMgr::getInstance()->getBaseOutfitUUID()) { mOutfitsPopulated = true; return; @@ -272,6 +276,7 @@ void LLLibraryOutfitsFetch::folderDone() // If Library->Clothing->Initial Outfits exists, use that. LLNameCategoryCollector matchFolderFunctor("Initial Outfits"); + cat_array.clear(); gInventory.collectDescendentsIf(mLibraryClothingID, cat_array, wearable_array, LLInventoryModel::EXCLUDE_TRASH, @@ -489,6 +494,9 @@ void LLLibraryOutfitsFetch::contentsDone() llwarns << "Library folder import for uuid:" << folder_id << " failed to find folder." << llendl; continue; } + + //initial outfit should be already in My Outfits + if (cat->getName() == LLStartUp::getInitialOutfitName()) continue; // First, make a folder in the My Outfits directory. LLUUID new_outfit_folder_id = gInventory.createNewCategory(mMyOutfitsID, LLFolderType::FT_OUTFIT, cat->getName()); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 0a464b3b6c..466c154f36 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -225,6 +225,7 @@ extern S32 gStartImageHeight; static bool gGotUseCircuitCodeAck = false; static std::string sInitialOutfit; static std::string sInitialOutfitGender; // "male" or "female" +static boost::signals2::connection sWearablesLoadedCon; static bool gUseCircuitCallbackCalled = false; @@ -2430,6 +2431,8 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name, } else { + sWearablesLoadedCon = gAgentWearables.addLoadedCallback(LLStartUp::saveInitialOutfit); + bool do_copy = true; bool do_append = false; LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id); @@ -2475,6 +2478,24 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name, } +//static +void LLStartUp::saveInitialOutfit() +{ + if (sInitialOutfit.empty()) return; + + if (sWearablesLoadedCon.connected()) + { + sWearablesLoadedCon.disconnect(); + } + + LLAppearanceMgr::getInstance()->makeNewOutfitLinks(sInitialOutfit); +} + +std::string& LLStartUp::getInitialOutfitName() +{ + return sInitialOutfit; +} + // Loads a bitmap to display during load void init_start_screen(S32 location_id) { diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h index 16cc74504f..e1e108ca6a 100644 --- a/indra/newview/llstartup.h +++ b/indra/newview/llstartup.h @@ -102,6 +102,10 @@ public: static void loadInitialOutfit( const std::string& outfit_folder_name, const std::string& gender_name ); + //save loaded initial outfit into My Outfits category + static void saveInitialOutfit(); + + static std::string& getInitialOutfitName(); static bool dispatchURL(); // if we have a SLURL or sim string ("Ahern/123/45") that started -- cgit v1.3