diff options
| author | Roxie Linden <roxie@lindenlab.com> | 2010-04-01 21:47:22 -0700 |
|---|---|---|
| committer | Roxie Linden <roxie@lindenlab.com> | 2010-04-01 21:47:22 -0700 |
| commit | aa0a129b6798f8be554d1d9d41cbd217a0040daf (patch) | |
| tree | a206cf638fa4a8f48dd869e0ccf12b7b6a428972 /indra | |
| parent | 98695056c2fbfb91de805d9e2a01cde23668c4d3 (diff) | |
| parent | 86dc5bce1a6fdde1238fea97ca1f6f8acb862184 (diff) | |
Automated Merge
Diffstat (limited to 'indra')
121 files changed, 16218 insertions, 9588 deletions
diff --git a/indra/llcommon/lluri.cpp b/indra/llcommon/lluri.cpp index 9d4f3a98f0..0e8f3f0f73 100644 --- a/indra/llcommon/lluri.cpp +++ b/indra/llcommon/lluri.cpp @@ -231,7 +231,8 @@ static BOOL isDefault(const std::string& scheme, U16 port) void LLURI::parseAuthorityAndPathUsingOpaque() { if (mScheme == "http" || mScheme == "https" || - mScheme == "ftp" || mScheme == "secondlife" ) + mScheme == "ftp" || mScheme == "secondlife" || + mScheme == "x-grid-location-info") { if (mEscapedOpaque.substr(0,2) != "//") { diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp index bcbae06ec5..583c1e589b 100644 --- a/indra/llcommon/lluuid.cpp +++ b/indra/llcommon/lluuid.cpp @@ -33,9 +33,12 @@ // We can't use WIN32_LEAN_AND_MEAN here, needs lots of includes. #if LL_WINDOWS -# undef WIN32_LEAN_AND_MEAN -# include <winsock2.h> -# include <windows.h> +#undef WIN32_LEAN_AND_MEAN +#include <winsock2.h> +#include <windows.h> +// ugh, this is ugly. We need to straighten out our linking for this library +#pragma comment(lib, "IPHLPAPI.lib") +#include <iphlpapi.h> #endif #include "lldefs.h" @@ -452,67 +455,102 @@ static void get_random_bytes(void *buf, int nbytes) return; } -#if LL_WINDOWS -typedef struct _ASTAT_ -{ - ADAPTER_STATUS adapt; - NAME_BUFFER NameBuff [30]; -}ASTAT, * PASTAT; +#if LL_WINDOWS +// Code copied from http://msdn.microsoft.com/en-us/library/aa365939(VS.85).aspx +// This code grabs the first hardware address, rather than the first interface. +// Using a VPN can cause the first returned interface to be changed. + +const S32 MAC_ADDRESS_BYTES=6; + // static -S32 LLUUID::getNodeID(unsigned char * node_id) -{ - ASTAT Adapter; - NCB Ncb; - UCHAR uRetCode; - LANA_ENUM lenum; - int i; - int retval = 0; - - memset( &Ncb, 0, sizeof(Ncb) ); - Ncb.ncb_command = NCBENUM; - Ncb.ncb_buffer = (UCHAR *)&lenum; - Ncb.ncb_length = sizeof(lenum); - uRetCode = Netbios( &Ncb ); - // printf( "The NCBENUM return code is: 0x%x \n", uRetCode ); - - for(i=0; i < lenum.length ;i++) - { - memset( &Ncb, 0, sizeof(Ncb) ); - Ncb.ncb_command = NCBRESET; - Ncb.ncb_lana_num = lenum.lana[i]; - - uRetCode = Netbios( &Ncb ); - // printf( "The NCBRESET on LANA %d return code is: 0x%x \n", - // lenum.lana[i], uRetCode ); - - memset( &Ncb, 0, sizeof (Ncb) ); - Ncb.ncb_command = NCBASTAT; - Ncb.ncb_lana_num = lenum.lana[i]; - - strcpy( (char *)Ncb.ncb_callname, "* " ); /* Flawfinder: ignore */ - Ncb.ncb_buffer = (unsigned char *)&Adapter; - Ncb.ncb_length = sizeof(Adapter); - - uRetCode = Netbios( &Ncb ); -// printf( "The NCBASTAT on LANA %d return code is: 0x%x \n", -// lenum.lana[i], uRetCode ); - if ( uRetCode == 0 ) - { -// printf( "The Ethernet Number on LANA %d is: %02x%02x%02x%02x%02x%02x\n", -// lenum.lana[i], -// Adapter.adapt.adapter_address[0], -// Adapter.adapt.adapter_address[1], -// Adapter.adapt.adapter_address[2], -// Adapter.adapt.adapter_address[3], -// Adapter.adapt.adapter_address[4], -// Adapter.adapt.adapter_address[5] ); - memcpy(node_id,Adapter.adapt.adapter_address,6); /* Flawfinder: ignore */ - retval = 1; - - } - } - return retval; +S32 LLUUID::getNodeID(unsigned char *node_id) +{ + + // Declare and initialize variables. + DWORD dwSize = 0; + DWORD dwRetVal = 0; + int i; + +/* variables used for GetIfTable and GetIfEntry */ + MIB_IFTABLE *pIfTable; + MIB_IFROW *pIfRow; + + // Allocate memory for our pointers. + pIfTable = (MIB_IFTABLE *) malloc(sizeof (MIB_IFTABLE)); + if (pIfTable == NULL) + { + printf("Error allocating memory needed to call GetIfTable\n"); + return 0; + } + + // Before calling GetIfEntry, we call GetIfTable to make + // sure there are entries to get and retrieve the interface index. + + // Make an initial call to GetIfTable to get the + // necessary size into dwSize + if (GetIfTable(pIfTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) { + free(pIfTable); + pIfTable = (MIB_IFTABLE *) malloc(dwSize); + if (pIfTable == NULL) + { + printf("Error allocating memory\n"); + return 0; + } + } + // Make a second call to GetIfTable to get the actual + // data we want. + if ((dwRetVal = GetIfTable(pIfTable, &dwSize, 0)) == NO_ERROR) + { + if (pIfTable->dwNumEntries > 0) + { + pIfRow = (MIB_IFROW *) malloc(sizeof (MIB_IFROW)); + if (pIfRow == NULL) + { + printf("Error allocating memory\n"); + if (pIfTable != NULL) + { + free(pIfTable); + pIfTable = NULL; + } + return 0; + } + + int limit = MAC_ADDRESS_BYTES; + memcpy(node_id, "\0\0\0\0\0\0", limit); // zero out array of bytes + for (i = 0; i < (int) pIfTable->dwNumEntries; i++) + { + pIfRow->dwIndex = pIfTable->table[i].dwIndex; + if ((dwRetVal = GetIfEntry(pIfRow)) == NO_ERROR) + { + switch (pIfRow->dwType) + { + case IF_TYPE_ETHERNET_CSMACD: + case IF_TYPE_IEEE80211: + limit = min((int) pIfRow->dwPhysAddrLen, limit); + if (pIfRow->dwPhysAddrLen == 0) + break; + memcpy(node_id, (UCHAR *)&pIfRow->bPhysAddr[0], limit); // just incase the PhysAddr is not the expected MAC_Address size + free(pIfTable); + return 1; //return first hardware device found. + break; + + case IF_TYPE_OTHER: + case IF_TYPE_PPP: + case IF_TYPE_SOFTWARE_LOOPBACK: + case IF_TYPE_ISO88025_TOKENRING: + case IF_TYPE_IEEE1394: + case IF_TYPE_ATM: + case IF_TYPE_TUNNEL: + default: + break; + } + } + } + } + } + free(pIfTable); + return 0; } #elif LL_DARWIN diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index 024e17a777..91e11b8c0d 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -89,10 +89,6 @@ S32 gCurlMultiCount = 0; std::vector<LLMutex*> LLCurl::sSSLMutex; std::string LLCurl::sCAPath; std::string LLCurl::sCAFile; -// Verify SSL certificates by default (matches libcurl default). The ability -// to alter this flag is only to allow us to suppress verification if it's -// broken for some reason. -bool LLCurl::sSSLVerify = true; //static void LLCurl::setCAPath(const std::string& path) @@ -107,18 +103,6 @@ void LLCurl::setCAFile(const std::string& file) } //static -void LLCurl::setSSLVerify(bool verify) -{ - sSSLVerify = verify; -} - -//static -bool LLCurl::getSSLVerify() -{ - return sSSLVerify; -} - -//static std::string LLCurl::getVersionString() { return std::string(curl_version()); @@ -481,8 +465,7 @@ void LLCurl::Easy::prepRequest(const std::string& url, setErrorBuffer(); setCA(); - setopt(CURLOPT_SSL_VERIFYPEER, LLCurl::getSSLVerify()); - setopt(CURLOPT_SSL_VERIFYHOST, LLCurl::getSSLVerify()? 2 : 0); + setopt(CURLOPT_SSL_VERIFYPEER, true); setopt(CURLOPT_TIMEOUT, CURL_REQUEST_TIMEOUT); setoptString(CURLOPT_URL, url); @@ -912,6 +895,15 @@ void LLCurlEasyRequest::setReadCallback(curl_read_callback callback, void* userd } } +void LLCurlEasyRequest::setSSLCtxCallback(curl_ssl_ctx_callback callback, void* userdata) +{ + if (mEasy) + { + mEasy->setopt(CURLOPT_SSL_CTX_FUNCTION, (void*)callback); + mEasy->setopt(CURLOPT_SSL_CTX_DATA, userdata); + } +} + void LLCurlEasyRequest::slist_append(const char* str) { if (mEasy) @@ -1061,3 +1053,4 @@ void LLCurl::cleanupClass() #endif curl_global_cleanup(); } + diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h index caf02cccd9..b6a637ae5b 100644 --- a/indra/llmessage/llcurl.h +++ b/indra/llmessage/llcurl.h @@ -158,16 +158,6 @@ public: static const std::string& getCAPath() { return sCAPath; } /** - * @ brief Set flag controlling whether to verify HTTPS certs. - */ - static void setSSLVerify(bool verify); - - /** - * @ brief Get flag controlling whether to verify HTTPS certs. - */ - static bool getSSLVerify(); - - /** * @ brief Initialize LLCurl class */ static void initClass(); @@ -192,7 +182,6 @@ public: private: static std::string sCAPath; static std::string sCAFile; - static bool sSSLVerify; }; namespace boost @@ -240,6 +229,7 @@ public: void setHeaderCallback(curl_header_callback callback, void* userdata); void setWriteCallback(curl_write_callback callback, void* userdata); void setReadCallback(curl_read_callback callback, void* userdata); + void setSSLCtxCallback(curl_ssl_ctx_callback callback, void* userdata); void slist_append(const char* str); void sendRequest(const std::string& url); void requestComplete(); diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index dd56e18caf..345b76d1a1 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -31,7 +31,7 @@ */ #include "linden_common.h" - +#include <openssl/x509_vfy.h> #include "llhttpclient.h" #include "llassetstorage.h" @@ -46,7 +46,10 @@ #include "message.h" #include <curl/curl.h> + const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f; +LLURLRequest::SSLCertVerifyCallback LLHTTPClient::mCertVerifyCallback = NULL; + //////////////////////////////////////////////////////////////////////////// // Responder class moved to LLCurl @@ -206,13 +209,19 @@ namespace LLPumpIO* theClientPump = NULL; } +void LLHTTPClient::setCertVerifyCallback(LLURLRequest::SSLCertVerifyCallback callback) +{ + LLHTTPClient::mCertVerifyCallback = callback; +} + static void request( const std::string& url, LLURLRequest::ERequestAction method, Injector* body_injector, LLCurl::ResponderPtr responder, const F32 timeout = HTTP_REQUEST_EXPIRY_SECS, - const LLSD& headers = LLSD()) + const LLSD& headers = LLSD() + ) { if (!LLHTTPClient::hasPump()) { @@ -222,7 +231,7 @@ static void request( LLPumpIO::chain_t chain; LLURLRequest* req = new LLURLRequest(method, url); - req->checkRootCertificate(LLCurl::getSSLVerify()); + req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req); lldebugs << LLURLRequest::actionAsVerb(method) << " " << url << " " @@ -417,7 +426,6 @@ static LLSD blocking_request( std::string body_str; // other request method checks root cert first, we skip? - //req->checkRootCertificate(true); // * Set curl handle options curl_easy_setopt(curlp, CURLOPT_NOSIGNAL, 1); // don't use SIGALRM for timeouts diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h index 3d0646e5fe..8afbc9e0fc 100644 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -40,7 +40,8 @@ #include <string> #include <boost/intrusive_ptr.hpp> - +#include <openssl/x509_vfy.h> +#include "llurlrequest.h" #include "llassettype.h" #include "llcurl.h" #include "lliopipe.h" @@ -61,6 +62,7 @@ public: typedef LLCurl::Responder Responder; typedef LLCurl::ResponderPtr ResponderPtr; + /** @name non-blocking API */ //@{ static void head( @@ -155,7 +157,12 @@ public: static void setPump(LLPumpIO& pump); ///< must be called before any of the above calls are made static bool hasPump(); - ///< for testing + + static void setCertVerifyCallback(LLURLRequest::SSLCertVerifyCallback callback); + static LLURLRequest::SSLCertVerifyCallback getCertVerifyCallback() { return mCertVerifyCallback; } + +protected: + static LLURLRequest::SSLCertVerifyCallback mCertVerifyCallback; }; #endif // LL_LLHTTPCLIENT_H diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index 4e7ceff984..1e76d10828 100644 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -36,7 +36,8 @@ #include "llurlrequest.h" #include <algorithm> - +#include <openssl/x509_vfy.h> +#include <openssl/ssl.h> #include "llcurl.h" #include "llioutil.h" #include "llmemtype.h" @@ -56,6 +57,8 @@ const std::string CONTEXT_TRANSFERED_BYTES("transfered_bytes"); static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user); + + /** * class LLURLRequestDetail */ @@ -72,6 +75,7 @@ public: U32 mBodyLimit; S32 mByteAccumulator; bool mIsBodyLimitSet; + LLURLRequest::SSLCertVerifyCallback mSSLVerifyCallback; }; LLURLRequestDetail::LLURLRequestDetail() : @@ -80,7 +84,8 @@ LLURLRequestDetail::LLURLRequestDetail() : mLastRead(NULL), mBodyLimit(0), mByteAccumulator(0), - mIsBodyLimitSet(false) + mIsBodyLimitSet(false), + mSSLVerifyCallback(NULL) { LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); mCurlRequest = new LLCurlEasyRequest(); @@ -94,6 +99,36 @@ LLURLRequestDetail::~LLURLRequestDetail() mLastRead = NULL; } +void LLURLRequest::setSSLVerifyCallback(SSLCertVerifyCallback callback, void *param) +{ + mDetail->mSSLVerifyCallback = callback; + mDetail->mCurlRequest->setSSLCtxCallback(LLURLRequest::_sslCtxCallback, (void *)this); + mDetail->mCurlRequest->setopt(CURLOPT_SSL_VERIFYPEER, true); + mDetail->mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, 2); +} + + +// _sslCtxFunction +// Callback function called when an SSL Context is created via CURL +// used to configure the context for custom cert validation + +CURLcode LLURLRequest::_sslCtxCallback(CURL * curl, void *sslctx, void *param) +{ + LLURLRequest *req = (LLURLRequest *)param; + if(req == NULL || req->mDetail->mSSLVerifyCallback == NULL) + { + SSL_CTX_set_cert_verify_callback((SSL_CTX *)sslctx, NULL, NULL); + return CURLE_OK; + } + SSL_CTX * ctx = (SSL_CTX *) sslctx; + // disable any default verification for server certs + SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); + // set the verification callback. + SSL_CTX_set_cert_verify_callback(ctx, req->mDetail->mSSLVerifyCallback, (void *)req); + // the calls are void + return CURLE_OK; + +} /** * class LLURLRequest @@ -148,6 +183,11 @@ void LLURLRequest::setURL(const std::string& url) mDetail->mURL = url; } +std::string LLURLRequest::getURL() const +{ + return mDetail->mURL; +} + void LLURLRequest::addHeader(const char* header) { LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); @@ -160,13 +200,6 @@ void LLURLRequest::setBodyLimit(U32 size) mDetail->mIsBodyLimitSet = true; } -void LLURLRequest::checkRootCertificate(bool check) -{ - mDetail->mCurlRequest->setopt(CURLOPT_SSL_VERIFYPEER, (check? TRUE : FALSE)); - mDetail->mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, (check? 2 : 0)); - mDetail->mCurlRequest->setoptString(CURLOPT_ENCODING, ""); -} - void LLURLRequest::setCallback(LLURLRequestComplete* callback) { LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h index cb3c466440..69fd22e592 100644 --- a/indra/llmessage/llurlrequest.h +++ b/indra/llmessage/llurlrequest.h @@ -44,6 +44,8 @@ #include "lliopipe.h" #include "llchainio.h" #include "llerror.h" +#include <openssl/x509_vfy.h> +#include "llcurl.h" extern const std::string CONTEXT_REQUEST; @@ -72,6 +74,8 @@ class LLURLRequest : public LLIOPipe { LOG_CLASS(LLURLRequest); public: + + typedef int (* SSLCertVerifyCallback)(X509_STORE_CTX *ctx, void *param); /** * @brief This enumeration is for specifying the type of request. */ @@ -125,7 +129,7 @@ public: * */ void setURL(const std::string& url); - + std::string getURL() const; /** * @brief Add a header to the http post. * @@ -143,8 +147,9 @@ public: * Set whether request will check that remote server * certificates are signed by a known root CA when using HTTPS. */ - void checkRootCertificate(bool check); + void setSSLVerifyCallback(SSLCertVerifyCallback callback, void * param); + /** * @brief Return at most size bytes of body. * @@ -189,6 +194,7 @@ public: * @brief Give this pipe a chance to handle a generated error */ virtual EStatus handleError(EStatus status, LLPumpIO* pump); + protected: /** @@ -217,6 +223,8 @@ protected: S32 mRequestTransferedBytes; S32 mResponseTransferedBytes; + static CURLcode _sslCtxCallback(CURL * curl, void *sslctx, void *param); + private: /** * @brief Initialize the object. Called during construction. @@ -364,62 +372,6 @@ protected: }; -/** - * @class LLURLRequestClientFactory - * @brief Template class to build url request based client chains - * - * This class eases construction of a basic sd rpc client. Here is an - * example of it's use: - * <code> - * class LLUsefulService : public LLService { ... }<br> - * LLService::registerCreator(<br> - * "useful",<br> - * LLService::creator_t(new LLURLRequestClientFactory<LLUsefulService>))<br> - * </code> - * - * This class should work, but I never got around to using/testing it. - * - */ -#if 0 -template<class Client> -class LLURLRequestClientFactory : public LLChainIOFactory -{ -public: - LLURLRequestClientFactory(LLURLRequest::ERequestAction action) {} - LLURLRequestClientFactory( - LLURLRequest::ERequestAction action, - const std::string& fixed_url) : - mAction(action), - mURL(fixed_url) - { - } - virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const - { - lldebugs << "LLURLRequestClientFactory::build" << llendl; - LLIOPipe::ptr_t service(new Client); - chain.push_back(service); - LLURLRequest* http(new LLURLRequest(mAction)); - LLIOPipe::ptr_t http_pipe(http); - // *FIX: how do we know the content type? - //http->addHeader("Content-Type: text/llsd"); - if(mURL.empty()) - { - chain.push_back(LLIOPipe::ptr_t(new LLContextURLExtractor(http))); - } - else - { - http->setURL(mURL); - } - chain.push_back(http_pipe); - chain.push_back(service); - return true; - } - -protected: - LLURLRequest::ERequestAction mAction; - std::string mURL; -}; -#endif /** * External constants diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index e8e3459673..c38e38c900 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -41,6 +41,9 @@ #include "lltrans.h" #include "lluicolortable.h" +#define APP_HEADER_REGEX "((x-grid-location-info://[-\\w\\.]+/app)|(secondlife:///app))" + + LLUrlEntryBase::LLUrlEntryBase() : mColor(LLUIColorTable::instance().getColor("HTMLLinkColor")), mDisabledLink(false) @@ -303,10 +306,11 @@ std::string LLUrlEntrySLURL::getLocation(const std::string &url) const // // LLUrlEntryAgent Describes a Second Life agent Url, e.g., // secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about +// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about // LLUrlEntryAgent::LLUrlEntryAgent() { - mPattern = boost::regex("secondlife:///app/agent/[\\da-f-]+/\\w+", + mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/\\w+", boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_agent.xml"; mIcon = "Generic_Person"; @@ -418,10 +422,11 @@ std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCa // LLUrlEntryGroup Describes a Second Life group Url, e.g., // secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about // secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/inspect +// x-grid-location-info://lincoln.lindenlab.com/app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/inspect // LLUrlEntryGroup::LLUrlEntryGroup() { - mPattern = boost::regex("secondlife:///app/group/[\\da-f-]+/\\w+", + mPattern = boost::regex(APP_HEADER_REGEX "/group/[\\da-f-]+/\\w+", boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_group.xml"; mIcon = "Generic_Group"; @@ -482,7 +487,8 @@ LLUrlEntryInventory::LLUrlEntryInventory() //*TODO: add supporting of inventory item names with whitespaces //this pattern cann't parse for example //secondlife:///app/inventory/0e346d8b-4433-4d66-a6b0-fd37083abc4c/select?name=name with spaces¶m2=value - mPattern = boost::regex("secondlife:///app/inventory/[\\da-f-]+/\\w+\\S*", + //x-grid-location-info://lincoln.lindenlab.com/app/inventory/0e346d8b-4433-4d66-a6b0-fd37083abc4c/select?name=name with spaces¶m2=value + mPattern = boost::regex(APP_HEADER_REGEX "/inventory/[\\da-f-]+/\\w+\\S*", boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_inventory.xml"; } @@ -496,10 +502,11 @@ std::string LLUrlEntryInventory::getLabel(const std::string &url, const LLUrlLab /// /// LLUrlEntryParcel Describes a Second Life parcel Url, e.g., /// secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about +/// x-grid-location-info://lincoln.lindenlab.com/app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about /// LLUrlEntryParcel::LLUrlEntryParcel() { - mPattern = boost::regex("secondlife:///app/parcel/[\\da-f-]+/about", + mPattern = boost::regex(APP_HEADER_REGEX "/parcel/[\\da-f-]+/about", boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_parcel.xml"; mTooltip = LLTrans::getString("TooltipParcelUrl"); @@ -515,7 +522,7 @@ std::string LLUrlEntryParcel::getLabel(const std::string &url, const LLUrlLabelC // LLUrlEntryPlace::LLUrlEntryPlace() { - mPattern = boost::regex("secondlife://\\S+/?(\\d+/\\d+/\\d+|\\d+/\\d+)/?", + mPattern = boost::regex("((x-grid-location-info://[-\\w\\.]+/region/)|(secondlife://))\\S+/?(\\d+/\\d+/\\d+|\\d+/\\d+)/?", boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_slurl.xml"; mTooltip = LLTrans::getString("TooltipSLURL"); @@ -560,10 +567,11 @@ std::string LLUrlEntryPlace::getLocation(const std::string &url) const // // LLUrlEntryTeleport Describes a Second Life teleport Url, e.g., // secondlife:///app/teleport/Ahern/50/50/50/ +// x-grid-location-info://lincoln.lindenlab.com/app/teleport/Ahern/50/50/50/ // LLUrlEntryTeleport::LLUrlEntryTeleport() { - mPattern = boost::regex("secondlife:///app/teleport/\\S+(/\\d+)?(/\\d+)?(/\\d+)?/?\\S*", + mPattern = boost::regex(APP_HEADER_REGEX "/teleport/\\S+(/\\d+)?(/\\d+)?(/\\d+)?/?\\S*", boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_teleport.xml"; mTooltip = LLTrans::getString("TooltipTeleportUrl"); @@ -581,7 +589,12 @@ std::string LLUrlEntryTeleport::getLabel(const std::string &url, const LLUrlLabe LLURI uri(url); LLSD path_array = uri.pathArray(); S32 path_parts = path_array.size(); - const std::string label = LLTrans::getString("SLurlLabelTeleport"); + std::string host = uri.hostName(); + std::string label = LLTrans::getString("SLurlLabelTeleport"); + if (!host.empty()) + { + label += " " + host; + } if (path_parts == 6) { // handle teleport url with (X,Y,Z) coordinates @@ -680,7 +693,7 @@ std::string LLUrlEntrySLLabel::getTooltip(const std::string &string) const // LLUrlEntryWorldMap::LLUrlEntryWorldMap() { - mPattern = boost::regex("secondlife:///app/worldmap/\\S+/?(\\d+)?/?(\\d+)?/?(\\d+)?/?\\S*", + mPattern = boost::regex(APP_HEADER_REGEX "/worldmap/\\S+/?(\\d+)?/?(\\d+)?/?(\\d+)?/?\\S*", boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_map.xml"; mTooltip = LLTrans::getString("TooltipMapUrl"); diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp index cbb303a059..4463b6cc6f 100644 --- a/indra/llui/tests/llurlentry_test.cpp +++ b/indra/llui/tests/llurlentry_test.cpp @@ -286,6 +286,13 @@ namespace tut "XXX secondlife:///App/AGENT/0E346D8B-4433-4d66-a6b0-fd37083abc4c/foobar", "secondlife:///App/AGENT/0E346D8B-4433-4d66-a6b0-fd37083abc4c/foobar"); + testRegex("Standalone Agent Url ", url, + "x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about", + "x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); + + testRegex("Standalone Agent Url Multicase with Text", url, + "M x-grid-location-info://lincoln.lindenlab.com/app/AGENT/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about M", + "x-grid-location-info://lincoln.lindenlab.com/app/AGENT/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); } template<> template<> @@ -315,6 +322,15 @@ namespace tut testRegex("Group Url multicase", url, "XXX secondlife:///APP/Group/00005FF3-4044-c79f-9de8-fb28ae0df991/About XXX", "secondlife:///APP/Group/00005FF3-4044-c79f-9de8-fb28ae0df991/About"); + + testRegex("Standalone Group Url ", url, + "x-grid-location-info://lincoln.lindenlab.com/app/group/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about", + "x-grid-location-info://lincoln.lindenlab.com/app/group/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); + + testRegex("Standalone Group Url Multicase ith Text", url, + "M x-grid-location-info://lincoln.lindenlab.com/app/GROUP/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about M", + "x-grid-location-info://lincoln.lindenlab.com/app/GROUP/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); + } template<> template<> @@ -361,7 +377,11 @@ namespace tut // DEV-35459: SLURLs and teleport Links not parsed properly testRegex("SLURL with quote", url, "XXX secondlife://A'ksha%20Oasis/41/166/701 XXX", - "secondlife://A%27ksha%20Oasis/41/166/701"); + "secondlife://A%27ksha%20Oasis/41/166/701"); + + testRegex("Standalone All Hands (50,50) [2] with text", url, + "XXX x-grid-location-info://lincoln.lindenlab.com/region/All%20Hands/50/50/50 XXX", + "x-grid-location-info://lincoln.lindenlab.com/region/All%20Hands/50/50/50"); } template<> template<> @@ -461,6 +481,10 @@ namespace tut testRegex("Teleport url with quote", url, "XXX secondlife:///app/teleport/A'ksha%20Oasis/41/166/701 XXX", "secondlife:///app/teleport/A%27ksha%20Oasis/41/166/701"); + + testRegex("Standalone All Hands", url, + "XXX x-grid-location-info://lincoln.lindenlab.com/app/teleport/All%20Hands/50/50/50 XXX", + "x-grid-location-info://lincoln.lindenlab.com/app/teleport/All%20Hands/50/50/50"); } template<> template<> diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp index da4abde451..b4ee42ef3a 100644 --- a/indra/llvfs/lldir.cpp +++ b/indra/llvfs/lldir.cpp @@ -459,7 +459,6 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd } //llinfos << "*** EXPANDED FILENAME: <" << expanded_filename << ">" << llendl; - return expanded_filename; } @@ -565,27 +564,23 @@ std::string LLDir::getForbiddenFileChars() return "\\/:*?\"<>|"; } -void LLDir::setLindenUserDir(const std::string &first, const std::string &last) +void LLDir::setLindenUserDir(const std::string &username) { - // if both first and last aren't set, that's bad. - if (!first.empty() && !last.empty()) + // if the username isn't set, that's bad + if (!username.empty()) { // some platforms have case-sensitive filesystems, so be // utterly consistent with our firstname/lastname case. - std::string firstlower(first); - LLStringUtil::toLower(firstlower); - std::string lastlower(last); - LLStringUtil::toLower(lastlower); + std::string userlower(username); + LLStringUtil::toLower(userlower); + LLStringUtil::replaceChar(userlower, ' ', '_'); mLindenUserDir = getOSUserAppDir(); mLindenUserDir += mDirDelimiter; - mLindenUserDir += firstlower; - mLindenUserDir += "_"; - mLindenUserDir += lastlower; - llinfos << "Got name for LLDir::setLindenUserDir(first='" << first << "', last='" << last << "')" << llendl; + mLindenUserDir += userlower; } else { - llerrs << "Invalid name for LLDir::setLindenUserDir(first='" << first << "', last='" << last << "')" << llendl; + llerrs << "NULL name for LLDir::setLindenUserDir" << llendl; } dumpCurrentDirectories(); @@ -603,27 +598,25 @@ void LLDir::setChatLogsDir(const std::string &path) } } -void LLDir::setPerAccountChatLogsDir(const std::string &first, const std::string &last) +void LLDir::setPerAccountChatLogsDir(const std::string &username) { // if both first and last aren't set, assume we're grabbing the cached dir - if (!first.empty() && !last.empty()) + if (!username.empty()) { // some platforms have case-sensitive filesystems, so be // utterly consistent with our firstname/lastname case. - std::string firstlower(first); - LLStringUtil::toLower(firstlower); - std::string lastlower(last); - LLStringUtil::toLower(lastlower); + std::string userlower(username); + LLStringUtil::toLower(userlower); + LLStringUtil::replaceChar(userlower, ' ', '_'); mPerAccountChatLogsDir = getChatLogsDir(); mPerAccountChatLogsDir += mDirDelimiter; - mPerAccountChatLogsDir += firstlower; - mPerAccountChatLogsDir += "_"; - mPerAccountChatLogsDir += lastlower; + mPerAccountChatLogsDir += userlower; } else { - llwarns << "Invalid name for LLDir::setPerAccountChatLogsDir" << llendl; + llerrs << "NULL name for LLDir::setPerAccountChatLogsDir" << llendl; } + } void LLDir::setSkinFolder(const std::string &skin_folder) diff --git a/indra/llvfs/lldir.h b/indra/llvfs/lldir.h index 9067d75bac..05d5efc66f 100644 --- a/indra/llvfs/lldir.h +++ b/indra/llvfs/lldir.h @@ -137,8 +137,8 @@ class LLDir static std::string getForbiddenFileChars(); virtual void setChatLogsDir(const std::string &path); // Set the chat logs dir to this user's dir - virtual void setPerAccountChatLogsDir(const std::string &first, const std::string &last); // Set the per user chat log directory. - virtual void setLindenUserDir(const std::string &first, const std::string &last); // Set the linden user dir to this user's dir + virtual void setPerAccountChatLogsDir(const std::string &username); // Set the per user chat log directory. + virtual void setLindenUserDir(const std::string &username); // Set the linden user dir to this user's dir virtual void setSkinFolder(const std::string &skin_folder); virtual bool setCacheDir(const std::string &path); diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 5c7e9c8db2..1a77d6e58e 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -7,6 +7,7 @@ include(Boost) include(BuildVersion) include(DBusGlib) include(DirectX) +include(OpenSSL) include(DragDrop) include(ELFIO) include(FMOD) @@ -370,6 +371,8 @@ set(viewer_SOURCE_FILES llscrollingpanelparam.cpp llsearchcombobox.cpp llsearchhistory.cpp + llsecapi.cpp + llsechandler_basic.cpp llselectmgr.cpp llsidepanelappearance.cpp llsidepanelinventory.cpp @@ -444,7 +447,6 @@ set(viewer_SOURCE_FILES llurldispatcherlistener.cpp llurlhistory.cpp llurllineeditorctrl.cpp - llurlsimstring.cpp llurlwhitelist.cpp llvectorperfoptions.cpp llversioninfo.cpp @@ -511,7 +513,9 @@ set(viewer_SOURCE_FILES llvoground.cpp llvoicechannel.cpp llvoiceclient.cpp + llvoicedw.cpp llvoicevisualizer.cpp + llvoicevivox.cpp llvoinventorylistener.cpp llvopartgroup.cpp llvosky.cpp @@ -870,6 +874,8 @@ set(viewer_HEADER_FILES llscrollingpanelparam.h llsearchcombobox.h llsearchhistory.h + llsecapi.h + llsechandler_basic.h llselectmgr.h llsidepanelappearance.h llsidepanelinventory.h @@ -946,7 +952,6 @@ set(viewer_HEADER_FILES llurldispatcherlistener.h llurlhistory.h llurllineeditorctrl.h - llurlsimstring.h llurlwhitelist.h llvectorperfoptions.h llversioninfo.h @@ -1010,7 +1015,9 @@ set(viewer_HEADER_FILES llvoground.h llvoicechannel.h llvoiceclient.h + llvoicedw.h llvoicevisualizer.h + llvoicevivox.h llvoinventorylistener.h llvopartgroup.h llvosky.h @@ -1401,8 +1408,8 @@ if (WINDOWS) ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/libtcmalloc_minimal.dll ${SHARED_LIB_STAGING_DIR}/Debug/libtcmalloc_minimal-debug.dll ) - endif(USE_GOOGLE_PERFTOOLS) - + endif(USE_GOOGLE_PERFTOOLS) + set(COPY_INPUT_DEPENDECIES # The following commented dependencies are determined at variably at build time. Can't do this here. @@ -1619,6 +1626,8 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${WINDOWS_LIBRARIES} ${XMLRPCEPI_LIBRARIES} ${ELFIO_LIBRARIES} + ${OPENSSL_LIBRARIES} + ${CRYPTO_LIBRARIES} ${LLLOGIN_LIBRARIES} ${GOOGLE_PERFTOOLS_LIBRARIES} ) @@ -1795,6 +1804,43 @@ if (LL_TESTS) "${CMAKE_SOURCE_DIR}/llmessage/tests/test_llsdmessage_peer.py" ) + set(test_libs + ${LLMESSAGE_LIBRARIES} + ${WINDOWS_LIBRARIES} + ${LLVFS_LIBRARIES} + ${LLMATH_LIBRARIES} + ${LLCOMMON_LIBRARIES} + ${GOOGLEMOCK_LIBRARIES} + ${OPENSSL_LIBRARIES} + ${CRYPTO_LIBRARIES} + ) + + LL_ADD_INTEGRATION_TEST(llsechandler_basic + llsechandler_basic.cpp + "${test_libs}" + ) + + LL_ADD_INTEGRATION_TEST(llsecapi + llsecapi.cpp + "${test_libs}" + ) + + set(llslurl_test_sources + llslurl.cpp + llviewernetwork.cpp + ) + + + LL_ADD_INTEGRATION_TEST(llslurl + "${llslurl_test_sources}" + "${test_libs}" + ) + + LL_ADD_INTEGRATION_TEST(llviewernetwork + llviewernetwork.cpp + "${test_libs}" + ) + #ADD_VIEWER_BUILD_TEST(llmemoryview viewer) #ADD_VIEWER_BUILD_TEST(llagentaccess viewer) #ADD_VIEWER_BUILD_TEST(llworldmap viewer) @@ -1802,6 +1848,7 @@ if (LL_TESTS) #ADD_VIEWER_BUILD_TEST(lltextureinfo viewer) #ADD_VIEWER_BUILD_TEST(lltextureinfodetails viewer) #ADD_VIEWER_BUILD_TEST(lltexturestatsuploader viewer) + endif (LL_TESTS) diff --git a/indra/newview/Info-SecondLife.plist b/indra/newview/Info-SecondLife.plist index 38ebb22b84..a800f4ba79 100644 --- a/indra/newview/Info-SecondLife.plist +++ b/indra/newview/Info-SecondLife.plist @@ -18,6 +18,33 @@ <string>APPL</string> <key>CFBundleSignature</key> <string>????</string> + <key>CFBundleDocumentTypes</key> + <array> + <dict> + <key>CFBundleTypeExtensions</key> + <array> + <string>slurl</string> + </array> + <key>CFBundleTypeIconFile</key> + <string>seconlife</string> + <key>CFBundleTypeMIMETypes</key> + <array> + <string>application/x-grid-location-info</string> + </array> + <key>CFBundleTypeName</key> + <string>Secondlife SLURL</string> + <key>CFBundleTypeOSTypes</key> + <array> + <string>SLRL</string> + </array> + <key>CFBundleTypeRole</key> + <string>Viewer</string> + <key>LSTypeIsPackage</key> + <true/> + <key>NSDocumentClass</key> + <string>SecondLifeSLURL</string> + </dict> + </array> <key>CFBundleURLTypes</key> <array> <dict> @@ -26,6 +53,7 @@ <key>CFBundleURLSchemes</key> <array> <string>secondlife</string> + <string>x-grid-location-info</string> </array> <key>LSIsAppleDefaultForScheme</key> <true/> diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 73fb24e4eb..9a02777697 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1264,6 +1264,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>CertStore</key> + <map> + <key>Comment</key> + <string>Specifies the Certificate Store for certificate trust verification</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>default</string> + </map> <key>ChatBarStealsFocus</key> <map> <key>Comment</key> @@ -1640,6 +1651,17 @@ <key>Value</key> <integer>1</integer> </map> + <key>CurrentGrid</key> + <map> + <key>Comment</key> + <string>Currently Selected Grid</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string></string> + </map> <key>CustomServer</key> <map> <key>Comment</key> @@ -2366,6 +2388,29 @@ <key>Value</key> <integer>0</integer> </map> + <key>DefaultFemaleAvatar</key> + <map> + <key>Comment</key> + <string>Default Female Avatar</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>Female Shape & Outfit</string> + </map> + <key>DefaultMaleAvatar</key> + <map> + <key>Comment</key> + <string>Default Male Avatar</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>Male Shape & Outfit</string> + </map> + <key>DefaultObjectTexture</key> <map> <key>Comment</key> @@ -3431,7 +3476,7 @@ <key>Type</key> <string>Boolean</string> <key>Value</key> - <integer>0</integer> + <integer>1</integer> </map> <key>ForceMandatoryUpdate</key> <map> @@ -7685,6 +7730,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>SecondLifeEnterprise</key> + <map> + <key>Comment</key> + <string>Enables Second Life Enterprise features</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>SelectMovableOnly</key> <map> <key>Comment</key> @@ -8489,7 +8545,7 @@ <key>Type</key> <string>Boolean</string> <key>Value</key> - <integer>0</integer> + <integer>1</integer> </map> <key>ShowTangentBasis</key> <map> @@ -10393,6 +10449,17 @@ <key>Value</key> <string></string> </map> + <key>VivoxDebugSIPURIHostName</key> + <map> + <key>Comment</key> + <string>Hostname portion of vivox SIP URIs (empty string for the default).</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string></string> + </map> <key>VivoxDebugVoiceAccountServerURI</key> <map> <key>Comment</key> @@ -10404,6 +10471,28 @@ <key>Value</key> <string></string> </map> + <key>VivoxVoiceHost</key> + <map> + <key>Comment</key> + <string>Client SLVoice host to connect to</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>127.0.0.1</string> + </map> + <key>VivoxVoicePort</key> + <map> + <key>Comment</key> + <string>Client SLVoice port to connect to</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>44125</integer> + </map> <key>VoiceCallsFriendsOnly</key> <map> <key>Comment</key> @@ -10536,6 +10625,17 @@ <key>Value</key> <string>Default</string> </map> + <key>VoiceLogFile</key> + <map> + <key>Comment</key> + <string>Log file to use when launching the voice daemon</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string></string> + </map> <key>VoiceOutputAudioDevice</key> <map> <key>Comment</key> @@ -10580,6 +10680,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>VoiceServerType</key> + <map> + <key>Comment</key> + <string>The type of voice server to connect to.</string> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>vivox</string> + </map> <key>WLSkyDetail</key> <map> <key>Comment</key> diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi index a7322749ca..b7b4c54001 100644 --- a/indra/newview/installers/windows/installer_template.nsi +++ b/indra/newview/installers/windows/installer_template.nsi @@ -797,6 +797,12 @@ WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}\DefaultIcon" "" '"$INSTDIR\$INSTEXE"' ;; URL param must be last item passed to viewer, it ignores subsequent params ;; to avoid parameter injection attacks. WriteRegExpandStr HKEY_CLASSES_ROOT "${URLNAME}\shell\open\command" "" '"$INSTDIR\$INSTEXE" $INSTFLAGS -url "%1"' +WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info"(default)" "URL:Second Life" +WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info" "URL Protocol" "" +WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info\DefaultIcon" "" '"$INSTDIR\$INSTEXE"' +;; URL param must be last item passed to viewer, it ignores subsequent params +;; to avoid parameter injection attacks. +WriteRegExpandStr HKEY_CLASSES_ROOT "x-grid-location-info\shell\open\command" "" '"$INSTDIR\$INSTEXE" $INSTFLAGS -url "%1"' ; write out uninstaller WriteUninstaller "$INSTDIR\uninst.exe" diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 69d4bba16d..1ecd902616 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -3231,7 +3231,7 @@ bool LLAgent::teleportCore(bool is_local) // MBW -- Let the voice client know a teleport has begun so it can leave the existing channel. // This was breaking the case of teleporting within a single sim. Backing it out for now. -// gVoiceClient->leaveChannel(); +// LLVoiceClient::getInstance()->leaveChannel(); return true; } @@ -3375,7 +3375,7 @@ void LLAgent::setTeleportState(ETeleportState state) if (mTeleportState == TELEPORT_MOVING) { // We're outa here. Save "back" slurl. - mTeleportSourceSLURL = LLAgentUI::buildSLURL(); + LLAgentUI::buildSLURL(mTeleportSourceSLURL); } else if(mTeleportState == TELEPORT_ARRIVING) { diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index a460077b7e..32f9b00135 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -42,6 +42,7 @@ #include "llpointer.h" #include "lluicolor.h" #include "llvoavatardefines.h" +#include "llslurl.h" extern const BOOL ANIMATE; extern const U8 AGENT_STATE_TYPING; // Typing indication @@ -514,13 +515,13 @@ public: public: static void parseTeleportMessages(const std::string& xml_filename); - const std::string getTeleportSourceSLURL() const { return mTeleportSourceSLURL; } + const void getTeleportSourceSLURL(LLSLURL& slurl) const { slurl = mTeleportSourceSLURL; } public: // ! TODO ! Define ERROR and PROGRESS enums here instead of exposing the mappings. static std::map<std::string, std::string> sTeleportErrorMessages; static std::map<std::string, std::string> sTeleportProgressMessages; private: - std::string mTeleportSourceSLURL; // SLURL where last TP began + LLSLURL mTeleportSourceSLURL; // SLURL where last TP began //-------------------------------------------------------------------- // Teleport Actions diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index b3ed7c353e..7a8205acb5 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -53,7 +53,10 @@ void LLAgentListener::requestTeleport(LLSD const & event_data) const } else { - std::string url = LLSLURL::buildSLURL(event_data["regionname"], event_data["x"], event_data["y"], event_data["z"]); + std::string url = LLSLURL(event_data["regionname"], + LLVector3(event_data["x"].asReal(), + event_data["y"].asReal(), + event_data["z"].asReal())).getSLURLString(); LLURLDispatcher::dispatch(url, NULL, false); } } diff --git a/indra/newview/llagentui.cpp b/indra/newview/llagentui.cpp index c4597ad6f8..15d9f36b74 100644 --- a/indra/newview/llagentui.cpp +++ b/indra/newview/llagentui.cpp @@ -76,16 +76,15 @@ void LLAgentUI::buildFullname(std::string& name) } //static -std::string LLAgentUI::buildSLURL(const bool escaped /*= true*/) +void LLAgentUI::buildSLURL(LLSLURL& slurl, const bool escaped /*= true*/) { - std::string slurl; - LLViewerRegion *regionp = gAgent.getRegion(); - if (regionp) - { - LLVector3d agentPos = gAgent.getPositionGlobal(); - slurl = LLSLURL::buildSLURLfromPosGlobal(regionp->getName(), agentPos, escaped); - } - return slurl; + LLSLURL return_slurl; + LLViewerRegion *regionp = gAgent.getRegion(); + if (regionp) + { + return_slurl = LLSLURL(regionp->getName(), gAgent.getPositionGlobal()); + } + slurl = return_slurl; } //static diff --git a/indra/newview/llagentui.h b/indra/newview/llagentui.h index 3478793e38..577b752fbe 100644 --- a/indra/newview/llagentui.h +++ b/indra/newview/llagentui.h @@ -33,6 +33,8 @@ #ifndef LLAGENTUI_H #define LLAGENTUI_H +class LLSLURL; + class LLAgentUI { public: @@ -48,7 +50,7 @@ public: static void buildName(std::string& name); static void buildFullname(std::string &name); - static std::string buildSLURL(const bool escaped = true); + static void buildSLURL(LLSLURL& slurl, const bool escaped = true); //build location string using the current position of gAgent. static BOOL buildLocationString(std::string& str, ELocationFormat fmt = LOCATION_FORMAT_LANDMARK); //build location string using a region position of the avatar. diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 43c8c679c6..2a355474b1 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -153,7 +153,7 @@ #include "llworld.h" #include "llhudeffecttrail.h" #include "llvectorperfoptions.h" -#include "llurlsimstring.h" +#include "llslurl.h" #include "llwatchdog.h" // Included so that constants/settings might be initialized @@ -193,6 +193,9 @@ #include "llparcel.h" #include "llavatariconctrl.h" +// Include for security api initialization +#include "llsecapi.h" + // *FIX: These extern globals should be cleaned up. // The globals either represent state/config/resource-storage of either // this app, or another 'component' of the viewer. App globals should be @@ -507,35 +510,6 @@ public: } }; -void LLAppViewer::initGridChoice() -{ - // Load up the initial grid choice from: - // - hard coded defaults... - // - command line settings... - // - if dev build, persisted settings... - - // Set the "grid choice", this is specified by command line. - std::string grid_choice = gSavedSettings.getString("CmdLineGridChoice"); - LLViewerLogin::getInstance()->setGridChoice(grid_choice); - - // Load last server choice by default - // ignored if the command line grid choice has been set - if(grid_choice.empty()) - { - S32 server = gSavedSettings.getS32("ServerChoice"); - server = llclamp(server, 0, (S32)GRID_INFO_COUNT - 1); - if(server == GRID_INFO_OTHER) - { - std::string custom_server = gSavedSettings.getString("CustomServer"); - LLViewerLogin::getInstance()->setGridChoice(custom_server); - } - else if(server != (S32)GRID_INFO_NONE) - { - LLViewerLogin::getInstance()->setGridChoice((EGridInfo)server); - } - } -} - //virtual bool LLAppViewer::initSLURLHandler() { @@ -647,7 +621,6 @@ bool LLAppViewer::init() LLCurl::initClass(); initThreads(); - writeSystemInfo(); // Build a string representing the current version number. @@ -777,10 +750,6 @@ bool LLAppViewer::init() return false; } - // Always fetch the Ethernet MAC address, needed both for login - // and password load. - LLUUID::getNodeID(gMACAddress); - // Prepare for out-of-memory situations, during which we will crash on // purpose and save a dump. #if LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD && LL_USE_SMARTHEAP @@ -892,6 +861,7 @@ bool LLAppViewer::init() } } + // save the graphics card gDebugInfo["GraphicsCard"] = LLFeatureManager::getInstance()->getGPUString(); @@ -902,6 +872,17 @@ bool LLAppViewer::init() gSimFrames = (F32)gFrameCount; LLViewerJoystick::getInstance()->init(false); + + try { + initializeSecHandler(); + } + catch (LLProtectedDataException ex) + { + LLNotificationsUtil::add("CorruptedProtectedDataStore"); + } + LLHTTPClient::setCertVerifyCallback(secapiSSLCertVerifyCallback); + + gGLActive = FALSE; if (gSavedSettings.getBOOL("QAMode") && gSavedSettings.getS32("QAModeEventHostPort") > 0) { @@ -936,13 +917,11 @@ bool LLAppViewer::mainLoop() gServicePump = new LLPumpIO(gAPRPoolp); LLHTTPClient::setPump(*gServicePump); LLCurl::setCAFile(gDirUtilp->getCAFile()); - LLCurl::setSSLVerify(! gSavedSettings.getBOOL("NoVerifySSLCert")); - + // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated. LLVoiceChannel::initClass(); - LLVoiceClient::init(gServicePump); - + LLVoiceClient::getInstance()->init(gServicePump); LLTimer frameTimer,idleTimer; LLTimer debugTime; LLViewerJoystick* joystick(LLViewerJoystick::getInstance()); @@ -1273,7 +1252,7 @@ bool LLAppViewer::cleanup() // to ensure shutdown order LLMortician::setZealous(TRUE); - LLVoiceClient::terminate(); + LLVoiceClient::getInstance()->terminate(); disconnectViewer(); @@ -1472,13 +1451,6 @@ bool LLAppViewer::cleanup() llinfos << "Saving Data" << llendflush; - // Quitting with "Remember Password" turned off should always stomp your - // saved password, whether or not you successfully logged in. JC - if (!gSavedSettings.getBOOL("RememberPassword")) - { - LLStartUp::deletePasswordFromDisk(); - } - // Store the time of our current logoff gSavedPerAccountSettings.setU32("LastLogoff", time_corrected()); @@ -2047,7 +2019,6 @@ bool LLAppViewer::initConfiguration() } } - initGridChoice(); // If we have specified crash on startup, set the global so we'll trigger the crash at the right time if(clp.hasOption("crashonstartup")) @@ -2141,30 +2112,17 @@ bool LLAppViewer::initConfiguration() // injection and steal passwords. Phoenix. SL-55321 if(clp.hasOption("url")) { - std::string slurl = clp.getOption("url")[0]; - if (LLSLURL::isSLURLCommand(slurl)) - { - LLStartUp::sSLURLCommand = slurl; - } - else - { - LLURLSimString::setString(slurl); - } + LLStartUp::setStartSLURL(LLSLURL(clp.getOption("url")[0])); + if(LLStartUp::getStartSLURL().getType() == LLSLURL::LOCATION) + { + LLGridManager::getInstance()->setGridChoice(LLStartUp::getStartSLURL().getGrid()); + + } } else if(clp.hasOption("slurl")) { - std::string slurl = clp.getOption("slurl")[0]; - if(LLSLURL::isSLURL(slurl)) - { - if (LLSLURL::isSLURLCommand(slurl)) - { - LLStartUp::sSLURLCommand = slurl; - } - else - { - LLURLSimString::setString(slurl); - } - } + LLSLURL start_slurl(clp.getOption("slurl")[0]); + LLStartUp::setStartSLURL(start_slurl); } const LLControlVariable* skinfolder = gSavedSettings.getControl("SkinCurrent"); @@ -2245,18 +2203,10 @@ bool LLAppViewer::initConfiguration() // don't call anotherInstanceRunning() when doing URL handoff, as // it relies on checking a marker file which will not work when running // out of different directories - std::string slurl; - if (!LLStartUp::sSLURLCommand.empty()) - { - slurl = LLStartUp::sSLURLCommand; - } - else if (LLURLSimString::parse()) - { - slurl = LLURLSimString::getURL(); - } - if (!slurl.empty()) + + if (LLStartUp::getStartSLURL().isValid()) { - if (sendURLToOtherInstance(slurl)) + if (sendURLToOtherInstance(LLStartUp::getStartSLURL().getSLURLString())) { // successfully handed off URL to existing instance, exit return false; @@ -2312,9 +2262,9 @@ bool LLAppViewer::initConfiguration() // need to do this here - need to have initialized global settings first std::string nextLoginLocation = gSavedSettings.getString( "NextLoginLocation" ); - if ( nextLoginLocation.length() ) + if ( !nextLoginLocation.empty() ) { - LLURLSimString::setString( nextLoginLocation ); + LLStartUp::setStartSLURL(LLSLURL(nextLoginLocation)); }; gLastRunVersion = gSavedSettings.getString("LastRunVersion"); @@ -2535,7 +2485,7 @@ void LLAppViewer::writeSystemInfo() // The user is not logged on yet, but record the current grid choice login url // which may have been the intended grid. This can b - gDebugInfo["GridName"] = LLViewerLogin::getInstance()->getGridLabel(); + gDebugInfo["GridName"] = LLGridManager::getInstance()->getGridLabel(); // *FIX:Mani - move this ddown in llappviewerwin32 #ifdef LL_WINDOWS @@ -3886,7 +3836,7 @@ void LLAppViewer::sendLogoutRequest() gLogoutMaxTime = LOGOUT_REQUEST_TIME; mLogoutRequestSent = TRUE; - gVoiceClient->leaveChannel(); + LLVoiceClient::getInstance()->leaveChannel(); //Set internal status variables and marker files gLogoutInProgress = TRUE; @@ -4306,7 +4256,7 @@ void LLAppViewer::launchUpdater() #endif // *TODO change userserver to be grid on both viewer and sim, since // userserver no longer exists. - query_map["userserver"] = LLViewerLogin::getInstance()->getGridLabel(); + query_map["userserver"] = LLGridManager::getInstance()->getGridLabel(); query_map["channel"] = gSavedSettings.getString("VersionChannelName"); // *TODO constantize this guy // *NOTE: This URL is also used in win_setup/lldownloader.cpp @@ -4319,10 +4269,10 @@ void LLAppViewer::launchUpdater() LLAppViewer::sUpdaterInfo = new LLAppViewer::LLUpdaterInfo() ; // if a sim name was passed in via command line parameter (typically through a SLURL) - if ( LLURLSimString::sInstance.mSimString.length() ) + if ( LLStartUp::getStartSLURL().getType() == LLSLURL::LOCATION ) { // record the location to start at next time - gSavedSettings.setString( "NextLoginLocation", LLURLSimString::sInstance.mSimString ); + gSavedSettings.setString( "NextLoginLocation", LLStartUp::getStartSLURL().getSLURLString()); }; #if LL_WINDOWS diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index a915b7fa50..27e8bec1d5 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -191,7 +191,6 @@ private: bool initThreads(); // Initialize viewer threads, return false on failure. bool initConfiguration(); // Initialize settings from the command line/config file. - void initGridChoice(); bool initCache(); // Initialize local client cache. diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp index d34bcb4a68..78b0f7ba83 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -604,7 +604,7 @@ void LLAppViewerLinux::handleCrashReporting(bool reportFreeze) {cmd.c_str(), ask_dialog, "-user", - (char*)LLViewerLogin::getInstance()->getGridLabel().c_str(), + (char*)LLGridManager::getInstance()->getGridLabel().c_str(), "-name", LLAppViewer::instance()->getSecondLifeTitle().c_str(), NULL}; diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp index 80d9b14345..58d28883c6 100644 --- a/indra/newview/llappviewermacosx.cpp +++ b/indra/newview/llappviewermacosx.cpp @@ -44,7 +44,6 @@ #include "llviewernetwork.h" #include "llviewercontrol.h" #include "llmd5.h" -#include "llurlsimstring.h" #include "llfloaterworldmap.h" #include "llurldispatcher.h" #include <Carbon/Carbon.h> diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index 4075ad8ee2..9f3f401630 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -274,7 +274,7 @@ bool LLAvatarActions::isCalling(const LLUUID &id) //static bool LLAvatarActions::canCall() { - return LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking(); + return LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking(); } // static diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp index 34cb6fd2eb..d1517cad8c 100644 --- a/indra/newview/llbottomtray.cpp +++ b/indra/newview/llbottomtray.cpp @@ -325,7 +325,7 @@ void LLBottomTray::onChange(EStatusType status, const std::string &channelURI, b // skipped to avoid button blinking if (status != STATUS_JOINING && status!= STATUS_LEFT_CHANNEL) { - mSpeakBtn->setFlyoutBtnEnabled(LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking()); + mSpeakBtn->setFlyoutBtnEnabled(LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking()); } } @@ -478,7 +478,7 @@ BOOL LLBottomTray::postBuild() mSpeakBtn->setShowToolTip( getString("VoiceControlBtnToolTip") ); // Registering Chat Bar to receive Voice client status change notifications. - gVoiceClient->addObserver(this); + LLVoiceClient::getInstance()->addObserver(this); mObjectDefaultWidthMap[RS_BUTTON_GESTURES] = mGesturePanel->getRect().getWidth(); mObjectDefaultWidthMap[RS_BUTTON_MOVEMENT] = mMovementPanel->getRect().getWidth(); diff --git a/indra/newview/llcallfloater.cpp b/indra/newview/llcallfloater.cpp index 4ea3c61ab2..215f1b95aa 100644 --- a/indra/newview/llcallfloater.cpp +++ b/indra/newview/llcallfloater.cpp @@ -133,9 +133,9 @@ LLCallFloater::~LLCallFloater() // Don't use LLVoiceClient::getInstance() here // singleton MAY have already been destroyed. - if(gVoiceClient) + if(LLVoiceClient::getInstance()) { - gVoiceClient->removeObserver(this); + LLVoiceClient::getInstance()->removeObserver(this); } LLTransientFloaterMgr::getInstance()->removeControlView(this); } @@ -191,7 +191,7 @@ void LLCallFloater::draw() // Seems this is a problem somewhere in Voice Client (LLVoiceClient::participantAddedEvent) // onChange(); - bool is_moderator_muted = gVoiceClient->getIsModeratorMuted(gAgentID); + bool is_moderator_muted = LLVoiceClient::getInstance()->getIsModeratorMuted(gAgentID); if (mIsModeratorMutedVoice != is_moderator_muted) { @@ -209,7 +209,6 @@ void LLCallFloater::draw() void LLCallFloater::onChange() { if (NULL == mParticipants) return; - updateParticipantsVoiceState(); // Add newly joined participants. @@ -239,11 +238,11 @@ void LLCallFloater::updateSession() LLVoiceChannel* voice_channel = LLVoiceChannel::getCurrentVoiceChannel(); if (voice_channel) { - lldebugs << "Current voice channel: " << voice_channel->getSessionID() << llendl; + LL_DEBUGS("Voice") << "Current voice channel: " << voice_channel->getSessionID() << LL_ENDL; if (mSpeakerManager && voice_channel->getSessionID() == mSpeakerManager->getSessionID()) { - lldebugs << "Speaker manager is already set for session: " << voice_channel->getSessionID() << llendl; + LL_DEBUGS("Voice") << "Speaker manager is already set for session: " << voice_channel->getSessionID() << LL_ENDL; return; } else @@ -253,7 +252,6 @@ void LLCallFloater::updateSession() } const LLUUID& session_id = voice_channel ? voice_channel->getSessionID() : LLUUID::null; - lldebugs << "Set speaker manager for session: " << session_id << llendl; LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id); if (im_session) @@ -293,7 +291,7 @@ void LLCallFloater::updateSession() { // by default let show nearby chat participants mSpeakerManager = LLLocalSpeakerMgr::getInstance(); - lldebugs << "Set DEFAULT speaker manager" << llendl; + LL_DEBUGS("Voice") << "Set DEFAULT speaker manager" << LL_ENDL; mVoiceType = VC_LOCAL_CHAT; } @@ -472,16 +470,15 @@ void LLCallFloater::updateAgentModeratorState() static void get_voice_participants_uuids(uuid_vec_t& speakers_uuids) { // Get a list of participants from VoiceClient - LLVoiceClient::participantMap *voice_map = gVoiceClient->getParticipantList(); - if (voice_map) + std::set<LLUUID> participants; + LLVoiceClient::getInstance()->getParticipantList(participants); + + for (std::set<LLUUID>::const_iterator iter = participants.begin(); + iter != participants.end(); ++iter) { - for (LLVoiceClient::participantMap::const_iterator iter = voice_map->begin(); - iter != voice_map->end(); ++iter) - { - LLUUID id = (*iter).second->mAvatarID; - speakers_uuids.push_back(id); - } + speakers_uuids.push_back(*iter); } + } void LLCallFloater::initParticipantsVoiceState() @@ -557,7 +554,7 @@ void LLCallFloater::updateParticipantsVoiceState() uuid_vec_t::iterator speakers_iter = std::find(speakers_uuids.begin(), speakers_uuids.end(), participant_id); - lldebugs << "processing speaker: " << item->getAvatarName() << ", " << item->getAvatarId() << llendl; + LL_DEBUGS("Voice") << "processing speaker: " << item->getAvatarName() << ", " << item->getAvatarId() << LL_ENDL; // If an avatarID assigned to a panel is found in a speakers list // obtained from VoiceClient we assign the JOINED status to the owner @@ -727,7 +724,7 @@ void LLCallFloater::connectToChannel(LLVoiceChannel* channel) void LLCallFloater::onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state) { // check is voice operational and if it doesn't work hide VCP (EXT-4397) - if(LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking()) + if(LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking()) { updateState(new_state); } diff --git a/indra/newview/llcallingcard.cpp b/indra/newview/llcallingcard.cpp index 79a2631c31..1a6c11fa73 100644 --- a/indra/newview/llcallingcard.cpp +++ b/indra/newview/llcallingcard.cpp @@ -700,6 +700,7 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online) args["FIRST"] = first; args["LAST"] = last; } + } } else diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index f5faeca126..c043db81df 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -657,20 +657,19 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL if ( chat.mSourceType == CHAT_SOURCE_OBJECT && chat.mFromID.notNull()) { // for object IMs, create a secondlife:///app/objectim SLapp - std::string url = LLSLURL::buildCommand("objectim", chat.mFromID, ""); + std::string url = LLSLURL("objectim", chat.mFromID, "").getSLURLString(); url += "?name=" + chat.mFromName; url += "&owner=" + args["owner_id"].asString(); std::string slurl = args["slurl"].asString(); if (slurl.empty()) { - LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent); - if (region) - { - S32 x, y, z; - LLSLURL::globalPosToXYZ(LLVector3d(chat.mPosAgent), x, y, z); - slurl = region->getName() + llformat("/%d/%d/%d", x, y, z); - } + LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent); + if(region) + { + LLSLURL region_slurl(region->getName(), chat.mPosAgent); + slurl = region_slurl.getLocationString(); + } } url += "&slurl=" + slurl; diff --git a/indra/newview/llcurrencyuimanager.cpp b/indra/newview/llcurrencyuimanager.cpp index be6c15eab4..fd3df359bd 100644 --- a/indra/newview/llcurrencyuimanager.cpp +++ b/indra/newview/llcurrencyuimanager.cpp @@ -284,7 +284,7 @@ void LLCurrencyUIManager::Impl::startTransaction(TransactionType type, static std::string transactionURI; if (transactionURI.empty()) { - transactionURI = LLViewerLogin::getInstance()->getHelperURI() + "currency.php"; + transactionURI = LLGridManager::getInstance()->getHelperURI() + "currency.php"; } delete mTransaction; diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp index ef69f39ad2..56bc4a7933 100644 --- a/indra/newview/llfloaterabout.cpp +++ b/indra/newview/llfloaterabout.cpp @@ -266,8 +266,18 @@ LLSD LLFloaterAbout::getInfo() info["J2C_VERSION"] = LLImageJ2C::getEngineInfo(); bool want_fullname = true; info["AUDIO_DRIVER_VERSION"] = gAudiop ? LLSD(gAudiop->getDriverName(want_fullname)) : LLSD(); - info["VIVOX_VERSION"] = gVoiceClient ? gVoiceClient->getAPIVersion() : LLTrans::getString("NotConnected"); - + if(LLVoiceClient::getInstance()->voiceEnabled()) + { + LLVoiceVersionInfo version = LLVoiceClient::getInstance()->getVersion(); + std::ostringstream version_string; + version_string << version.serverType << " " << version.serverVersion << std::endl; + info["VOICE_VERSION"] = version_string.str(); + } + else + { + info["VOICE_VERSION"] = LLTrans::getString("NotConnected"); + } + // TODO: Implement media plugin version query info["QT_WEBKIT_VERSION"] = "4.6 (version number hard-coded)"; diff --git a/indra/newview/llfloaterbuyland.cpp b/indra/newview/llfloaterbuyland.cpp index d37bc01885..464b3a7214 100644 --- a/indra/newview/llfloaterbuyland.cpp +++ b/indra/newview/llfloaterbuyland.cpp @@ -830,7 +830,7 @@ void LLFloaterBuyLandUI::updateNames() else { mParcelSellerName = - LLSLURL::buildCommand("agent", parcelp->getOwnerID(), "inspect"); + LLSLURL("agent", parcelp->getOwnerID(), "inspect").getSLURLString(); } } @@ -859,7 +859,7 @@ void LLFloaterBuyLandUI::startTransaction(TransactionType type, const LLXMLRPCVa static std::string transaction_uri; if (transaction_uri.empty()) { - transaction_uri = LLViewerLogin::getInstance()->getHelperURI() + "landtool.php"; + transaction_uri = LLGridManager::getInstance()->getHelperURI() + "landtool.php"; } const char* method; diff --git a/indra/newview/llfloaterchat.cpp b/indra/newview/llfloaterchat.cpp index cdb9b8edb8..882d12f68e 100644 --- a/indra/newview/llfloaterchat.cpp +++ b/indra/newview/llfloaterchat.cpp @@ -166,7 +166,7 @@ void add_timestamped_line(LLViewerTextEditor* edit, LLChat chat, const LLColor4& if (chat.mSourceType == CHAT_SOURCE_AGENT && chat.mFromID != LLUUID::null) { - chat.mURL = LLSLURL::buildCommand("agent", chat.mFromID, "inspect"); + chat.mURL = LLSLURL("agent", chat.mFromID, "inspect").getSLURLString(); } // If the chat line has an associated url, link it up to the name. diff --git a/indra/newview/llfloaterchatterbox.cpp b/indra/newview/llfloaterchatterbox.cpp index 774caaec90..a15cef7ea4 100644 --- a/indra/newview/llfloaterchatterbox.cpp +++ b/indra/newview/llfloaterchatterbox.cpp @@ -318,7 +318,7 @@ LLFloaterChatterBox* LLFloaterChatterBox::getInstance() //static LLFloater* LLFloaterChatterBox::getCurrentVoiceFloater() { - if (!LLVoiceClient::voiceEnabled()) + if (!LLVoiceClient::getInstance()->voiceEnabled()) { return NULL; } diff --git a/indra/newview/llfloaterevent.cpp b/indra/newview/llfloaterevent.cpp index 97ebab3425..84a5c3dc77 100644 --- a/indra/newview/llfloaterevent.cpp +++ b/indra/newview/llfloaterevent.cpp @@ -193,7 +193,7 @@ void LLFloaterEvent::processEventInfoReply(LLMessageSystem *msg, void **) floater->mTBCategory->setText(floater->mEventInfo.mCategoryStr); floater->mTBDate->setText(floater->mEventInfo.mTimeStr); floater->mTBDesc->setText(floater->mEventInfo.mDesc); - floater->mTBRunBy->setText(LLSLURL::buildCommand("agent", floater->mEventInfo.mRunByID, "inspect")); + floater->mTBRunBy->setText(LLSLURL("agent", floater->mEventInfo.mRunByID, "inspect").getSLURLString()); floater->mTBDuration->setText(llformat("%d:%.2d", floater->mEventInfo.mDuration / 60, floater->mEventInfo.mDuration % 60)); diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index 6467ee13b0..f2483e82dc 100644 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -42,7 +42,6 @@ #include "llnotificationsutil.h" #include "llparcel.h" #include "message.h" -#include "lluserauth.h" #include "llagent.h" #include "llbutton.h" @@ -804,7 +803,7 @@ void LLPanelLandGeneral::refreshNames() else { // Figure out the owner's name - owner = LLSLURL::buildCommand("agent", parcel->getOwnerID(), "inspect"); + owner = LLSLURL("agent", parcel->getOwnerID(), "inspect").getSLURLString(); } if(LLParcel::OS_LEASE_PENDING == parcel->getOwnershipStatus()) @@ -816,7 +815,7 @@ void LLPanelLandGeneral::refreshNames() std::string group; if (!parcel->getGroupID().isNull()) { - group = LLSLURL::buildCommand("group", parcel->getGroupID(), "inspect"); + group = LLSLURL("group", parcel->getGroupID(), "inspect").getSLURLString(); } mTextGroup->setText(group); @@ -825,9 +824,9 @@ void LLPanelLandGeneral::refreshNames() const LLUUID& auth_buyer_id = parcel->getAuthorizedBuyerID(); if(auth_buyer_id.notNull()) { - std::string name; - name = LLSLURL::buildCommand("agent", auth_buyer_id, "inspect"); - mSaleInfoForSale2->setTextArg("[BUYER]", name); + std::string name; + name = LLSLURL("agent", auth_buyer_id, "inspect").getSLURLString(); + mSaleInfoForSale2->setTextArg("[BUYER]", name); } else { diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 3487f52f35..5af4ed3c2c 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -609,7 +609,7 @@ void LLFloaterPreference::onBtnOK() llinfos << "Can't close preferences!" << llendl; } - LLPanelLogin::refreshLocation( false ); + LLPanelLogin::updateLocationCombo( false ); } // static @@ -626,7 +626,7 @@ void LLFloaterPreference::onBtnApply( ) apply(); saveSettings(); - LLPanelLogin::refreshLocation( false ); + LLPanelLogin::updateLocationCombo( false ); } // static diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 3758cbe74f..8c219cb3fd 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -2922,8 +2922,7 @@ bool LLDispatchEstateUpdateInfo::operator()( LLUUID owner_id(strings[1]); regionp->setOwner(owner_id); // Update estate owner name in UI - std::string owner_name = - LLSLURL::buildCommand("agent", owner_id, "inspect"); + std::string owner_name = LLSLURL("agent", owner_id, "inspect").getSLURLString(); panel->setOwnerName(owner_name); U32 estate_id = strtoul(strings[2].c_str(), NULL, 10); diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index b42b34835d..f7c8855bf6 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -126,7 +126,9 @@ void LLFloaterReporter::processRegionInfo(LLMessageSystem* msg) // virtual BOOL LLFloaterReporter::postBuild() { - childSetText("abuse_location_edit", LLAgentUI::buildSLURL()); + LLSLURL slurl; + LLAgentUI::buildSLURL(slurl); + childSetText("abuse_location_edit", slurl.getSLURLString()); enableControls(TRUE); @@ -280,7 +282,6 @@ void LLFloaterReporter::getObjectInfo(const LLUUID& object_id) { object_owner.append("Unknown"); } - setFromAvatar(mObjectID, object_owner); } else @@ -325,7 +326,8 @@ void LLFloaterReporter::setFromAvatar(const LLUUID& avatar_id, const std::string mAbuserID = mObjectID = avatar_id; mOwnerName = avatar_name; - std::string avatar_link = LLSLURL::buildCommand("agent", mObjectID, "inspect"); + std::string avatar_link = + LLSLURL("agent", mObjectID, "inspect").getSLURLString(); childSetText("owner_name", avatar_link); childSetText("object_name", avatar_name); childSetText("abuser_name_edit", avatar_name); @@ -504,7 +506,7 @@ void LLFloaterReporter::setPickedObjectProperties(const std::string& object_name { childSetText("object_name", object_name); std::string owner_link = - LLSLURL::buildCommand("agent", owner_id, "inspect"); + LLSLURL("agent", owner_id, "inspect").getSLURLString(); childSetText("owner_name", owner_link); childSetText("abuser_name_edit", owner_name); mAbuserID = owner_id; @@ -566,7 +568,7 @@ LLSD LLFloaterReporter::gatherReport() mCopyrightWarningSeen = FALSE; std::ostringstream summary; - if (!LLViewerLogin::getInstance()->isInProductionGrid()) + if (!LLGridManager::getInstance()->isInProductionGrid()) { summary << "Preview "; } diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index adac9861d4..aae379afe2 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -1123,7 +1123,7 @@ void LLSnapshotLivePreview::saveWeb(std::string url) void LLSnapshotLivePreview::regionNameCallback(std::string url, LLSD body, const std::string& name, S32 x, S32 y, S32 z) { - body["slurl"] = LLSLURL::buildSLURL(name, x, y, z); + body["slurl"] = LLSLURL(name, LLVector3d(x, y, z)).getSLURLString(); LLHTTPClient::post(url, body, new LLSendWebResponder()); diff --git a/indra/newview/llfloatervoicedevicesettings.cpp b/indra/newview/llfloatervoicedevicesettings.cpp index 638c9f1b8c..63365e3461 100644 --- a/indra/newview/llfloatervoicedevicesettings.cpp +++ b/indra/newview/llfloatervoicedevicesettings.cpp @@ -64,9 +64,6 @@ LLPanelVoiceDeviceSettings::LLPanelVoiceDeviceSettings() // grab "live" mic volume level mMicVolume = gSavedSettings.getF32("AudioLevelMic"); - // ask for new device enumeration - // now do this in onOpen() instead... - //gVoiceClient->refreshDeviceLists(); } LLPanelVoiceDeviceSettings::~LLPanelVoiceDeviceSettings() @@ -105,7 +102,7 @@ void LLPanelVoiceDeviceSettings::draw() refresh(); // let user know that volume indicator is not yet available - bool is_in_tuning_mode = gVoiceClient->inTuningMode(); + bool is_in_tuning_mode = LLVoiceClient::getInstance()->inTuningMode(); childSetVisible("wait_text", !is_in_tuning_mode); LLPanel::draw(); @@ -113,7 +110,7 @@ void LLPanelVoiceDeviceSettings::draw() if (is_in_tuning_mode) { const S32 num_bars = 5; - F32 voice_power = gVoiceClient->tuningGetEnergy() / LLVoiceClient::OVERDRIVEN_POWER_LEVEL; + F32 voice_power = LLVoiceClient::getInstance()->tuningGetEnergy() / LLVoiceClient::OVERDRIVEN_POWER_LEVEL; S32 discrete_power = llmin(num_bars, llfloor(voice_power * (F32)num_bars + 0.1f)); for(S32 power_bar_idx = 0; power_bar_idx < num_bars; power_bar_idx++) @@ -194,13 +191,13 @@ void LLPanelVoiceDeviceSettings::refresh() LLSlider* volume_slider = getChild<LLSlider>("mic_volume_slider"); // set mic volume tuning slider based on last mic volume setting F32 current_volume = (F32)volume_slider->getValue().asReal(); - gVoiceClient->tuningSetMicVolume(current_volume); + LLVoiceClient::getInstance()->tuningSetMicVolume(current_volume); // Fill in popup menus mCtrlInputDevices = getChild<LLComboBox>("voice_input_device"); mCtrlOutputDevices = getChild<LLComboBox>("voice_output_device"); - if(!gVoiceClient->deviceSettingsAvailable()) + if(!LLVoiceClient::getInstance()->deviceSettingsAvailable()) { // The combo boxes are disabled, since we can't get the device settings from the daemon just now. // Put the currently set default (ONLY) in the box, and select it. @@ -219,17 +216,16 @@ void LLPanelVoiceDeviceSettings::refresh() } else if (!mDevicesUpdated) { - LLVoiceClient::deviceList *devices; - - LLVoiceClient::deviceList::iterator iter; + LLVoiceDeviceList::const_iterator iter; if(mCtrlInputDevices) { mCtrlInputDevices->removeall(); mCtrlInputDevices->add( getString("default_text"), ADD_BOTTOM ); - devices = gVoiceClient->getCaptureDevices(); - for(iter=devices->begin(); iter != devices->end(); iter++) + for(iter=LLVoiceClient::getInstance()->getCaptureDevices().begin(); + iter != LLVoiceClient::getInstance()->getCaptureDevices().end(); + iter++) { mCtrlInputDevices->add( *iter, ADD_BOTTOM ); } @@ -245,8 +241,8 @@ void LLPanelVoiceDeviceSettings::refresh() mCtrlOutputDevices->removeall(); mCtrlOutputDevices->add( getString("default_text"), ADD_BOTTOM ); - devices = gVoiceClient->getRenderDevices(); - for(iter=devices->begin(); iter != devices->end(); iter++) + for(iter= LLVoiceClient::getInstance()->getRenderDevices().begin(); + iter != LLVoiceClient::getInstance()->getRenderDevices().end(); iter++) { mCtrlOutputDevices->add( *iter, ADD_BOTTOM ); } @@ -268,37 +264,34 @@ void LLPanelVoiceDeviceSettings::initialize() mDevicesUpdated = FALSE; // ask for new device enumeration - gVoiceClient->refreshDeviceLists(); + LLVoiceClient::getInstance()->refreshDeviceLists(); // put voice client in "tuning" mode - gVoiceClient->tuningStart(); + LLVoiceClient::getInstance()->tuningStart(); LLVoiceChannel::suspend(); } void LLPanelVoiceDeviceSettings::cleanup() { - if (gVoiceClient) - { - gVoiceClient->tuningStop(); - } + LLVoiceClient::getInstance()->tuningStop(); LLVoiceChannel::resume(); } // static void LLPanelVoiceDeviceSettings::onCommitInputDevice(LLUICtrl* ctrl, void* user_data) { - if(gVoiceClient) + if(LLVoiceClient::getInstance()) { - gVoiceClient->setCaptureDevice(ctrl->getValue().asString()); + LLVoiceClient::getInstance()->setCaptureDevice(ctrl->getValue().asString()); } } // static void LLPanelVoiceDeviceSettings::onCommitOutputDevice(LLUICtrl* ctrl, void* user_data) { - if(gVoiceClient) + if(LLVoiceClient::getInstance()) { - gVoiceClient->setRenderDevice(ctrl->getValue().asString()); + LLVoiceClient::getInstance()->setRenderDevice(ctrl->getValue().asString()); } } diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index f17c9765b9..896c410e32 100644 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -461,7 +461,7 @@ void LLFloaterWorldMap::draw() childSetEnabled("Teleport", (BOOL)tracking_status); // childSetEnabled("Clear", (BOOL)tracking_status); childSetEnabled("Show Destination", (BOOL)tracking_status || LLWorldMap::getInstance()->isTracking()); - childSetEnabled("copy_slurl", (mSLURL.size() > 0) ); + childSetEnabled("copy_slurl", (mSLURL.isValid()) ); setMouseOpaque(TRUE); getDragHandle()->setMouseOpaque(TRUE); @@ -660,14 +660,8 @@ void LLFloaterWorldMap::updateLocation() childSetValue("location", agent_sim_name); // Figure out where user is - LLVector3d agentPos = gAgent.getPositionGlobal(); - - S32 agent_x = llround( (F32)fmod( agentPos.mdV[VX], (F64)REGION_WIDTH_METERS ) ); - S32 agent_y = llround( (F32)fmod( agentPos.mdV[VY], (F64)REGION_WIDTH_METERS ) ); - S32 agent_z = llround( (F32)agentPos.mdV[VZ] ); - // Set the current SLURL - mSLURL = LLSLURL::buildSLURL(agent_sim_name, agent_x, agent_y, agent_z); + mSLURL = LLSLURL(agent_sim_name, gAgent.getPositionGlobal()); } } @@ -694,18 +688,15 @@ void LLFloaterWorldMap::updateLocation() } childSetValue("location", sim_name); - - F32 region_x = (F32)fmod( pos_global.mdV[VX], (F64)REGION_WIDTH_METERS ); - F32 region_y = (F32)fmod( pos_global.mdV[VY], (F64)REGION_WIDTH_METERS ); // simNameFromPosGlobal can fail, so don't give the user an invalid SLURL if ( gotSimName ) { - mSLURL = LLSLURL::buildSLURL(sim_name, llround(region_x), llround(region_y), llround((F32)pos_global.mdV[VZ])); + mSLURL = LLSLURL(sim_name, pos_global); } else { // Empty SLURL will disable the "Copy SLURL to clipboard" button - mSLURL = ""; + mSLURL = LLSLURL(); } } } @@ -1174,7 +1165,7 @@ void LLFloaterWorldMap::onClearBtn() mTrackedStatus = LLTracker::TRACKING_NOTHING; LLTracker::stopTracking((void *)(intptr_t)TRUE); LLWorldMap::getInstance()->cancelTracking(); - mSLURL = ""; // Clear the SLURL since it's invalid + mSLURL = LLSLURL(); // Clear the SLURL since it's invalid mSetToUserPosition = TRUE; // Revert back to the current user position } @@ -1197,10 +1188,10 @@ void LLFloaterWorldMap::onClickTeleportBtn() void LLFloaterWorldMap::onCopySLURL() { - getWindow()->copyTextToClipboard(utf8str_to_wstring(mSLURL)); + getWindow()->copyTextToClipboard(utf8str_to_wstring(mSLURL.getSLURLString())); LLSD args; - args["SLURL"] = mSLURL; + args["SLURL"] = mSLURL.getSLURLString(); LLNotificationsUtil::add("CopySLURL", args); } diff --git a/indra/newview/llfloaterworldmap.h b/indra/newview/llfloaterworldmap.h index 00f5e788fb..52809ff830 100644 --- a/indra/newview/llfloaterworldmap.h +++ b/indra/newview/llfloaterworldmap.h @@ -43,6 +43,7 @@ #include "llhudtext.h" #include "llmapimagetype.h" #include "lltracker.h" +#include "llslurl.h" class LLEventInfo; class LLFriendObserver; @@ -183,7 +184,7 @@ private: LLTracker::ETrackingStatus mTrackedStatus; std::string mTrackedSimName; std::string mTrackedAvatarName; - std::string mSLURL; + LLSLURL mSLURL; }; extern LLFloaterWorldMap* gFloaterWorldMap; diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp index 8a056f836f..03a47b5983 100644 --- a/indra/newview/llgrouplist.cpp +++ b/indra/newview/llgrouplist.cpp @@ -287,7 +287,7 @@ bool LLGroupList::onContextMenuItemEnable(const LLSD& userdata) return gAgent.getGroupID() != selected_group_id; if (userdata.asString() == "call") - return real_group_selected && LLVoiceClient::voiceEnabled()&&gVoiceClient->voiceWorking(); + return real_group_selected && LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking(); return real_group_selected; } diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index 3ec8d11fb0..9704c7537a 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -58,7 +58,6 @@ #include "lltransientfloatermgr.h" #include "llinventorymodel.h" #include "llrootview.h" - #include "llspeakers.h" diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index 4bdf5f42dc..0e3b78df7f 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -300,7 +300,7 @@ void LLFloaterIMPanel::onVolumeChange(LLUICtrl* source, void* user_data) LLFloaterIMPanel* floaterp = (LLFloaterIMPanel*)user_data; if (floaterp) { - gVoiceClient->setUserVolume(floaterp->mOtherParticipantUUID, (F32)source->getValue().asReal()); + LLVoiceClient::getInstance()->setUserVolume(floaterp->mOtherParticipantUUID, (F32)source->getValue().asReal()); } } @@ -312,7 +312,7 @@ void LLFloaterIMPanel::draw() BOOL enable_connect = (region && region->getCapability("ChatSessionRequest") != "") && mSessionInitialized - && LLVoiceClient::voiceEnabled() + && LLVoiceClient::getInstance()->voiceEnabled() && mCallBackEnabled; // hide/show start call and end call buttons @@ -320,8 +320,8 @@ void LLFloaterIMPanel::draw() if (!voice_channel) return; - childSetVisible("end_call_btn", LLVoiceClient::voiceEnabled() && voice_channel->getState() >= LLVoiceChannel::STATE_CALL_STARTED); - childSetVisible("start_call_btn", LLVoiceClient::voiceEnabled() && voice_channel->getState() < LLVoiceChannel::STATE_CALL_STARTED); + childSetVisible("end_call_btn", LLVoiceClient::getInstance()->voiceEnabled() && voice_channel->getState() >= LLVoiceChannel::STATE_CALL_STARTED); + childSetVisible("start_call_btn", LLVoiceClient::getInstance()->voiceEnabled() && voice_channel->getState() < LLVoiceChannel::STATE_CALL_STARTED); childSetEnabled("start_call_btn", enable_connect); childSetEnabled("send_btn", !childGetValue("chat_editor").asString().empty()); @@ -384,11 +384,11 @@ void LLFloaterIMPanel::draw() else { // refresh volume and mute checkbox - childSetVisible("speaker_volume", LLVoiceClient::voiceEnabled() && voice_channel->isActive()); - childSetValue("speaker_volume", gVoiceClient->getUserVolume(mOtherParticipantUUID)); + childSetVisible("speaker_volume", LLVoiceClient::getInstance()->voiceEnabled() && voice_channel->isActive()); + childSetValue("speaker_volume", LLVoiceClient::getInstance()->getUserVolume(mOtherParticipantUUID)); childSetValue("mute_btn", LLMuteList::getInstance()->isMuted(mOtherParticipantUUID, LLMute::flagVoiceChat)); - childSetVisible("mute_btn", LLVoiceClient::voiceEnabled() && voice_channel->isActive()); + childSetVisible("mute_btn", LLVoiceClient::getInstance()->voiceEnabled() && voice_channel->isActive()); } LLFloater::draw(); } diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 0099cd114f..49e04ca908 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -323,13 +323,13 @@ LLIMModel::LLIMSession::~LLIMSession() mSpeakers = NULL; // End the text IM session if necessary - if(gVoiceClient && mOtherParticipantID.notNull()) + if(LLVoiceClient::getInstance() && mOtherParticipantID.notNull()) { switch(mType) { case IM_NOTHING_SPECIAL: case IM_SESSION_P2P_INVITE: - gVoiceClient->endUserIMSession(mOtherParticipantID); + LLVoiceClient::getInstance()->endUserIMSession(mOtherParticipantID); break; default: @@ -904,7 +904,7 @@ void LLIMModel::sendMessage(const std::string& utf8_text, if((offline == IM_OFFLINE) && (LLVoiceClient::getInstance()->isOnlineSIP(other_participant_id))) { // User is online through the OOW connector, but not with a regular viewer. Try to send the message via SLVoice. - sent = gVoiceClient->sendTextMessage(other_participant_id, utf8_text); + sent = LLVoiceClient::getInstance()->sendTextMessage(other_participant_id, utf8_text); } if(!sent) @@ -1691,7 +1691,7 @@ void LLOutgoingCallDialog::show(const LLSD& key) // skipping "You will now be reconnected to nearby" in notification when call is ended by disabling voice, // so no reconnection to nearby chat happens (EXT-4397) - bool voice_works = LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking(); + bool voice_works = LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking(); std::string reconnect_nearby = voice_works ? LLTrans::getString("reconnect_nearby") : std::string(); childSetTextArg("nearby", "[RECONNECT_NEARBY]", reconnect_nearby); @@ -1817,7 +1817,11 @@ LLCallDialog(payload) void LLIncomingCallDialog::onLifetimeExpired() { // check whether a call is valid or not - if (LLVoiceClient::getInstance()->findSession(mPayload["caller_id"].asUUID())) + LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mPayload["session_id"].asUUID()); + if(channelp && + (channelp->getState() != LLVoiceChannel::STATE_NO_CHANNEL_INFO) && + (channelp->getState() != LLVoiceChannel::STATE_ERROR) && + (channelp->getState() != LLVoiceChannel::STATE_HUNG_UP)) { // restart notification's timer if call is still valid mLifetimeTimer.start(); @@ -2051,10 +2055,10 @@ void LLIncomingCallDialog::processCallResponse(S32 response) { if (type == IM_SESSION_P2P_INVITE) { - if(gVoiceClient) + if(LLVoiceClient::getInstance()) { std::string s = mPayload["session_handle"].asString(); - gVoiceClient->declineInvite(s); + LLVoiceClient::getInstance()->declineInvite(s); } } else @@ -2142,11 +2146,8 @@ bool inviteUserResponse(const LLSD& notification, const LLSD& response) { if (type == IM_SESSION_P2P_INVITE) { - if(gVoiceClient) - { - std::string s = payload["session_handle"].asString(); - gVoiceClient->declineInvite(s); - } + std::string s = payload["session_handle"].asString(); + LLVoiceClient::getInstance()->declineInvite(s); } else { @@ -3052,7 +3053,7 @@ public: return; } - if(!LLVoiceClient::voiceEnabled()) + if(!LLVoiceClient::getInstance()->voiceEnabled()) { // Don't display voice invites unless the user has voice enabled. return; diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp index 35cb9b3468..dfc69db3f1 100644 --- a/indra/newview/llinspectavatar.cpp +++ b/indra/newview/llinspectavatar.cpp @@ -534,8 +534,7 @@ void LLInspectAvatar::toggleSelectedVoice(bool enabled) void LLInspectAvatar::updateVolumeSlider() { - - bool voice_enabled = gVoiceClient->getVoiceEnabled(mAvatarID); + bool voice_enabled = LLVoiceClient::getInstance()->getVoiceEnabled(mAvatarID); // Do not display volume slider and mute button if it // is ourself or we are not in a voice channel together @@ -565,6 +564,7 @@ void LLInspectAvatar::updateVolumeSlider() volume_slider->setEnabled( !is_muted ); F32 volume; + if (is_muted) { // it's clearer to display their volume as zero @@ -573,7 +573,7 @@ void LLInspectAvatar::updateVolumeSlider() else { // actual volume - volume = gVoiceClient->getUserVolume(mAvatarID); + volume = LLVoiceClient::getInstance()->getUserVolume(mAvatarID); } volume_slider->setValue( (F64)volume ); } @@ -602,7 +602,7 @@ void LLInspectAvatar::onClickMuteVolume() void LLInspectAvatar::onVolumeChange(const LLSD& data) { F32 volume = (F32)data.asReal(); - gVoiceClient->setUserVolume(mAvatarID, volume); + LLVoiceClient::getInstance()->setUserVolume(mAvatarID, volume); } void LLInspectAvatar::nameUpdatedCallback( diff --git a/indra/newview/llinspectobject.cpp b/indra/newview/llinspectobject.cpp index 91cbbbf430..a2b5ffbac4 100644 --- a/indra/newview/llinspectobject.cpp +++ b/indra/newview/llinspectobject.cpp @@ -480,7 +480,7 @@ void LLInspectObject::updateCreator(LLSelectNode* nodep) // Objects cannot be created by a group, so use agent URL format LLUUID creator_id = nodep->mPermissions->getCreator(); std::string creator_url = - LLSLURL::buildCommand("agent", creator_id, "about"); + LLSLURL("agent", creator_id, "about").getSLURLString(); args["[CREATOR]"] = creator_url; // created by one user but owned by another @@ -490,12 +490,12 @@ void LLInspectObject::updateCreator(LLSelectNode* nodep) if (group_owned) { owner_id = nodep->mPermissions->getGroup(); - owner_url = LLSLURL::buildCommand("group", owner_id, "about"); + owner_url = LLSLURL("group", owner_id, "about").getSLURLString(); } else { owner_id = nodep->mPermissions->getOwner(); - owner_url = LLSLURL::buildCommand("agent", owner_id, "about"); + owner_url = LLSLURL("agent", owner_id, "about").getSLURLString(); } args["[OWNER]"] = owner_url; diff --git a/indra/newview/llinspectremoteobject.cpp b/indra/newview/llinspectremoteobject.cpp index 66e4a1bf66..97ff771658 100644 --- a/indra/newview/llinspectremoteobject.cpp +++ b/indra/newview/llinspectremoteobject.cpp @@ -176,11 +176,11 @@ void LLInspectRemoteObject::update() { if (mGroupOwned) { - owner = LLSLURL::buildCommand("group", mOwnerID, "about"); + owner = LLSLURL("group", mOwnerID, "about").getSLURLString(); } else { - owner = LLSLURL::buildCommand("agent", mOwnerID, "about"); + owner = LLSLURL("agent", mOwnerID, "about").getSLURLString(); } } else diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index d1cc0ae936..b6202c6a8c 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1329,7 +1329,6 @@ bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id) return cat->fetchDescendents(); } - void LLInventoryModel::cache( const LLUUID& parent_folder_id, const LLUUID& agent_id) diff --git a/indra/newview/lllandmarkactions.cpp b/indra/newview/lllandmarkactions.cpp index 7336efb62a..539ca97a93 100644 --- a/indra/newview/lllandmarkactions.cpp +++ b/indra/newview/lllandmarkactions.cpp @@ -299,7 +299,7 @@ void LLLandmarkActions::getSLURLfromPosGlobal(const LLVector3d& global_pos, slur bool gotSimName = LLWorldMap::getInstance()->simNameFromPosGlobal(global_pos, sim_name); if (gotSimName) { - std::string slurl = LLSLURL::buildSLURLfromPosGlobal(sim_name, global_pos, escaped); + std::string slurl = LLSLURL(sim_name, global_pos).getSLURLString(); cb(slurl); return; @@ -351,7 +351,7 @@ void LLLandmarkActions::onRegionResponseSLURL(slurl_callback_t cb, bool gotSimName = LLWorldMap::getInstance()->simNameFromPosGlobal(global_pos, sim_name); if (gotSimName) { - slurl = LLSLURL::buildSLURLfromPosGlobal(sim_name, global_pos, escaped); + slurl = LLSLURL(sim_name, global_pos).getSLURLString(); } else { diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index ba50287ebd..85b022878f 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -669,9 +669,8 @@ void LLLocationInputCtrl::onLocationPrearrange(const LLSD& data) value["item_type"] = TELEPORT_HISTORY; value["global_pos"] = result->mGlobalPos.getValue(); std::string region_name = result->mTitle.substr(0, result->mTitle.find(',')); - //TODO*: add slurl to teleportitem or parse region name from title - value["tooltip"] = LLSLURL::buildSLURLfromPosGlobal(region_name, - result->mGlobalPos, false); + //TODO*: add Surl to teleportitem or parse region name from title + value["tooltip"] = LLSLURL(region_name, result->mGlobalPos).getSLURLString(); add(result->getTitle(), value); } result = std::find_if(result + 1, th_items.end(), boost::bind( @@ -1012,7 +1011,9 @@ void LLLocationInputCtrl::changeLocationPresentation() if(!mTextEntry->hasSelection() && text == mHumanReadableLocation) { //needs unescaped one - mTextEntry->setText(LLAgentUI::buildSLURL(false)); + LLSLURL slurl; + LLAgentUI::buildSLURL(slurl, false); + mTextEntry->setText(slurl.getSLURLString()); mTextEntry->selectAll(); mMaturityIcon->setVisible(FALSE); diff --git a/indra/newview/llloginhandler.cpp b/indra/newview/llloginhandler.cpp index e3817eecc4..4e0a7594ba 100644 --- a/indra/newview/llloginhandler.cpp +++ b/indra/newview/llloginhandler.cpp @@ -35,13 +35,14 @@ #include "llloginhandler.h" // viewer includes +#include "llsecapi.h" #include "lllogininstance.h" // to check if logged in yet #include "llpanellogin.h" // save_password_to_disk() #include "llstartup.h" // getStartupState() -#include "llurlsimstring.h" +#include "llslurl.h" #include "llviewercontrol.h" // gSavedSettings #include "llviewernetwork.h" // EGridInfo -#include "llviewerwindow.h" // getWindow() +#include "llviewerwindow.h" // getWindow() // library includes #include "llmd5.h" @@ -60,109 +61,33 @@ bool LLLoginHandler::parseDirectLogin(std::string url) LLURI uri(url); parse(uri.queryMap()); - if (/*mWebLoginKey.isNull() ||*/ - mFirstName.empty() || - mLastName.empty()) - { - return false; - } - else - { - return true; - } + // NOTE: Need to add direct login as per identity evolution + return true; } - void LLLoginHandler::parse(const LLSD& queryMap) { - //mWebLoginKey = queryMap["web_login_key"].asUUID(); - mFirstName = queryMap["first_name"].asString(); - mLastName = queryMap["last_name"].asString(); - EGridInfo grid_choice = GRID_INFO_NONE; - if (queryMap["grid"].asString() == "aditi") - { - grid_choice = GRID_INFO_ADITI; - } - else if (queryMap["grid"].asString() == "agni") - { - grid_choice = GRID_INFO_AGNI; - } - else if (queryMap["grid"].asString() == "siva") - { - grid_choice = GRID_INFO_SIVA; - } - else if (queryMap["grid"].asString() == "damballah") - { - grid_choice = GRID_INFO_DAMBALLAH; - } - else if (queryMap["grid"].asString() == "durga") - { - grid_choice = GRID_INFO_DURGA; - } - else if (queryMap["grid"].asString() == "shakti") - { - grid_choice = GRID_INFO_SHAKTI; - } - else if (queryMap["grid"].asString() == "soma") - { - grid_choice = GRID_INFO_SOMA; - } - else if (queryMap["grid"].asString() == "ganga") - { - grid_choice = GRID_INFO_GANGA; - } - else if (queryMap["grid"].asString() == "vaak") - { - grid_choice = GRID_INFO_VAAK; - } - else if (queryMap["grid"].asString() == "uma") - { - grid_choice = GRID_INFO_UMA; - } - else if (queryMap["grid"].asString() == "mohini") - { - grid_choice = GRID_INFO_MOHINI; - } - else if (queryMap["grid"].asString() == "yami") - { - grid_choice = GRID_INFO_YAMI; - } - else if (queryMap["grid"].asString() == "nandi") + if (queryMap.has("grid")) { - grid_choice = GRID_INFO_NANDI; + LLGridManager::getInstance()->setGridChoice(queryMap["grid"].asString()); } - else if (queryMap["grid"].asString() == "mitra") - { - grid_choice = GRID_INFO_MITRA; - } - else if (queryMap["grid"].asString() == "radha") - { - grid_choice = GRID_INFO_RADHA; - } - else if (queryMap["grid"].asString() == "ravi") - { - grid_choice = GRID_INFO_RAVI; - } - else if (queryMap["grid"].asString() == "aruna") - { - grid_choice = GRID_INFO_ARUNA; - } - - if(grid_choice != GRID_INFO_NONE) - { - LLViewerLogin::getInstance()->setGridChoice(grid_choice); - } - + + std::string startLocation = queryMap["location"].asString(); - + if (startLocation == "specify") { - LLURLSimString::setString(queryMap["region"].asString()); + LLStartUp::setStartSLURL(LLSLURL(LLGridManager::getInstance()->getGridLoginID(), + queryMap["region"].asString())); } - else if (!startLocation.empty()) // "last" or "home" or ??? (let LLURLSimString figure it out) + else if (startLocation == "home") { - LLURLSimString::setString(startLocation); + LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME)); + } + else if (startLocation == "last") + { + LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_LAST)); } } @@ -220,40 +145,65 @@ bool LLLoginHandler::handle(const LLSD& tokens, return true; } - std::string password = query_map["password"].asString(); - - if (!password.empty()) + if (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP) //on splash page { - gSavedSettings.setBOOL("RememberPassword", TRUE); - - if (password.substr(0,3) != "$1$") - { - LLMD5 pass((unsigned char*)password.c_str()); - char md5pass[33]; /* Flawfinder: ignore */ - pass.hex_digest(md5pass); - std::string hashed_password = ll_safe_string(md5pass, 32); - LLStartUp::savePasswordToDisk(hashed_password); - } + // as the login page may change from grid to grid, as well as + // things like username/password/etc, we simply refresh the + // login page to make sure everything is set up correctly + LLPanelLogin::loadLoginPage(); + LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); } - + return true; +} - if (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP) //on splash page - { - if (!mFirstName.empty() || !mLastName.empty()) - { - // Fill in the name, and maybe the password - LLPanelLogin::setFields(mFirstName, mLastName, password); - } - //if (mWebLoginKey.isNull()) - //{ - // LLPanelLogin::loadLoginPage(); - //} - //else - //{ - // LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); - //} - LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); - } - return true; + +// Initialize the credentials +// If the passed in URL contains login info, parse +// that into a credential and web login key. Otherwise +// check the command line. If the command line +// does not contain any login creds, load the last saved +// ones from the protected credential store. +// This always returns with a credential structure set in the +// login handler +LLPointer<LLCredential> LLLoginHandler::initializeLoginInfo() +{ + LLPointer<LLCredential> result = NULL; + // so try to load it from the UserLoginInfo + result = loadSavedUserLoginInfo(); + if (result.isNull()) + { + result = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + } + + return result; +} + + +LLPointer<LLCredential> LLLoginHandler::loadSavedUserLoginInfo() +{ + // load the saved user login info into a LLCredential. + // perhaps this should be moved. + LLSD cmd_line_login = gSavedSettings.getLLSD("UserLoginInfo"); + if (cmd_line_login.size() == 3) + { + + LLMD5 pass((unsigned char*)cmd_line_login[2].asString().c_str()); + char md5pass[33]; /* Flawfinder: ignore */ + pass.hex_digest(md5pass); + LLSD identifier = LLSD::emptyMap(); + identifier["type"] = "agent"; + identifier["first_name"] = cmd_line_login[0]; + identifier["last_name"] = cmd_line_login[1]; + + LLSD authenticator = LLSD::emptyMap(); + authenticator["type"] = "hash"; + authenticator["algorithm"] = "md5"; + authenticator["secret"] = md5pass; + // yuck, we'll fix this with mani's changes. + gSavedSettings.setBOOL("AutoLogin", TRUE); + return gSecAPIHandler->createCredential(LLGridManager::getInstance()->getGrid(), + identifier, authenticator); + } + return NULL; } diff --git a/indra/newview/llloginhandler.h b/indra/newview/llloginhandler.h index ac4648761b..c15b998c91 100644 --- a/indra/newview/llloginhandler.h +++ b/indra/newview/llloginhandler.h @@ -34,6 +34,7 @@ #define LLLOGINHANDLER_H #include "llcommandhandler.h" +#include "llsecapi.h" class LLLoginHandler : public LLCommandHandler { @@ -46,19 +47,15 @@ class LLLoginHandler : public LLCommandHandler // secondlife:///app/login?first=Bob&last=Dobbs bool parseDirectLogin(std::string url); - std::string getFirstName() const { return mFirstName; } - std::string getLastName() const { return mLastName; } - // Web-based login unsupported //LLUUID getWebLoginKey() const { return mWebLoginKey; } + LLPointer<LLCredential> loadSavedUserLoginInfo(); + LLPointer<LLCredential> initializeLoginInfo(); + private: void parse(const LLSD& queryMap); -private: - std::string mFirstName; - std::string mLastName; - //LLUUID mWebLoginKey; }; extern LLLoginHandler gLoginHandler; diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index 24c72c65ce..0459c85050 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -48,13 +48,16 @@ // newview #include "llviewernetwork.h" #include "llviewercontrol.h" -#include "llurlsimstring.h" +#include "llslurl.h" +#include "llstartup.h" #include "llfloaterreg.h" #include "llnotifications.h" #include "llwindow.h" #if LL_LINUX || LL_SOLARIS #include "lltrans.h" #endif +#include "llsecapi.h" +#include "llstartup.h" static const char * const TOS_REPLY_PUMP = "lllogininstance_tos_callback"; static const char * const TOS_LISTENER_NAME = "lllogininstance_tos"; @@ -83,14 +86,14 @@ LLLoginInstance::~LLLoginInstance() { } -void LLLoginInstance::connect(const LLSD& credentials) +void LLLoginInstance::connect(LLPointer<LLCredential> credentials) { std::vector<std::string> uris; - LLViewerLogin::getInstance()->getLoginURIs(uris); + LLGridManager::getInstance()->getLoginURIs(uris); connect(uris.front(), credentials); } -void LLLoginInstance::connect(const std::string& uri, const LLSD& credentials) +void LLLoginInstance::connect(const std::string& uri, LLPointer<LLCredential> credentials) { mAttemptComplete = false; // Reset attempt complete at this point! constructAuthParams(credentials); @@ -102,7 +105,7 @@ void LLLoginInstance::reconnect() // Sort of like connect, only using the pre-existing // request params. std::vector<std::string> uris; - LLViewerLogin::getInstance()->getLoginURIs(uris); + LLGridManager::getInstance()->getLoginURIs(uris); mLoginModule->connect(uris.front(), mRequestData); } @@ -118,7 +121,7 @@ LLSD LLLoginInstance::getResponse() return mResponseData; } -void LLLoginInstance::constructAuthParams(const LLSD& credentials) +void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credential) { // Set up auth request options. //#define LL_MINIMIAL_REQUESTED_OPTIONS @@ -145,8 +148,10 @@ void LLLoginInstance::constructAuthParams(const LLSD& credentials) requested_options.append("adult_compliant"); //requested_options.append("inventory-targets"); requested_options.append("buddy-list"); + requested_options.append("newuser-config"); requested_options.append("ui-config"); #endif + requested_options.append("voice-config"); requested_options.append("tutorial_setting"); requested_options.append("login-flags"); requested_options.append("global-textures"); @@ -155,20 +160,18 @@ void LLLoginInstance::constructAuthParams(const LLSD& credentials) gSavedSettings.setBOOL("UseDebugMenus", TRUE); requested_options.append("god-connect"); } + + // (re)initialize the request params with creds. + LLSD request_params = user_credential->getLoginParams(); char hashed_mac_string[MD5HEX_STR_SIZE]; /* Flawfinder: ignore */ LLMD5 hashed_mac; - hashed_mac.update( gMACAddress, MAC_ADDRESS_BYTES ); + unsigned char MACAddress[MAC_ADDRESS_BYTES]; + LLUUID::getNodeID(MACAddress); + hashed_mac.update( MACAddress, MAC_ADDRESS_BYTES ); hashed_mac.finalize(); hashed_mac.hex_digest(hashed_mac_string); - - // prepend "$1$" to the password to indicate its the md5'd version. - std::string dpasswd("$1$"); - dpasswd.append(credentials["passwd"].asString()); - - // (re)initialize the request params with creds. - LLSD request_params(credentials); - request_params["passwd"] = dpasswd; + request_params["start"] = construct_start_string(); request_params["skipoptional"] = mSkipOptionalUpdate; request_params["agree_to_tos"] = false; // Always false here. Set true in @@ -247,6 +250,15 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event) LLSD data(LLSD::emptyMap()); data["message"] = message_response; data["reply_pump"] = TOS_REPLY_PUMP; + if(response.has("error_code")) + { + data["error_code"] = response["error_code"]; + } + if(response.has("certificate")) + { + data["certificate"] = response["certificate"]; + } + LLFloaterReg::showInstance("message_critical", data); LLEventPumps::instance().obtain(TOS_REPLY_PUMP) .listen(TOS_LISTENER_NAME, @@ -454,20 +466,31 @@ bool LLLoginInstance::updateDialogCallback(const LLSD& notification, const LLSD& std::string construct_start_string() { std::string start; - if (LLURLSimString::parse()) + LLSLURL start_slurl = LLStartUp::getStartSLURL(); + switch(start_slurl.getType()) { - // a startup URL was specified - std::string unescaped_start = + case LLSLURL::LOCATION: + { + // a startup URL was specified + LLVector3 position = start_slurl.getPosition(); + std::string unescaped_start = STRINGIZE( "uri:" - << LLURLSimString::sInstance.mSimName << "&" - << LLURLSimString::sInstance.mX << "&" - << LLURLSimString::sInstance.mY << "&" - << LLURLSimString::sInstance.mZ); - start = xml_escape_string(unescaped_start); - } - else - { - start = gSavedSettings.getString("LoginLocation"); + << start_slurl.getRegion() << "&" + << position[VX] << "&" + << position[VY] << "&" + << position[VZ]); + start = xml_escape_string(unescaped_start); + break; + } + case LLSLURL::HOME_LOCATION: + { + start = "home"; + break; + } + default: + { + start = "last"; + } } return start; } diff --git a/indra/newview/lllogininstance.h b/indra/newview/lllogininstance.h index c8704eddb4..44271bb75e 100644 --- a/indra/newview/lllogininstance.h +++ b/indra/newview/lllogininstance.h @@ -36,6 +36,7 @@ #include "lleventdispatcher.h" #include <boost/scoped_ptr.hpp> #include <boost/function.hpp> +#include "llsecapi.h" class LLLogin; class LLEventStream; class LLNotificationsInterface; @@ -48,8 +49,8 @@ public: LLLoginInstance(); ~LLLoginInstance(); - void connect(const LLSD& credential); // Connect to the current grid choice. - void connect(const std::string& uri, const LLSD& credential); // Connect to the given uri. + void connect(LLPointer<LLCredential> credentials); // Connect to the current grid choice. + void connect(const std::string& uri, LLPointer<LLCredential> credentials); // Connect to the given uri. void reconnect(); // reconnect using the current credentials. void disconnect(); @@ -81,7 +82,7 @@ public: void setUpdaterLauncher(const UpdaterLauncherCallback& ulc) { mUpdaterLauncher = ulc; } private: - void constructAuthParams(const LLSD& credentials); + void constructAuthParams(LLPointer<LLCredential> user_credentials); void updateApp(bool mandatory, const std::string& message); bool updateDialogCallback(const LLSD& notification, const LLSD& response); diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp index e11df06d86..c3d0f1bfc2 100644 --- a/indra/newview/llnavigationbar.cpp +++ b/indra/newview/llnavigationbar.cpp @@ -52,7 +52,6 @@ #include "llsearchcombobox.h" #include "llsidetray.h" #include "llslurl.h" -#include "llurlsimstring.h" #include "llurlregistry.h" #include "llurldispatcher.h" #include "llviewerinventory.h" @@ -508,29 +507,34 @@ void LLNavigationBar::onLocationSelection() std::string region_name; LLVector3 local_coords(128, 128, 0); - S32 x = 0, y = 0, z = 0; // Is the typed location a SLURL? - if (LLSLURL::isSLURL(typed_location)) + LLSLURL slurl = LLSLURL(typed_location); + if (slurl.getType() == LLSLURL::LOCATION) { - // Yes. Extract region name and local coordinates from it. - if (LLURLSimString::parse(LLSLURL::stripProtocol(typed_location), ®ion_name, &x, &y, &z)) - local_coords.set(x, y, z); - else - return; + region_name = slurl.getRegion(); + local_coords = slurl.getPosition(); } - // we have to do this check after previous, because LLUrlRegistry contains handlers for slurl too - //but we need to know whether typed_location is a simple http url. - else if (LLUrlRegistry::instance().isUrl(typed_location)) + else if(!slurl.isValid()) { + // we have to do this check after previous, because LLUrlRegistry contains handlers for slurl too + // but we need to know whether typed_location is a simple http url. + if (LLUrlRegistry::instance().isUrl(typed_location)) + { // display http:// URLs in the media browser, or // anything else is sent to the search floater LLWeb::loadURL(typed_location); return; + } + else + { + // assume that an user has typed the {region name} or possible {region_name, parcel} + region_name = typed_location.substr(0,typed_location.find(',')); + } } else { - // assume that an user has typed the {region name} or possible {region_name, parcel} - region_name = typed_location.substr(0,typed_location.find(',')); + // was an app slurl, home, whatever. Bail + return; } // Resolve the region name to its global coordinates. @@ -562,7 +566,7 @@ void LLNavigationBar::onTeleportFinished(const LLVector3d& global_agent_pos) */ LLAgentUI::buildLocationString(location, LLAgentUI::LOCATION_FORMAT_NO_MATURITY, gAgent.getPosAgentFromGlobal(global_agent_pos)); - std::string tooltip (LLSLURL::buildSLURLfromPosGlobal(gAgent.getRegion()->getName(), global_agent_pos, false)); + std::string tooltip (LLSLURL(gAgent.getRegion()->getName(), global_agent_pos).getSLURLString()); LLLocationHistoryItem item (location, global_agent_pos, tooltip,TYPED_REGION_SLURL);// we can add into history only TYPED location @@ -651,7 +655,7 @@ void LLNavigationBar::onRegionNameResponse( LLVector3d region_pos = from_region_handle(region_handle); LLVector3d global_pos = region_pos + (LLVector3d) local_coords; - llinfos << "Teleporting to: " << LLSLURL::buildSLURLfromPosGlobal(region_name, global_pos, false) << llendl; + llinfos << "Teleporting to: " << LLSLURL(region_name, global_pos).getSLURLString() << llendl; gAgent.teleportViaLocation(global_pos); } diff --git a/indra/newview/lloutputmonitorctrl.cpp b/indra/newview/lloutputmonitorctrl.cpp index d6d48a4ead..197a0ef728 100644 --- a/indra/newview/lloutputmonitorctrl.cpp +++ b/indra/newview/lloutputmonitorctrl.cpp @@ -142,7 +142,7 @@ void LLOutputMonitorCtrl::draw() // Copied from llmediaremotectrl.cpp // *TODO: Give the LLOutputMonitorCtrl an agent-id to monitor, then - // call directly into gVoiceClient to ask if that agent-id is muted, is + // call directly into LLVoiceClient::getInstance() to ask if that agent-id is muted, is // speaking, and what power. This avoids duplicating data, which can get // out of sync. const F32 LEVEL_0 = LLVoiceClient::OVERDRIVEN_POWER_LEVEL / 3.f; @@ -151,14 +151,14 @@ void LLOutputMonitorCtrl::draw() if (getVisible() && mAutoUpdate && !mIsMuted && mSpeakerId.notNull()) { - setPower(gVoiceClient->getCurrentPower(mSpeakerId)); + setPower(LLVoiceClient::getInstance()->getCurrentPower(mSpeakerId)); if(mIsAgentControl) { - setIsTalking(gVoiceClient->getUserPTTState()); + setIsTalking(LLVoiceClient::getInstance()->getUserPTTState()); } else { - setIsTalking(gVoiceClient->getIsSpeaking(mSpeakerId)); + setIsTalking(LLVoiceClient::getInstance()->getIsSpeaking(mSpeakerId)); } } diff --git a/indra/newview/lloutputmonitorctrl.h b/indra/newview/lloutputmonitorctrl.h index b7454a5066..3a83da67e2 100644 --- a/indra/newview/lloutputmonitorctrl.h +++ b/indra/newview/lloutputmonitorctrl.h @@ -143,7 +143,7 @@ private: LLPointer<LLUIImage> mImageLevel2; LLPointer<LLUIImage> mImageLevel3; - /** whether to deal with gVoiceClient directly */ + /** whether to deal with LLVoiceClient::getInstance() directly */ bool mAutoUpdate; /** uuid of a speaker being monitored */ diff --git a/indra/newview/lloverlaybar.cpp b/indra/newview/lloverlaybar.cpp index 67e048885f..3f1b23ba14 100644 --- a/indra/newview/lloverlaybar.cpp +++ b/indra/newview/lloverlaybar.cpp @@ -258,7 +258,7 @@ void LLOverlayBar::refresh() { // update "remotes" childSetVisible("media_remote_container", TRUE); - childSetVisible("voice_remote_container", LLVoiceClient::voiceEnabled()); + childSetVisible("voice_remote_container", LLVoiceClient::getInstance()->voiceEnabled()); childSetVisible("state_buttons", TRUE); } diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index a0ba2f739b..b554af66f0 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -163,7 +163,7 @@ BOOL LLPanelAvatarNotes::postBuild() resetControls(); resetData(); - gVoiceClient->addObserver((LLVoiceClientStatusObserver*)this); + LLVoiceClient::getInstance()->addObserver((LLVoiceClientStatusObserver*)this); return TRUE; } @@ -374,7 +374,7 @@ void LLPanelAvatarNotes::onChange(EStatusType status, const std::string &channel return; } - childSetEnabled("call", LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking()); + childSetEnabled("call", LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking()); } void LLPanelAvatarNotes::setAvatarId(const LLUUID& id) @@ -518,7 +518,7 @@ BOOL LLPanelAvatarProfile::postBuild() pic = getChild<LLTextureCtrl>("real_world_pic"); pic->setFallbackImageName("default_profile_picture.j2c"); - gVoiceClient->addObserver((LLVoiceClientStatusObserver*)this); + LLVoiceClient::getInstance()->addObserver((LLVoiceClientStatusObserver*)this); resetControls(); resetData(); @@ -809,7 +809,7 @@ void LLPanelAvatarProfile::onChange(EStatusType status, const std::string &chann return; } - childSetEnabled("call", LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking()); + childSetEnabled("call", LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking()); } void LLPanelAvatarProfile::setAvatarId(const LLUUID& id) diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp index 706787e824..af6f240a2d 100644 --- a/indra/newview/llpanelgroup.cpp +++ b/indra/newview/llpanelgroup.cpp @@ -199,7 +199,7 @@ BOOL LLPanelGroup::postBuild() mJoinText = panel_general->getChild<LLUICtrl>("join_cost_text"); } - gVoiceClient->addObserver(this); + LLVoiceClient::getInstance()->addObserver(this); return TRUE; } @@ -320,7 +320,7 @@ void LLPanelGroup::onChange(EStatusType status, const std::string &channelURI, b return; } - childSetEnabled("btn_call", LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking()); + childSetEnabled("btn_call", LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking()); } void LLPanelGroup::notifyObservers() diff --git a/indra/newview/llpanelimcontrolpanel.cpp b/indra/newview/llpanelimcontrolpanel.cpp index c34f0633b9..709bb83fe4 100644 --- a/indra/newview/llpanelimcontrolpanel.cpp +++ b/indra/newview/llpanelimcontrolpanel.cpp @@ -81,7 +81,8 @@ void LLPanelChatControlPanel::onVoiceChannelStateChanged(const LLVoiceChannel::E void LLPanelChatControlPanel::updateCallButton() { - bool voice_enabled = LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking(); + // hide/show call button + bool voice_enabled = LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking(); LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(mSessionId); @@ -124,7 +125,7 @@ BOOL LLPanelChatControlPanel::postBuild() childSetAction("end_call_btn", boost::bind(&LLPanelChatControlPanel::onEndCallButtonClicked, this)); childSetAction("voice_ctrls_btn", boost::bind(&LLPanelChatControlPanel::onOpenVoiceControlsClicked, this)); - gVoiceClient->addObserver(this); + LLVoiceClient::getInstance()->addObserver(this); return TRUE; } diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index ee4dcc44fe..42e4b397db 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -51,11 +51,12 @@ #include "llfocusmgr.h" #include "lllineeditor.h" #include "llnotificationsutil.h" +#include "llsecapi.h" #include "llstartup.h" #include "lltextbox.h" #include "llui.h" #include "lluiconstants.h" -#include "llurlsimstring.h" +#include "llslurl.h" #include "llversioninfo.h" #include "llviewerhelp.h" #include "llviewertexturelist.h" @@ -77,6 +78,7 @@ #pragma warning(disable: 4355) // 'this' used in initializer list #endif // LL_WINDOWS +#include "llsdserialize.h" #define USE_VIEWER_AUTH 0 const S32 BLACK_BORDER_HEIGHT = 160; @@ -104,7 +106,6 @@ public: LLLoginRefreshHandler gLoginRefreshHandler; - // helper class that trys to download a URL from a web site and calls a method // on parent class indicating if the web server is working or not class LLIamHereLogin : public LLHTTPClient::Responder @@ -153,10 +154,6 @@ namespace { boost::intrusive_ptr< LLIamHereLogin > gResponsePtr = 0; }; -void set_start_location(LLUICtrl* ctrl, void* data) -{ - LLURLSimString::setString(ctrl->getValue().asString()); -} //--------------------------------------------------------------------------- // Public methods @@ -187,6 +184,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, delete LLPanelLogin::sInstance; } + mPasswordModified = FALSE; LLPanelLogin::sInstance = this; // add to front so we are the bottom-most child @@ -213,10 +211,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, } #if !USE_VIEWER_AUTH - childSetPrevalidate("first_name_edit", LLTextValidate::validateASCIIPrintableNoSpace); - childSetPrevalidate("last_name_edit", LLTextValidate::validateASCIIPrintableNoSpace); - - childSetCommitCallback("password_edit", mungePassword, this); + childSetPrevalidate("username_edit", LLTextValidate::validateASCIIPrintableNoPipe); getChild<LLLineEditor>("password_edit")->setKeystrokeCallback(onPassKey, this); // change z sort of clickable text to be behind buttons @@ -228,27 +223,19 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, LLComboBox* combo = getChild<LLComboBox>("start_location_combo"); - std::string sim_string = LLURLSimString::sInstance.mSimString; - if(sim_string.empty()) - { - LLURLSimString::setString(gSavedSettings.getString("LoginLocation")); - sim_string = LLURLSimString::sInstance.mSimString; - } - - if (!sim_string.empty()) + if(LLStartUp::getStartSLURL().getType() != LLSLURL::LOCATION) { - // Replace "<Type region name>" with this region name - combo->remove(2); - combo->add( sim_string ); - combo->setTextEntry(sim_string); - combo->setCurrentByIndex( 2 ); + LLSLURL slurl(gSavedSettings.getString("LoginLocation")); + LLStartUp::setStartSLURL(slurl); } - - combo->setCommitCallback( &set_start_location, NULL ); + updateLocationCombo(false); + + combo->setCommitCallback(onSelectLocation, NULL); LLComboBox* server_choice_combo = sInstance->getChild<LLComboBox>("server_combo"); server_choice_combo->setCommitCallback(onSelectServer, NULL); server_choice_combo->setFocusLostCallback(boost::bind(onServerComboLostFocus, _1)); + updateServerCombo(); childSetAction("connect_btn", onClickConnect, this); @@ -304,17 +291,10 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, // kick off a request to grab the url manually gResponsePtr = LLIamHereLogin::build( this ); - std::string login_page = gSavedSettings.getString("LoginPage"); - if (login_page.empty()) - { - login_page = getString( "real_url" ); - } - LLHTTPClient::head( login_page, gResponsePtr ); -#if !USE_VIEWER_AUTH - // Initialize visibility (and don't force visibility - use prefs) - refreshLocation( false ); -#endif + LLHTTPClient::head( LLGridManager::getInstance()->getLoginPage(), gResponsePtr ); + + updateLocationCombo(false); } @@ -378,21 +358,6 @@ void LLPanelLogin::setSiteIsAlive( bool alive ) } } -void LLPanelLogin::mungePassword(LLUICtrl* caller, void* user_data) -{ - LLPanelLogin* self = (LLPanelLogin*)user_data; - LLLineEditor* editor = (LLLineEditor*)caller; - std::string password = editor->getText(); - - // Re-md5 if we've changed at all - if (password != self->mIncomingPassword) - { - LLMD5 pass((unsigned char *)password.c_str()); - char munged_password[MD5HEX_STR_SIZE]; - pass.hex_digest(munged_password); - self->mMungedPassword = munged_password; - } -} LLPanelLogin::~LLPanelLogin() { @@ -499,14 +464,14 @@ void LLPanelLogin::giveFocus() if( sInstance ) { // Grab focus and move cursor to first blank input field - std::string first = sInstance->childGetText("first_name_edit"); + std::string username = sInstance->childGetText("username_edit"); std::string pass = sInstance->childGetText("password_edit"); - BOOL have_first = !first.empty(); + BOOL have_username = !username.empty(); BOOL have_pass = !pass.empty(); LLLineEditor* edit = NULL; - if (have_first && !have_pass) + if (have_username && !have_pass) { // User saved his name but not his password. Move // focus to password field. @@ -515,7 +480,7 @@ void LLPanelLogin::giveFocus() else { // User doesn't have a name, so start there. - edit = sInstance->getChild<LLLineEditor>("first_name_edit"); + edit = sInstance->getChild<LLLineEditor>("username_edit"); } if (edit) @@ -537,8 +502,8 @@ void LLPanelLogin::showLoginWidgets() // *TODO: Append all the usual login parameters, like first_login=Y etc. std::string splash_screen_url = sInstance->getString("real_url"); web_browser->navigateTo( splash_screen_url, "text/html" ); - LLUICtrl* first_name_edit = sInstance->getChild<LLUICtrl>("first_name_edit"); - first_name_edit->setFocus(TRUE); + LLUICtrl* username_edit = sInstance->getChild<LLUICtrl>("username_edit"); + username_edit->setFocus(TRUE); } // static @@ -560,77 +525,120 @@ void LLPanelLogin::show(const LLRect &rect, } // static -void LLPanelLogin::setFields(const std::string& firstname, - const std::string& lastname, - const std::string& password) +void LLPanelLogin::setFields(LLPointer<LLCredential> credential, + BOOL remember) { if (!sInstance) { llwarns << "Attempted fillFields with no login view shown" << llendl; return; } + LL_INFOS("Credentials") << "Setting login fields to " << *credential << LL_ENDL; - sInstance->childSetText("first_name_edit", firstname); - sInstance->childSetText("last_name_edit", lastname); - - // Max "actual" password length is 16 characters. - // Hex digests are always 32 characters. - if (password.length() == 32) + LLSD identifier = credential->getIdentifier(); + if((std::string)identifier["type"] == "agent") + { + sInstance->childSetText("username_edit", (std::string)identifier["first_name"] + " " + + (std::string)identifier["last_name"]); + } + else if((std::string)identifier["type"] == "account") + { + sInstance->childSetText("username_edit", (std::string)identifier["account_name"]); + } + else + { + sInstance->childSetText("username_edit", std::string()); + } + // if the password exists in the credential, set the password field with + // a filler to get some stars + LLSD authenticator = credential->getAuthenticator(); + LL_INFOS("Credentials") << "Setting authenticator field " << authenticator["type"].asString() << LL_ENDL; + if(authenticator.isMap() && + authenticator.has("secret") && + (authenticator["secret"].asString().size() > 0)) { + // This is a MD5 hex digest of a password. // We don't actually use the password input field, // fill it with MAX_PASSWORD characters so we get a // nice row of asterixes. const std::string filler("123456789!123456"); - sInstance->childSetText("password_edit", filler); - sInstance->mIncomingPassword = filler; - sInstance->mMungedPassword = password; + sInstance->childSetText("password_edit", std::string("123456789!123456")); } else { - // this is a normal text password - sInstance->childSetText("password_edit", password); - sInstance->mIncomingPassword = password; - LLMD5 pass((unsigned char *)password.c_str()); - char munged_password[MD5HEX_STR_SIZE]; - pass.hex_digest(munged_password); - sInstance->mMungedPassword = munged_password; + sInstance->childSetText("password_edit", std::string()); } + sInstance->childSetValue("remember_check", remember); } // static -void LLPanelLogin::addServer(const std::string& server, S32 domain_name) +void LLPanelLogin::getFields(LLPointer<LLCredential>& credential, + BOOL remember) { if (!sInstance) { - llwarns << "Attempted addServer with no login view shown" << llendl; + llwarns << "Attempted getFields with no login view shown" << llendl; return; } + + // load the credential so we can pass back the stored password or hash if the user did + // not modify the password field. + + credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); - LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo"); - combo->add(server, LLSD(domain_name) ); - combo->setCurrentByIndex(0); -} - -// static -void LLPanelLogin::getFields(std::string *firstname, - std::string *lastname, - std::string *password) -{ - if (!sInstance) + LLSD identifier = LLSD::emptyMap(); + LLSD authenticator = LLSD::emptyMap(); + + if(credential.notNull()) { - llwarns << "Attempted getFields with no login view shown" << llendl; - return; + authenticator = credential->getAuthenticator(); } - *firstname = sInstance->childGetText("first_name_edit"); - LLStringUtil::trim(*firstname); - - *lastname = sInstance->childGetText("last_name_edit"); - LLStringUtil::trim(*lastname); + std::string username = sInstance->childGetText("username_edit"); + LLStringUtil::trim(username); + std::string password = sInstance->childGetText("password_edit"); - *password = sInstance->mMungedPassword; + LL_INFOS2("Credentials", "Authentication") << "retrieving username:" << username << LL_ENDL; + // determine if the username is a first/last form or not. + size_t separator_index = username.find_first_of(' '); + if (separator_index == username.npos) + { + LL_INFOS2("Credentials", "Authentication") << "account: " << username << LL_ENDL; + // single username, so this is a 'clear' identifier + identifier["type"] = "account"; + identifier["account_name"] = username; + + if (LLPanelLogin::sInstance->mPasswordModified) + { + authenticator = LLSD::emptyMap(); + // password is plaintext + authenticator["type"] = "clear"; + authenticator["secret"] = password; + } + } + else if (separator_index == username.find_last_of(' ')) + { + LL_INFOS2("Credentials", "Authentication") << "agent: " << username << LL_ENDL; + // traditional firstname / lastname + 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["algorithm"] = "md5"; + LLMD5 pass((const U8 *)password.c_str()); + char md5pass[33]; /* Flawfinder: ignore */ + pass.hex_digest(md5pass); + authenticator["secret"] = md5pass; + } + } + credential = gSecAPIHandler->createCredential(LLGridManager::getInstance()->getGrid(), identifier, authenticator); + remember = sInstance->childGetValue("remember_check"); } // static @@ -650,64 +658,147 @@ BOOL LLPanelLogin::isGridComboDirty() } // static -void LLPanelLogin::getLocation(std::string &location) +BOOL LLPanelLogin::areCredentialFieldsDirty() { if (!sInstance) { - llwarns << "Attempted getLocation with no login view shown" << llendl; - return; + llwarns << "Attempted getServer with no login view shown" << llendl; } - - LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo"); - location = combo->getValue().asString(); + else + { + std::string username = sInstance->childGetText("username_edit"); + LLStringUtil::trim(username); + std::string password = sInstance->childGetText("password_edit"); + LLLineEditor* ctrl = sInstance->getChild<LLLineEditor>("username_edit"); + if(ctrl && ctrl->isDirty()) + { + return true; + } + ctrl = sInstance->getChild<LLLineEditor>("password_edit"); + if(ctrl && ctrl->isDirty()) + { + return true; + } + } + return false; } + // static -void LLPanelLogin::refreshLocation( bool force_visible ) +void LLPanelLogin::updateLocationCombo( bool force_visible ) { - if (!sInstance) return; - -#if USE_VIEWER_AUTH - loadLoginPage(); -#else + if (!sInstance) + { + return; + } + + llinfos << "updatelocationcombo " << LLStartUp::getStartSLURL().asString() << llendl; + LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo"); + + switch(LLStartUp::getStartSLURL().getType()) + { + case LLSLURL::LOCATION: + { + + combo->setCurrentByIndex( 2 ); + combo->setTextEntry(LLStartUp::getStartSLURL().getLocationString()); + break; + } + case LLSLURL::HOME_LOCATION: + combo->setCurrentByIndex(1); + break; + default: + combo->setCurrentByIndex(0); + break; + } + BOOL show_start = TRUE; - + if ( ! force_visible ) - { - // Don't show on first run after install - // Otherwise ShowStartLocation defaults to true. show_start = gSavedSettings.getBOOL("ShowStartLocation"); - } - - // Update the value of the location combo. - updateLocationUI(); sInstance->childSetVisible("start_location_combo", show_start); sInstance->childSetVisible("start_location_text", show_start); - - BOOL show_server = gSavedSettings.getBOOL("ForceShowGrid"); - sInstance->childSetVisible("server_combo", show_server); - -#endif + + sInstance->childSetVisible("server_combo", TRUE); } // static -void LLPanelLogin::updateLocationUI() +void LLPanelLogin::onSelectLocation(LLUICtrl*, void*) { if (!sInstance) return; - std::string sim_string = LLURLSimString::sInstance.mSimString; - if (!sim_string.empty()) + LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo"); + S32 index = combo->getCurrentIndex(); + + switch (index) { - // Replace "<Type region name>" with this region name - LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo"); - combo->remove(2); - combo->add( sim_string ); - combo->setTextEntry(sim_string); - combo->setCurrentByIndex( 2 ); + case 2: + { + LLSLURL slurl = LLSLURL(combo->getSelectedValue()); + if((slurl.getType() == LLSLURL::LOCATION) && + (slurl.getGrid() != LLStartUp::getStartSLURL().getGrid())) + { + + + // we've changed the grid, so update the grid selection + try + { + LLStartUp::setStartSLURL(slurl); + } + catch (LLInvalidGridName ex) + { + LLSD args; + args["GRID"] = slurl.getGrid(); + LLNotificationsUtil::add("InvalidGrid", args); + return; + } + loadLoginPage(); + } + break; + } + case 1: + { + LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME)); + break; + } + default: + { + LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_LAST)); + break; + } } } + +// static +void LLPanelLogin::getLocation(LLSLURL& slurl) +{ + LLSLURL result; + if (!sInstance) + { + llwarns << "Attempted getLocation with no login view shown" << llendl; + } + + LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo"); + + switch(combo->getCurrentIndex()) + { + case 0: + slurl = LLSLURL(LLSLURL::SIM_LOCATION_HOME); + case 1: + slurl = LLSLURL(LLSLURL::SIM_LOCATION_LAST); + default: + slurl = LLSLURL(combo->getValue().asString()); + } +} + +void LLPanelLogin::setLocation(const LLSLURL& slurl) +{ + LLStartUp::setStartSLURL(slurl); + updateServer(); +} + // static void LLPanelLogin::closePanel() { @@ -741,15 +832,13 @@ void LLPanelLogin::loadLoginPage() std::ostringstream oStr; - std::string login_page = gSavedSettings.getString("LoginPage"); - if (login_page.empty()) - { - login_page = sInstance->getString( "real_url" ); - } + std::string login_page = LLGridManager::getInstance()->getLoginPage(); + oStr << login_page; // Use the right delimeter depending on how LLURI parses the URL LLURI login_page_uri = LLURI(login_page); + std::string first_query_delimiter = "&"; if (login_page_uri.queryMap().size() == 0) { @@ -781,11 +870,10 @@ void LLPanelLogin::loadLoginPage() curl_free(curl_version); // Grid - char* curl_grid = curl_escape(LLViewerLogin::getInstance()->getGridLabel().c_str(), 0); + char* curl_grid = curl_escape(LLGridManager::getInstance()->getGridLoginID().c_str(), 0); oStr << "&grid=" << curl_grid; curl_free(curl_grid); - - gViewerWindow->setMenuBackgroundColor(false, !LLViewerLogin::getInstance()->isInProductionGrid()); + gViewerWindow->setMenuBackgroundColor(false, !LLGridManager::getInstance()->isInProductionGrid()); gLoginMenuBarView->setBackgroundColor(gMenuBarView->getBackgroundColor()); @@ -810,30 +898,20 @@ void LLPanelLogin::loadLoginPage() location = gSavedSettings.getString("LoginLocation"); } - std::string firstname, lastname; + std::string username; if(gSavedSettings.getLLSD("UserLoginInfo").size() == 3) { LLSD cmd_line_login = gSavedSettings.getLLSD("UserLoginInfo"); - firstname = cmd_line_login[0].asString(); - lastname = cmd_line_login[1].asString(); + username = cmd_line_login[0].asString() + " " + cmd_line_login[1]; password = cmd_line_login[2].asString(); } - if (firstname.empty()) - { - firstname = gSavedSettings.getString("FirstName"); - } - - if (lastname.empty()) - { - lastname = gSavedSettings.getString("LastName"); - } char* curl_region = curl_escape(region.c_str(), 0); - oStr <<"firstname=" << firstname << - "&lastname=" << lastname << "&location=" << location << "®ion=" << curl_region; + oStr <<"username=" << username << + "&location=" << location << "®ion=" << curl_region; curl_free(curl_region); @@ -866,7 +944,7 @@ void LLPanelLogin::loadLoginPage() #endif LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html"); - + // navigate to the "real" page if (gSavedSettings.getBOOL("RegInClient")) { @@ -915,34 +993,33 @@ void LLPanelLogin::onClickConnect(void *) // JC - Make sure the fields all get committed. sInstance->setFocus(FALSE); - std::string first = sInstance->childGetText("first_name_edit"); - std::string last = sInstance->childGetText("last_name_edit"); - LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo"); - std::string combo_text = combo->getSimple(); - - bool has_first_and_last = !(first.empty() || last.empty()); - bool has_location = false; - - if(combo_text=="<Type region name>" || combo_text =="") + LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo"); + LLSD combo_val = combo->getSelectedValue(); + if (combo_val.isUndefined()) { - // *NOTE: Mani - Location field is not always committed by this point! - // This may be duplicate work, but better than not doing the work! - LLURLSimString::sInstance.setString(""); + combo_val = combo->getValue(); } - else + if(combo_val.isUndefined()) { - // *NOTE: Mani - Location field is not always committed by this point! - LLURLSimString::sInstance.setString(combo_text); - has_location = true; + LLNotificationsUtil::add("StartRegionEmpty"); + return; + } + try + { + LLGridManager::getInstance()->setGridChoice(combo_val.asString()); } - - if(!has_first_and_last) + catch (LLInvalidGridName ex) { - LLNotificationsUtil::add("MustHaveAccountToLogIn"); + LLSD args; + args["GRID"] = combo_val.asString(); + LLNotificationsUtil::add("InvalidGrid", args); + return; } - else if(!has_location) + + std::string username = sInstance->childGetText("username_edit"); + if(username.empty()) { - LLNotificationsUtil::add("StartRegionEmpty"); + LLNotificationsUtil::add("MustHaveAccountToLogIn"); } else { @@ -1005,6 +1082,8 @@ void LLPanelLogin::onClickHelp(void*) // static void LLPanelLogin::onPassKey(LLLineEditor* caller, void* user_data) { + LLPanelLogin *This = (LLPanelLogin *) user_data; + This->mPasswordModified = TRUE; if (gKeyboard->getKeyDown(KEY_CAPSLOCK) && sCapslockDidNotification == FALSE) { LLNotificationsUtil::add("CapsKeyOn"); @@ -1012,54 +1091,90 @@ void LLPanelLogin::onPassKey(LLLineEditor* caller, void* user_data) } } -// static -void LLPanelLogin::onSelectServer(LLUICtrl*, void*) -{ - // *NOTE: The paramters for this method are ignored. - // LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe, void*) - // calls this method. - - // The user twiddled with the grid choice ui. - // apply the selection to the grid setting. - std::string grid_label; - S32 grid_index; - LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo"); - LLSD combo_val = combo->getValue(); - - if (LLSD::TypeInteger == combo_val.type()) +void LLPanelLogin::updateServer() +{ + try { - grid_index = combo->getValue().asInteger(); - if ((S32)GRID_INFO_OTHER == grid_index) + updateServerCombo(); + // if they've selected another grid, we should load the credentials + // for that grid and set them to the UI. + if(sInstance && !sInstance->areCredentialFieldsDirty()) { - // This happens if the user specifies a custom grid - // via command line. - grid_label = combo->getSimple(); + LLPointer<LLCredential> credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + bool remember = sInstance->childGetValue("remember_check"); + sInstance->setFields(credential, remember); } + // grid changed so show new splash screen (possibly) + loadLoginPage(); + updateLocationCombo(LLStartUp::getStartSLURL().getType() == LLSLURL::LOCATION); } - else + catch (LLInvalidGridName ex) { - // no valid selection, return other - grid_index = (S32)GRID_INFO_OTHER; - grid_label = combo_val.asString(); + // do nothing } +} - // This new seelction will override preset uris - // from the command line. - LLViewerLogin* vl = LLViewerLogin::getInstance(); - vl->resetURIs(); - if(grid_index != GRID_INFO_OTHER) +void LLPanelLogin::updateServerCombo() +{ + if (!sInstance) { - vl->setGridChoice((EGridInfo)grid_index); + return; } - else + // We add all of the possible values, sorted, and then add a bar and the current value at the top + LLComboBox* server_choice_combo = sInstance->getChild<LLComboBox>("server_combo"); + server_choice_combo->removeall(); +#ifdef LL_RELEASE_FOR_DOWNLOAD + std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids(TRUE); +#else + std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids(FALSE); +#endif + for (std::map<std::string, std::string>::iterator grid_choice = known_grids.begin(); + grid_choice != known_grids.end(); + grid_choice++) { - vl->setGridChoice(grid_label); + if (!grid_choice->first.empty()) + { + server_choice_combo->add(grid_choice->second, grid_choice->first, ADD_SORTED); + } } + + server_choice_combo->addSeparator(ADD_TOP); + + server_choice_combo->add(LLGridManager::getInstance()->getGridLabel(), + LLGridManager::getInstance()->getGrid(), ADD_TOP); + + server_choice_combo->selectFirstItem(); +} - // grid changed so show new splash screen (possibly) - loadLoginPage(); +// static +void LLPanelLogin::onSelectServer(LLUICtrl*, void*) +{ + // *NOTE: The paramters for this method are ignored. + // LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe, void*) + // calls this method. + LL_INFOS("AppInit") << "onSelectServer" << LL_ENDL; + // The user twiddled with the grid choice ui. + // apply the selection to the grid setting. + LLPointer<LLCredential> credential; + + LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo"); + LLSD combo_val = combo->getSelectedValue(); + if (combo_val.isUndefined()) + { + combo_val = combo->getValue(); + } + + combo = sInstance->getChild<LLComboBox>("start_location_combo"); + combo->setCurrentByIndex(1); + LLStartUp::setStartSLURL(LLSLURL(gSavedSettings.getString("LoginLocation"))); + LLGridManager::getInstance()->setGridChoice(combo_val.asString()); + // This new selection will override preset uris + // from the command line. + updateServer(); + updateLocationCombo(false); + updateLoginPanelLinks(); } void LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe) @@ -1072,3 +1187,14 @@ void LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe) onSelectServer(combo, NULL); } } + +void LLPanelLogin::updateLoginPanelLinks() +{ + LLSD grid_data = LLGridManager::getInstance()->getGridInfo(); + bool system_grid = grid_data.has(GRID_IS_SYSTEM_GRID_VALUE); + + // need to call through sInstance, as it's called from onSelectServer, which + // is static. + sInstance->childSetVisible("create_new_account_text", system_grid); + sInstance->childSetVisible("forgot_password_text", system_grid); +} diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index 1fdc3a9361..0b0ef38d77 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -41,6 +41,8 @@ class LLLineEditor; class LLUIImage; class LLPanelLoginListener; +class LLSLURL; +class LLCredential; class LLPanelLogin: public LLPanel, @@ -65,20 +67,16 @@ public: void (*callback)(S32 option, void* user_data), void* callback_data); - // Remember password checkbox is set via gSavedSettings "RememberPassword" - static void setFields(const std::string& firstname, const std::string& lastname, - const std::string& password); + static void setFields(LLPointer<LLCredential> credential, BOOL remember); - static void addServer(const std::string& server, S32 domain_name); - static void refreshLocation( bool force_visible ); - static void updateLocationUI(); - - static void getFields(std::string *firstname, std::string *lastname, - std::string *password); + static void getFields(LLPointer<LLCredential>& credential, BOOL remember); static BOOL isGridComboDirty(); - static void getLocation(std::string &location); - + static BOOL areCredentialFieldsDirty(); + static void getLocation(LLSLURL& slurl); + static void setLocation(const LLSLURL& slurl); + + static void updateLocationCombo(bool force_visible); // simply update the combo box static void closePanel(); void setSiteIsAlive( bool alive ); @@ -86,7 +84,6 @@ public: static void loadLoginPage(); static void giveFocus(); static void setAlwaysRefresh(bool refresh); - static void mungePassword(LLUICtrl* caller, void* user_data); // inherited from LLViewerMediaObserver /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); @@ -103,6 +100,11 @@ private: static void onPassKey(LLLineEditor* caller, void* user_data); static void onSelectServer(LLUICtrl*, void*); static void onServerComboLostFocus(LLFocusableElement*); + static void updateServerCombo(); + static void onSelectLocation(LLUICtrl*, void*); + + static void updateServer(); // update the combo box, change the login page to the new server, clear the combo + static void updateLoginPanelLinks(); private: LLPointer<LLUIImage> mLogoImage; @@ -111,8 +113,7 @@ private: void (*mCallback)(S32 option, void *userdata); void* mCallbackData; - std::string mIncomingPassword; - std::string mMungedPassword; + BOOL mPasswordModified; static LLPanelLogin* sInstance; static BOOL sCapslockDidNotification; diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 8a1be2706c..4f728c8d51 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -619,7 +619,7 @@ BOOL LLPanelPeople::postBuild() if(recent_view_sort) mRecentViewSortMenuHandle = recent_view_sort->getHandle(); - gVoiceClient->addObserver(this); + LLVoiceClient::getInstance()->addObserver(this); // call this method in case some list is empty and buttons can be in inconsistent state updateButtons(); @@ -806,7 +806,7 @@ void LLPanelPeople::updateButtons() } } - bool enable_calls = gVoiceClient->voiceWorking() && gVoiceClient->voiceEnabled(); + bool enable_calls = LLVoiceClient::getInstance()->isVoiceWorking() && LLVoiceClient::getInstance()->voiceEnabled(); buttonSetEnabled("teleport_btn", friends_tab_active && item_selected && isFriendOnline(selected_uuids.front())); buttonSetEnabled("view_profile_btn", item_selected); diff --git a/indra/newview/llpanelplacestab.cpp b/indra/newview/llpanelplacestab.cpp index 9806b8c64d..6b12796e59 100644 --- a/indra/newview/llpanelplacestab.cpp +++ b/indra/newview/llpanelplacestab.cpp @@ -70,10 +70,7 @@ void LLPanelPlacesTab::onRegionResponse(const LLVector3d& landmark_global_pos, std::string sl_url; if ( gotSimName ) { - F32 region_x = (F32)fmod( landmark_global_pos.mdV[VX], (F64)REGION_WIDTH_METERS ); - F32 region_y = (F32)fmod( landmark_global_pos.mdV[VY], (F64)REGION_WIDTH_METERS ); - - sl_url = LLSLURL::buildSLURL(sim_name, llround(region_x), llround(region_y), llround((F32)landmark_global_pos.mdV[VZ])); + sl_url = LLSLURL(sim_name, landmark_global_pos).getSLURLString(); } else { diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp index 0a20ff6226..268738d88c 100644 --- a/indra/newview/llparticipantlist.cpp +++ b/indra/newview/llparticipantlist.cpp @@ -346,7 +346,6 @@ void LLParticipantList::addAvatarIDExceptAgent(const LLUUID& avatar_id) { if (mExcludeAgent && gAgent.getID() == avatar_id) return; if (mAvatarList->contains(avatar_id)) return; - mAvatarList->getIDs().push_back(avatar_id); mAvatarList->setDirty(); adjustParticipant(avatar_id); @@ -632,7 +631,7 @@ bool LLParticipantList::LLParticipantListMenu::enableContextMenuItem(const LLSD& else if (item == "can_call") { bool not_agent = mUUIDs.front() != gAgentID; - bool can_call = not_agent && LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking(); + bool can_call = not_agent && LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking(); return can_call; } diff --git a/indra/newview/llsecapi.cpp b/indra/newview/llsecapi.cpp new file mode 100644 index 0000000000..ba343f5387 --- /dev/null +++ b/indra/newview/llsecapi.cpp @@ -0,0 +1,161 @@ +/** + * @file llsecapi.cpp + * @brief Security API for services such as certificate handling + * secure local storage, etc. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + + +#include "llviewerprecompiledheaders.h" +#include "llsecapi.h" +#include "llsechandler_basic.h" +#include <openssl/evp.h> +#include <map> +#include "llhttpclient.h" + + + +std::map<std::string, LLPointer<LLSecAPIHandler> > gHandlerMap; +LLPointer<LLSecAPIHandler> gSecAPIHandler; + +void initializeSecHandler() +{ + OpenSSL_add_all_algorithms(); + OpenSSL_add_all_ciphers(); + OpenSSL_add_all_digests(); + gHandlerMap[BASIC_SECHANDLER] = new LLSecAPIBasicHandler(); + + + // Currently, we only have the Basic handler, so we can point the main sechandler + // pointer to the basic handler. Later, we'll create a wrapper handler that + // selects the appropriate sechandler as needed, for instance choosing the + // mac keyring handler, with fallback to the basic sechandler + gSecAPIHandler = gHandlerMap[BASIC_SECHANDLER]; + + // initialize all SecAPIHandlers + LLProtectedDataException ex = LLProtectedDataException(""); + std::map<std::string, LLPointer<LLSecAPIHandler> >::const_iterator itr; + for(itr = gHandlerMap.begin(); itr != gHandlerMap.end(); ++itr) + { + LLPointer<LLSecAPIHandler> handler = (*itr).second; + try + { + handler->init(); + } + catch (LLProtectedDataException e) + { + ex = e; + } + } + if (ex.getMessage().length() > 0 ) // an exception was thrown. + { + throw ex; + } + +} +// start using a given security api handler. If the string is empty +// the default is used +LLPointer<LLSecAPIHandler> getSecHandler(const std::string& handler_type) +{ + if (gHandlerMap.find(handler_type) != gHandlerMap.end()) + { + return gHandlerMap[handler_type]; + } + else + { + return LLPointer<LLSecAPIHandler>(NULL); + } +} +// register a handler +void registerSecHandler(const std::string& handler_type, + LLPointer<LLSecAPIHandler>& handler) +{ + gHandlerMap[handler_type] = handler; +} + +std::ostream& operator <<(std::ostream& s, const LLCredential& cred) +{ + return s << (std::string)cred; +} + + +// secapiSSLCertVerifyCallback +// basic callback called when a cert verification is requested. +// calls SECAPI to validate the context +// not initialized in the above initialization function, due to unit tests +// see llappviewer + +int secapiSSLCertVerifyCallback(X509_STORE_CTX *ctx, void *param) +{ + LLURLRequest *req = (LLURLRequest *)param; + LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore(""); + LLPointer<LLCertificateChain> chain = gSecAPIHandler->getCertificateChain(ctx); + LLSD validation_params = LLSD::emptyMap(); + LLURI uri(req->getURL()); + validation_params[CERT_HOSTNAME] = uri.hostName(); + try + { + chain->validate(VALIDATION_POLICY_SSL, store, validation_params); + } + catch (LLCertValidationTrustException& cert_exception) + { + LL_WARNS("AppInit") << "Cert not trusted: " << cert_exception.getMessage() << LL_ENDL; + return 0; + } + catch (LLCertException& cert_exception) + { + LL_WARNS("AppInit") << "cert error " << cert_exception.getMessage() << LL_ENDL; + return 0; + } + catch (...) + { + LL_WARNS("AppInit") << "cert error " << LL_ENDL; + return 0; + } + return 1; +} + +LLSD LLCredential::getLoginParams() +{ + LLSD result = LLSD::emptyMap(); + 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"]; + + } + return result; +} diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h new file mode 100644 index 0000000000..5211dc2699 --- /dev/null +++ b/indra/newview/llsecapi.h @@ -0,0 +1,493 @@ +/** + * @file llsecapi.h + * @brief Security API for services such as certificate handling + * secure local storage, etc. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LLSECAPI_H +#define LLSECAPI_H +#include <vector> +#include <openssl/x509.h> +#include <ostream> + +#ifdef LL_WINDOWS +#pragma warning(disable:4250) +#endif // LL_WINDOWS + +// All error handling is via exceptions. + + +#define CERT_SUBJECT_NAME "subject_name" +#define CERT_ISSUER_NAME "issuer_name" +#define CERT_NAME_CN "commonName" + +#define CERT_SUBJECT_NAME_STRING "subject_name_string" +#define CERT_ISSUER_NAME_STRING "issuer_name_string" + +#define CERT_SERIAL_NUMBER "serial_number" + +#define CERT_VALID_FROM "valid_from" +#define CERT_VALID_TO "valid_to" +#define CERT_SHA1_DIGEST "sha1_digest" +#define CERT_MD5_DIGEST "md5_digest" +#define CERT_HOSTNAME "hostname" +#define CERT_BASIC_CONSTRAINTS "basicConstraints" +#define CERT_BASIC_CONSTRAINTS_CA "CA" +#define CERT_BASIC_CONSTRAINTS_PATHLEN "pathLen" + +#define CERT_KEY_USAGE "keyUsage" +#define CERT_KU_DIGITAL_SIGNATURE "digitalSignature" +#define CERT_KU_NON_REPUDIATION "nonRepudiation" +#define CERT_KU_KEY_ENCIPHERMENT "keyEncipherment" +#define CERT_KU_DATA_ENCIPHERMENT "dataEncipherment" +#define CERT_KU_KEY_AGREEMENT "keyAgreement" +#define CERT_KU_CERT_SIGN "certSigning" +#define CERT_KU_CRL_SIGN "crlSigning" +#define CERT_KU_ENCIPHER_ONLY "encipherOnly" +#define CERT_KU_DECIPHER_ONLY "decipherOnly" + +#define BASIC_SECHANDLER "BASIC_SECHANDLER" +#define CERT_VALIDATION_DATE "validation_date" + +#define CERT_EXTENDED_KEY_USAGE "extendedKeyUsage" +#define CERT_EKU_SERVER_AUTH SN_server_auth + +#define CERT_SUBJECT_KEY_IDENTFIER "subjectKeyIdentifier" +#define CERT_AUTHORITY_KEY_IDENTIFIER "authorityKeyIdentifier" +#define CERT_AUTHORITY_KEY_IDENTIFIER_ID "authorityKeyIdentifierId" +#define CERT_AUTHORITY_KEY_IDENTIFIER_NAME "authorityKeyIdentifierName" +#define CERT_AUTHORITY_KEY_IDENTIFIER_SERIAL "authorityKeyIdentifierSerial" + +// validate the current time lies within +// the validation period of the cert +#define VALIDATION_POLICY_TIME 1 + +// validate that the CA, or some cert in the chain +// lies within the certificate store +#define VALIDATION_POLICY_TRUSTED 2 + +// validate that the subject name of +// the cert contains the passed in hostname +// or validates against the hostname +#define VALIDATION_POLICY_HOSTNAME 4 + + +// validate that the cert contains the SSL EKU +#define VALIDATION_POLICY_SSL_KU 8 + +// validate that the cert contains the SSL EKU +#define VALIDATION_POLICY_CA_KU 16 + +#define VALIDATION_POLICY_CA_BASIC_CONSTRAINTS 32 + +// validate that the cert is correct for SSL +#define VALIDATION_POLICY_SSL (VALIDATION_POLICY_TIME | \ + VALIDATION_POLICY_HOSTNAME | \ + VALIDATION_POLICY_TRUSTED | \ + VALIDATION_POLICY_SSL_KU | \ + VALIDATION_POLICY_CA_BASIC_CONSTRAINTS | \ + VALIDATION_POLICY_CA_KU) + + + + + + +class LLProtectedDataException +{ +public: + LLProtectedDataException(const char *msg) + { + LL_WARNS("SECAPI") << "Protected Data Error: " << (std::string)msg << LL_ENDL; + mMsg = (std::string)msg; + } + std::string getMessage() { return mMsg; } +protected: + std::string mMsg; +}; + +// class LLCertificate +// parent class providing an interface for certifiate. +// LLCertificates are considered unmodifiable +// Certificates are pulled out of stores, or created via +// factory calls +class LLCertificate : public LLRefCount +{ + LOG_CLASS(LLCertificate); +public: + LLCertificate() {} + + virtual ~LLCertificate() {} + + // return a PEM encoded certificate. The encoding + // includes the -----BEGIN CERTIFICATE----- and end certificate elements + virtual std::string getPem() const=0; + + // return a DER encoded certificate + virtual std::vector<U8> getBinary() const=0; + + // return an LLSD object containing information about the certificate + // such as its name, signature, expiry time, serial number + virtual LLSD getLLSD() const=0; + + // return an openSSL X509 struct for the certificate + virtual X509* getOpenSSLX509() const=0; + +}; + +// class LLCertificateVector +// base class for a list of certificates. + + +class LLCertificateVector : public LLRefCount +{ + +public: + + LLCertificateVector() {}; + virtual ~LLCertificateVector() {}; + + // base iterator implementation class, providing + // the functionality needed for the iterator class. + class iterator_impl : public LLRefCount + { + public: + iterator_impl() {}; + virtual ~iterator_impl() {}; + virtual void seek(bool incr)=0; + virtual LLPointer<iterator_impl> clone() const=0; + virtual bool equals(const LLPointer<iterator_impl>& _iter) const=0; + virtual LLPointer<LLCertificate> get()=0; + }; + + // iterator class + class iterator + { + public: + iterator(LLPointer<iterator_impl> impl) : mImpl(impl) {} + iterator() : mImpl(NULL) {} + iterator(const iterator& _iter) {mImpl = _iter.mImpl->clone(); } + ~iterator() {} + iterator& operator++() { if(mImpl.notNull()) mImpl->seek(true); return *this;} + iterator& operator--() { if(mImpl.notNull()) mImpl->seek(false); return *this;} + + iterator operator++(int) { iterator result = *this; if(mImpl.notNull()) mImpl->seek(true); return result;} + iterator operator--(int) { iterator result = *this; if(mImpl.notNull()) mImpl->seek(false); return result;} + LLPointer<LLCertificate> operator*() { return mImpl->get(); } + + LLPointer<iterator_impl> mImpl; + protected: + friend bool operator==(const LLCertificateVector::iterator& _lhs, const LLCertificateVector::iterator& _rhs); + bool equals(const iterator& _iter) const { return mImpl->equals(_iter.mImpl); } + }; + + // numeric indexer + virtual LLPointer<LLCertificate> operator[](int)=0; + + // Iteration + virtual iterator begin()=0; + + virtual iterator end()=0; + + // find a cert given params + virtual iterator find(const LLSD& params) =0; + + // return the number of certs in the store + virtual int size() const = 0; + + // append the cert to the store. if a copy of the cert already exists in the store, it is removed first + virtual void add(LLPointer<LLCertificate> cert)=0; + + // insert the cert to the store. if a copy of the cert already exists in the store, it is removed first + virtual void insert(iterator location, LLPointer<LLCertificate> cert)=0; + + // remove a certificate from the store + virtual LLPointer<LLCertificate> erase(iterator cert)=0; +}; + + +// class LLCertificateStore +// represents a store of certificates, typically a store of root CA +// certificates. The store can be persisted, and can be used to validate +// a cert chain +// +class LLCertificateStore : virtual public LLCertificateVector +{ + +public: + + LLCertificateStore() {} + virtual ~LLCertificateStore() {} + + // persist the store + virtual void save()=0; + + // 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<LLCertificateStore> ca_store, + const LLSD& validation_params) =0; +}; + + + + +inline +bool operator==(const LLCertificateVector::iterator& _lhs, const LLCertificateVector::iterator& _rhs) +{ + return _lhs.equals(_rhs); +} +inline +bool operator!=(const LLCertificateVector::iterator& _lhs, const LLCertificateVector::iterator& _rhs) +{ + return !(_lhs == _rhs); +} + + +// +// LLCredential - interface for credentials providing the following functionality: +// * persistance of credential information based on grid (for saving username/password) +// * serialization to an OGP identifier/authenticator pair +// +class LLCredential : public LLRefCount +{ +public: + + LLCredential() {} + + LLCredential(const std::string& grid) + { + mGrid = grid; + mIdentifier = LLSD::emptyMap(); + mAuthenticator = LLSD::emptyMap(); + } + + virtual ~LLCredential() {} + + virtual void setCredentialData(const LLSD& identifier, const LLSD& authenticator) + { + mIdentifier = identifier; + mAuthenticator = authenticator; + } + virtual LLSD getIdentifier() { return mIdentifier; } + virtual LLSD getAuthenticator() { return mAuthenticator; } + virtual LLSD getLoginParams(); + virtual std::string getGrid() { return mGrid; } + + + virtual void clearAuthenticator() { mAuthenticator = LLSD(); } + virtual std::string userID() const { return std::string("unknown");} + virtual std::string asString() const { return std::string("unknown");} + operator std::string() const { return asString(); } +protected: + LLSD mIdentifier; + LLSD mAuthenticator; + std::string mGrid; +}; + +std::ostream& operator <<(std::ostream& s, const LLCredential& cred); + + +// All error handling is via exceptions. + +class LLCertException +{ +public: + LLCertException(LLPointer<LLCertificate> cert, const char* msg) + { + + mCert = cert; + + LL_WARNS("SECAPI") << "Certificate Error: " << (std::string)msg << LL_ENDL; + mMsg = (std::string)msg; + } + LLPointer<LLCertificate> getCert() { return mCert; } + std::string getMessage() { return mMsg; } +protected: + LLPointer<LLCertificate> mCert; + std::string mMsg; +}; + +class LLInvalidCertificate : public LLCertException +{ +public: + LLInvalidCertificate(LLPointer<LLCertificate> cert) : LLCertException(cert, "CertInvalid") + { + } +protected: +}; + +class LLCertValidationTrustException : public LLCertException +{ +public: + LLCertValidationTrustException(LLPointer<LLCertificate> cert) : LLCertException(cert, "CertUntrusted") + { + } +protected: +}; + +class LLCertValidationHostnameException : public LLCertException +{ +public: + LLCertValidationHostnameException(std::string hostname, + LLPointer<LLCertificate> cert) : LLCertException(cert, "CertInvalidHostname") + { + mHostname = hostname; + } + + std::string getHostname() { return mHostname; } +protected: + std::string mHostname; +}; + +class LLCertValidationExpirationException : public LLCertException +{ +public: + LLCertValidationExpirationException(LLPointer<LLCertificate> cert, + LLDate current_time) : LLCertException(cert, "CertExpired") + { + mTime = current_time; + } + LLDate GetTime() { return mTime; } +protected: + LLDate mTime; +}; + +class LLCertKeyUsageValidationException : public LLCertException +{ +public: + LLCertKeyUsageValidationException(LLPointer<LLCertificate> cert) : LLCertException(cert, "CertKeyUsage") + { + } +protected: +}; + +class LLCertBasicConstraintsValidationException : public LLCertException +{ +public: + LLCertBasicConstraintsValidationException(LLPointer<LLCertificate> cert) : LLCertException(cert, "CertBasicConstraints") + { + } +protected: +}; + +class LLCertValidationInvalidSignatureException : public LLCertException +{ +public: + LLCertValidationInvalidSignatureException(LLPointer<LLCertificate> cert) : LLCertException(cert, "CertInvalidSignature") + { + } +protected: +}; + +// LLSecAPIHandler Class +// Interface handler class for the various security storage handlers. +class LLSecAPIHandler : public LLRefCount +{ +public: + + + LLSecAPIHandler() {} + virtual ~LLSecAPIHandler() {} + + // initialize the SecAPIHandler + virtual void init() {}; + + // instantiate a certificate from a pem string + virtual LLPointer<LLCertificate> getCertificate(const std::string& pem_cert)=0; + + + + // instiate a certificate from an openssl X509 structure + virtual LLPointer<LLCertificate> getCertificate(X509* openssl_cert)=0; + + // instantiate a chain from an X509_STORE_CTX + virtual LLPointer<LLCertificateChain> getCertificateChain(const X509_STORE_CTX* chain)=0; + + // instantiate a cert store given it's id. if a persisted version + // exists, it'll be loaded. If not, one will be created (but not + // persisted) + virtual LLPointer<LLCertificateStore> getCertificateStore(const std::string& store_id)=0; + + // persist data in a protected store + virtual void setProtectedData(const std::string& data_type, + const std::string& data_id, + const LLSD& data)=0; + + // retrieve protected data + virtual LLSD getProtectedData(const std::string& data_type, + const std::string& data_id)=0; + + // delete a protected data item from the store + virtual void deleteProtectedData(const std::string& data_type, + const std::string& data_id)=0; + + virtual LLPointer<LLCredential> createCredential(const std::string& grid, + const LLSD& identifier, + const LLSD& authenticator)=0; + + virtual LLPointer<LLCredential> loadCredential(const std::string& grid)=0; + + virtual void saveCredential(LLPointer<LLCredential> cred, bool save_authenticator)=0; + + virtual void deleteCredential(LLPointer<LLCredential> cred)=0; + +}; + +void initializeSecHandler(); + +// retrieve a security api depending on the api type +LLPointer<LLSecAPIHandler> getSecHandler(const std::string& handler_type); + +void registerSecHandler(const std::string& handler_type, + LLPointer<LLSecAPIHandler>& handler); + +extern LLPointer<LLSecAPIHandler> gSecAPIHandler; + + +int secapiSSLCertVerifyCallback(X509_STORE_CTX *ctx, void *param); + + +#endif // LL_SECAPI_H diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp new file mode 100644 index 0000000000..51e250ffc6 --- /dev/null +++ b/indra/newview/llsechandler_basic.cpp @@ -0,0 +1,1586 @@ +/** + * @file llsechandler_basic.cpp + * @brief Security API for services such as certificate handling + * secure local storage, etc. + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-2000, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * +LLS * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + + +#include "llviewerprecompiledheaders.h" +#include "llsecapi.h" +#include "llsechandler_basic.h" +#include "llsdserialize.h" +#include "llviewernetwork.h" +#include "llxorcipher.h" +#include "llfile.h" +#include "lldir.h" +#include "llviewercontrol.h" +#include <vector> +#include <ios> +#include <openssl/ossl_typ.h> +#include <openssl/x509.h> +#include <openssl/x509v3.h> +#include <openssl/pem.h> +#include <openssl/asn1.h> +#include <openssl/rand.h> +#include <openssl/err.h> +#include <iostream> +#include <iomanip> +#include <time.h> + + + +// 128 bits of salt data... +#define STORE_SALT_SIZE 16 +#define BUFFER_READ_SIZE 256 +std::string cert_string_from_asn1_string(ASN1_STRING* value); +std::string cert_string_from_octet_string(ASN1_OCTET_STRING* value); + +LLSD _basic_constraints_ext(X509* cert); +LLSD _key_usage_ext(X509* cert); +LLSD _ext_key_usage_ext(X509* cert); +LLSD _subject_key_identifier_ext(X509 *cert); +LLSD _authority_key_identifier_ext(X509* cert); + +LLBasicCertificate::LLBasicCertificate(const std::string& pem_cert) +{ + + // BIO_new_mem_buf returns a read only bio, but takes a void* which isn't const + // so we need to cast it. + BIO * pem_bio = BIO_new_mem_buf((void*)pem_cert.c_str(), pem_cert.length()); + if(pem_bio == NULL) + { + LL_WARNS("SECAPI") << "Could not allocate an openssl memory BIO." << LL_ENDL; + throw LLInvalidCertificate(this); + } + mCert = NULL; + PEM_read_bio_X509(pem_bio, &mCert, 0, NULL); + BIO_free(pem_bio); + if (!mCert) + { + throw LLInvalidCertificate(this); + } + _initLLSD(); +} + + +LLBasicCertificate::LLBasicCertificate(X509* pCert) +{ + if (!pCert || !pCert->cert_info) + { + throw LLInvalidCertificate(this); + } + mCert = X509_dup(pCert); + _initLLSD(); +} + +LLBasicCertificate::~LLBasicCertificate() +{ + if(mCert) + { + X509_free(mCert); + } +} + +// +// retrieve the pem using the openssl functionality +std::string LLBasicCertificate::getPem() const +{ + char * pem_bio_chars = NULL; + // a BIO is the equivalent of a 'std::stream', and + // can be a file, mem stream, whatever. Grab a memory based + // BIO for the result + BIO *pem_bio = BIO_new(BIO_s_mem()); + if (!pem_bio) + { + LL_WARNS("SECAPI") << "Could not allocate an openssl memory BIO." << LL_ENDL; + return std::string(); + } + PEM_write_bio_X509(pem_bio, mCert); + int length = BIO_get_mem_data(pem_bio, &pem_bio_chars); + std::string result = std::string(pem_bio_chars, length); + BIO_free(pem_bio); + return result; +} + +// get the DER encoding for the cert +// DER is a binary encoding format for certs... +std::vector<U8> LLBasicCertificate::getBinary() const +{ + U8 * der_bio_data = NULL; + // get a memory bio + BIO *der_bio = BIO_new(BIO_s_mem()); + if (!der_bio) + { + LL_WARNS("SECAPI") << "Could not allocate an openssl memory BIO." << LL_ENDL; + return std::vector<U8>(); + } + i2d_X509_bio(der_bio, mCert); + int length = BIO_get_mem_data(der_bio, &der_bio_data); + std::vector<U8> result(length); + // vectors are guranteed to be a contiguous chunk of memory. + memcpy(&result[0], der_bio_data, length); + BIO_free(der_bio); + return result; +} + + +LLSD LLBasicCertificate::getLLSD() const +{ + return mLLSDInfo; +} + +// Initialize the LLSD info for the certificate +LLSD& LLBasicCertificate::_initLLSD() +{ + + // call the various helpers to build the LLSD + mLLSDInfo[CERT_SUBJECT_NAME] = cert_name_from_X509_NAME(X509_get_subject_name(mCert)); + mLLSDInfo[CERT_ISSUER_NAME] = cert_name_from_X509_NAME(X509_get_issuer_name(mCert)); + mLLSDInfo[CERT_SUBJECT_NAME_STRING] = cert_string_name_from_X509_NAME(X509_get_subject_name(mCert)); + mLLSDInfo[CERT_ISSUER_NAME_STRING] = cert_string_name_from_X509_NAME(X509_get_issuer_name(mCert)); + ASN1_INTEGER *sn = X509_get_serialNumber(mCert); + if (sn != NULL) + { + mLLSDInfo[CERT_SERIAL_NUMBER] = cert_string_from_asn1_integer(sn); + } + + mLLSDInfo[CERT_VALID_TO] = cert_date_from_asn1_time(X509_get_notAfter(mCert)); + mLLSDInfo[CERT_VALID_FROM] = cert_date_from_asn1_time(X509_get_notBefore(mCert)); + mLLSDInfo[CERT_SHA1_DIGEST] = cert_get_digest("sha1", mCert); + mLLSDInfo[CERT_MD5_DIGEST] = cert_get_digest("md5", mCert); + // add the known extensions + mLLSDInfo[CERT_BASIC_CONSTRAINTS] = _basic_constraints_ext(mCert); + mLLSDInfo[CERT_KEY_USAGE] = _key_usage_ext(mCert); + mLLSDInfo[CERT_EXTENDED_KEY_USAGE] = _ext_key_usage_ext(mCert); + mLLSDInfo[CERT_SUBJECT_KEY_IDENTFIER] = _subject_key_identifier_ext(mCert); + mLLSDInfo[CERT_AUTHORITY_KEY_IDENTIFIER] = _authority_key_identifier_ext(mCert); + return mLLSDInfo; +} + +// Retrieve the basic constraints info +LLSD _basic_constraints_ext(X509* cert) +{ + LLSD result; + BASIC_CONSTRAINTS *bs = (BASIC_CONSTRAINTS *)X509_get_ext_d2i(cert, NID_basic_constraints, NULL, NULL); + if(bs) + { + result = LLSD::emptyMap(); + // Determines whether the cert can be used as a CA + result[CERT_BASIC_CONSTRAINTS_CA] = (bool)bs->ca; + + if(bs->pathlen) + { + // the pathlen determines how deep a certificate chain can be from + // this CA + if((bs->pathlen->type == V_ASN1_NEG_INTEGER) + || !bs->ca) + { + result[CERT_BASIC_CONSTRAINTS_PATHLEN] = 0; + } + else + { + result[CERT_BASIC_CONSTRAINTS_PATHLEN] = (int)ASN1_INTEGER_get(bs->pathlen); + } + } + + } + return result; +} + +// retrieve the key usage, which specifies how the cert can be used. +// +LLSD _key_usage_ext(X509* cert) +{ + LLSD result; + ASN1_STRING *usage_str = (ASN1_STRING *)X509_get_ext_d2i(cert, NID_key_usage, NULL, NULL); + if(usage_str) + { + result = LLSD::emptyArray(); + long usage = 0; + if(usage_str->length > 0) + { + usage = usage_str->data[0]; + if(usage_str->length > 1) + { + usage |= usage_str->data[1] << 8; + } + } + ASN1_STRING_free(usage_str); + if(usage) + { + if(usage & KU_DIGITAL_SIGNATURE) result.append(LLSD((std::string)CERT_KU_DIGITAL_SIGNATURE)); + if(usage & KU_NON_REPUDIATION) result.append(LLSD((std::string)CERT_KU_NON_REPUDIATION)); + if(usage & KU_KEY_ENCIPHERMENT) result.append(LLSD((std::string)CERT_KU_KEY_ENCIPHERMENT)); + if(usage & KU_DATA_ENCIPHERMENT) result.append(LLSD((std::string)CERT_KU_DATA_ENCIPHERMENT)); + if(usage & KU_KEY_AGREEMENT) result.append(LLSD((std::string)CERT_KU_KEY_AGREEMENT)); + if(usage & KU_KEY_CERT_SIGN) result.append(LLSD((std::string)CERT_KU_CERT_SIGN)); + if(usage & KU_CRL_SIGN) result.append(LLSD((std::string)CERT_KU_CRL_SIGN)); + if(usage & KU_ENCIPHER_ONLY) result.append(LLSD((std::string)CERT_KU_ENCIPHER_ONLY)); + if(usage & KU_DECIPHER_ONLY) result.append(LLSD((std::string)CERT_KU_DECIPHER_ONLY)); + } + } + return result; +} + +// retrieve the extended key usage for the cert +LLSD _ext_key_usage_ext(X509* cert) +{ + LLSD result; + EXTENDED_KEY_USAGE *eku = (EXTENDED_KEY_USAGE *)X509_get_ext_d2i(cert, NID_ext_key_usage, NULL, NULL); + if(eku) + { + result = LLSD::emptyArray(); + while(sk_ASN1_OBJECT_num(eku)) + { + ASN1_OBJECT *usage = sk_ASN1_OBJECT_pop(eku); + if(usage) + { + int nid = OBJ_obj2nid(usage); + if (nid) + { + std::string sn = OBJ_nid2sn(nid); + result.append(sn); + } + ASN1_OBJECT_free(usage); + } + } + } + return result; +} + +// retrieve the subject key identifier of the cert +LLSD _subject_key_identifier_ext(X509 *cert) +{ + LLSD result; + ASN1_OCTET_STRING *skeyid = (ASN1_OCTET_STRING *)X509_get_ext_d2i(cert, NID_subject_key_identifier, NULL, NULL); + if(skeyid) + { + result = cert_string_from_octet_string(skeyid); + } + return result; +} + +// retrieve the authority key identifier of the cert +LLSD _authority_key_identifier_ext(X509* cert) +{ + LLSD result; + AUTHORITY_KEYID *akeyid = (AUTHORITY_KEYID *)X509_get_ext_d2i(cert, NID_authority_key_identifier, NULL, NULL); + if(akeyid) + { + result = LLSD::emptyMap(); + if(akeyid->keyid) + { + result[CERT_AUTHORITY_KEY_IDENTIFIER_ID] = cert_string_from_octet_string(akeyid->keyid); + } + if(akeyid->serial) + { + result[CERT_AUTHORITY_KEY_IDENTIFIER_SERIAL] = cert_string_from_asn1_integer(akeyid->serial); + } + } + + // we ignore the issuer name in the authority key identifier, we check the issue name via + // the the issuer name entry in the cert. + + + return result; +} + +// retrieve an openssl x509 object, +// which must be freed by X509_free +X509* LLBasicCertificate::getOpenSSLX509() const +{ + return X509_dup(mCert); +} + +// generate a single string containing the subject or issuer +// name of the cert. +std::string cert_string_name_from_X509_NAME(X509_NAME* name) +{ + char * name_bio_chars = NULL; + // get a memory bio + BIO *name_bio = BIO_new(BIO_s_mem()); + // stream the name into the bio. The name will be in the 'short name' format + X509_NAME_print_ex(name_bio, name, 0, XN_FLAG_RFC2253); + int length = BIO_get_mem_data(name_bio, &name_bio_chars); + std::string result = std::string(name_bio_chars, length); + BIO_free(name_bio); + return result; +} + +// generate an LLSD from a certificate name (issuer or subject name). +// the name will be strings indexed by the 'long form' +LLSD cert_name_from_X509_NAME(X509_NAME* name) +{ + LLSD result = LLSD::emptyMap(); + int name_entries = X509_NAME_entry_count(name); + for (int entry_index=0; entry_index < name_entries; entry_index++) + { + char buffer[32]; + X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, entry_index); + + std::string name_value = std::string((const char*)M_ASN1_STRING_data(X509_NAME_ENTRY_get_data(entry)), + M_ASN1_STRING_length(X509_NAME_ENTRY_get_data(entry))); + + ASN1_OBJECT* name_obj = X509_NAME_ENTRY_get_object(entry); + OBJ_obj2txt(buffer, sizeof(buffer), name_obj, 0); + std::string obj_buffer_str = std::string(buffer); + result[obj_buffer_str] = name_value; + } + + return result; +} + +// Generate a string from an ASN1 integer. ASN1 Integers are +// bignums, so they can be 'infinitely' long, therefore we +// cannot simply use a conversion to U64 or something. +// We retrieve as a readable string for UI + +std::string cert_string_from_asn1_integer(ASN1_INTEGER* value) +{ + std::string result; + BIGNUM *bn = ASN1_INTEGER_to_BN(value, NULL); + if(bn) + { + char * ascii_bn = BN_bn2hex(bn); + + if(ascii_bn) + { + result = ascii_bn; + OPENSSL_free(ascii_bn); + } + BN_free(bn); + } + return result; +} + +// Generate a string from an OCTET string. +// we retrieve as a + +std::string cert_string_from_octet_string(ASN1_OCTET_STRING* value) +{ + + std::stringstream result; + result << std::hex << std::setprecision(2); + for (int i=0; i < value->length; i++) + { + if (i != 0) + { + result << ":"; + } + result << std::setfill('0') << std::setw(2) << (int)value->data[i]; + } + return result.str(); +} + +// Generate a string from an ASN1 integer. ASN1 Integers are +// bignums, so they can be 'infinitely' long, therefore we +// cannot simply use a conversion to U64 or something. +// We retrieve as a readable string for UI + +std::string cert_string_from_asn1_string(ASN1_STRING* value) +{ + char * string_bio_chars = NULL; + std::string result; + // get a memory bio + BIO *string_bio = BIO_new(BIO_s_mem()); + if(!string_bio) + { + // stream the name into the bio. The name will be in the 'short name' format + ASN1_STRING_print_ex(string_bio, value, ASN1_STRFLGS_RFC2253); + int length = BIO_get_mem_data(string_bio, &string_bio_chars); + result = std::string(string_bio_chars, length); + BIO_free(string_bio); + } + else + { + LL_WARNS("SECAPI") << "Could not allocate an openssl memory BIO." << LL_ENDL; + } + + return result; +} + +// retrieve a date structure from an ASN1 time, for +// validity checking. +LLDate cert_date_from_asn1_time(ASN1_TIME* asn1_time) +{ + + struct tm timestruct = {0}; + int i = asn1_time->length; + + if (i < 10) + { + return LLDate(); + } + // convert the date from the ASN1 time (which is a string in ZULU time), to + // a timeval. + timestruct.tm_year = (asn1_time->data[0]-'0') * 10 + (asn1_time->data[1]-'0'); + + /* Deal with Year 2000 */ + if (timestruct.tm_year < 70) + timestruct.tm_year += 100; + + timestruct.tm_mon = (asn1_time->data[2]-'0') * 10 + (asn1_time->data[3]-'0') - 1; + timestruct.tm_mday = (asn1_time->data[4]-'0') * 10 + (asn1_time->data[5]-'0'); + timestruct.tm_hour = (asn1_time->data[6]-'0') * 10 + (asn1_time->data[7]-'0'); + timestruct.tm_min = (asn1_time->data[8]-'0') * 10 + (asn1_time->data[9]-'0'); + timestruct.tm_sec = (asn1_time->data[10]-'0') * 10 + (asn1_time->data[11]-'0'); + +#if LL_WINDOWS + return LLDate((F64)_mkgmtime(×truct)); +#else // LL_WINDOWS + return LLDate((F64)timegm(×truct)); +#endif // LL_WINDOWS +} + + +// Generate a string containing a digest. The digest time is 'ssh1' or +// 'md5', and the resulting string is of the form "aa:12:5c:' and so on +std::string cert_get_digest(const std::string& digest_type, X509 *cert) +{ + unsigned char digest_data[BUFFER_READ_SIZE]; + unsigned int len = sizeof(digest_data); + std::stringstream result; + const EVP_MD* digest = NULL; + // we could use EVP_get_digestbyname, but that requires initializer code which + // would require us to complicate things by plumbing it into the system. + if (digest_type == "md5") + { + digest = EVP_md5(); + } + else if (digest_type == "sha1") + { + digest = EVP_sha1(); + } + else + { + return std::string(); + } + + X509_digest(cert, digest, digest_data, &len); + result << std::hex << std::setprecision(2); + for (unsigned int i=0; i < len; i++) + { + if (i != 0) + { + result << ":"; + } + result << std::setfill('0') << std::setw(2) << (int)digest_data[i]; + } + return result.str(); +} + + +// class LLBasicCertificateVector +// This class represents a list of certificates, implemented by a vector of certificate pointers. +// it contains implementations of the virtual functions for iterators, search, add, remove, etc. +// + +// Find a certificate in the list. +// It will find a cert that has minimally the params listed, with the values being the same +LLBasicCertificateVector::iterator LLBasicCertificateVector::find(const LLSD& params) +{ + BOOL found = FALSE; + // loop through the entire vector comparing the values in the certs + // against those passed in via the params. + // params should be a map. Only the items specified in the map will be + // checked, but they must match exactly, even if they're maps or arrays. + + for(iterator cert = begin(); + cert != end(); + cert++) + { + + found= TRUE; + LLSD cert_info = (*cert)->getLLSD(); + for (LLSD::map_const_iterator param = params.beginMap(); + param != params.endMap(); + param++) + { + + if (!cert_info.has((std::string)param->first) || + (!valueCompareLLSD(cert_info[(std::string)param->first], param->second))) + { + found = FALSE; + break; + } + } + if (found) + { + return (cert); + } + } + return end(); +} + +// Insert a certificate into the store. If the certificate already +// exists in the store, nothing is done. +void LLBasicCertificateVector::insert(iterator _iter, + LLPointer<LLCertificate> cert) +{ + LLSD cert_info = cert->getLLSD(); + if (cert_info.isMap() && cert_info.has(CERT_SHA1_DIGEST)) + { + LLSD existing_cert_info = LLSD::emptyMap(); + existing_cert_info[CERT_MD5_DIGEST] = cert_info[CERT_MD5_DIGEST]; + if(find(existing_cert_info) == end()) + { + BasicIteratorImpl *basic_iter = dynamic_cast<BasicIteratorImpl*>(_iter.mImpl.get()); + mCerts.insert(basic_iter->mIter, cert); + } + } +} + +// remove a certificate from the store +LLPointer<LLCertificate> LLBasicCertificateVector::erase(iterator _iter) +{ + + if (_iter != end()) + { + BasicIteratorImpl *basic_iter = dynamic_cast<BasicIteratorImpl*>(_iter.mImpl.get()); + LLPointer<LLCertificate> result = (*_iter); + mCerts.erase(basic_iter->mIter); + return result; + } + return NULL; +} + + +// +// LLBasicCertificateStore +// This class represents a store of CA certificates. The basic implementation +// uses a pem file such as the legacy CA.pem stored in the existing +// SL implementation. +LLBasicCertificateStore::LLBasicCertificateStore(const std::string& filename) +{ + mFilename = filename; + load_from_file(filename); +} + +void LLBasicCertificateStore::load_from_file(const std::string& filename) +{ + // scan the PEM file extracting each certificate + BIO* file_bio = BIO_new(BIO_s_file()); + if(file_bio) + { + if (BIO_read_filename(file_bio, filename.c_str()) > 0) + { + X509 *cert_x509 = NULL; + while((PEM_read_bio_X509(file_bio, &cert_x509, 0, NULL)) && + (cert_x509 != NULL)) + { + try + { + add(new LLBasicCertificate(cert_x509)); + } + catch (...) + { + LL_WARNS("SECAPI") << "Failure creating certificate from the certificate store file." << LL_ENDL; + } + X509_free(cert_x509); + cert_x509 = NULL; + } + BIO_free(file_bio); + } + } + else + { + LL_WARNS("SECAPI") << "Could not allocate a file BIO" << LL_ENDL; + } +} + + +LLBasicCertificateStore::~LLBasicCertificateStore() +{ +} + + +// persist the store +void LLBasicCertificateStore::save() +{ + llofstream file_store(mFilename, llofstream::binary); + if(!file_store.fail()) + { + for(iterator cert = begin(); + cert != end(); + cert++) + { + std::string pem = (*cert)->getPem(); + if(!pem.empty()) + { + file_store << (*cert)->getPem() << std::endl; + } + } + file_store.close(); + } + else + { + LL_WARNS("SECAPI") << "Could not open certificate store " << mFilename << "for save" << LL_ENDL; + } +} + +// return the store id +std::string LLBasicCertificateStore::storeId() const +{ + // this is the basic handler which uses the CA.pem store, + // so we ignore this. + return std::string(""); +} + + +// +// LLBasicCertificateChain +// This class represents a chain of certs, each cert being signed by the next cert +// in the chain. Certs must be properly signed by the parent +LLBasicCertificateChain::LLBasicCertificateChain(const X509_STORE_CTX* store) +{ + + // we're passed in a context, which contains a cert, and a blob of untrusted + // certificates which compose the chain. + if((store == NULL) || (store->cert == NULL)) + { + LL_WARNS("SECAPI") << "An invalid store context was passed in when trying to create a certificate chain" << LL_ENDL; + return; + } + // grab the child cert + LLPointer<LLCertificate> current = new LLBasicCertificate(store->cert); + + add(current); + if(store->untrusted != NULL) + { + // if there are other certs in the chain, we build up a vector + // of untrusted certs so we can search for the parents of each + // consecutive cert. + LLBasicCertificateVector untrusted_certs; + for(int i = 0; i < sk_X509_num(store->untrusted); i++) + { + LLPointer<LLCertificate> cert = new LLBasicCertificate(sk_X509_value(store->untrusted, i)); + untrusted_certs.add(cert); + + } + while(untrusted_certs.size() > 0) + { + LLSD find_data = LLSD::emptyMap(); + LLSD cert_data = current->getLLSD(); + // 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 + // validation. + find_data[CERT_SUBJECT_NAME_STRING] = cert_data[CERT_ISSUER_NAME_STRING]; + LLBasicCertificateVector::iterator issuer = untrusted_certs.find(find_data); + if (issuer != untrusted_certs.end()) + { + current = untrusted_certs.erase(issuer); + add(current); + } + else + { + break; + } + } + } +} + + +// subdomain wildcard specifiers can be divided into 3 parts +// the part before the first *, the part after the first * but before +// the second *, and the part after the second *. +// It then iterates over the second for each place in the string +// that it matches. ie if the subdomain was testfoofoobar, and +// the wildcard was test*foo*bar, it would match test, then +// recursively match foofoobar and foobar + +bool _cert_subdomain_wildcard_match(const std::string& subdomain, + const std::string& wildcard) +{ + // split wildcard into the portion before the *, and the portion after + + int wildcard_pos = wildcard.find_first_of('*'); + // check the case where there is no wildcard. + if(wildcard_pos == wildcard.npos) + { + return (subdomain == wildcard); + } + + // we need to match the first part of the subdomain string up to the wildcard + // position + if(subdomain.substr(0, wildcard_pos) != wildcard.substr(0, wildcard_pos)) + { + // the first portions of the strings didn't match + return FALSE; + } + + // as the portion of the wildcard string before the * matched, we need to check the + // portion afterwards. Grab that portion. + std::string new_wildcard_string = wildcard.substr( wildcard_pos+1, wildcard.npos); + if(new_wildcard_string.empty()) + { + // we had nothing after the *, so it's an automatic match + return TRUE; + } + + // grab the portion of the remaining wildcard string before the next '*'. We need to find this + // within the remaining subdomain string. and then recursively check. + std::string new_wildcard_match_string = new_wildcard_string.substr(0, new_wildcard_string.find_first_of('*')); + + // grab the portion of the subdomain after the part that matched the initial wildcard portion + std::string new_subdomain = subdomain.substr(wildcard_pos, subdomain.npos); + + // iterate through the current subdomain, finding instances of the match string. + int sub_pos = new_subdomain.find_first_of(new_wildcard_match_string); + while(sub_pos != std::string::npos) + { + new_subdomain = new_subdomain.substr(sub_pos, std::string::npos); + if(_cert_subdomain_wildcard_match(new_subdomain, new_wildcard_string)) + { + return TRUE; + } + sub_pos = new_subdomain.find_first_of(new_wildcard_match_string, 1); + + + } + // didn't find any instances of the match string that worked in the subdomain, so fail. + return FALSE; +} + + +// RFC2459 does not address wildcards as part of it's name matching +// specification, and there is no RFC specifying wildcard matching, +// RFC2818 does a few statements about wildcard matching, but is very +// general. Generally, wildcard matching is per implementation, although +// it's pretty similar. +// in our case, we use the '*' wildcard character only, within each +// subdomain. The hostname and the CN specification should have the +// same number of subdomains. +// We then iterate that algorithm over each subdomain. +bool _cert_hostname_wildcard_match(const std::string& hostname, const std::string& common_name) +{ + std::string new_hostname = hostname; + std::string new_cn = common_name; + int subdomain_pos = new_hostname.find_first_of('.'); + int subcn_pos = new_cn.find_first_of('.'); + + while((subcn_pos != std::string::npos) && (subdomain_pos != std::string::npos)) + { + // snip out the first subdomain and cn element + + if(!_cert_subdomain_wildcard_match(new_hostname.substr(0, subdomain_pos), + new_cn.substr(0, subcn_pos))) + { + return FALSE; + } + new_hostname = new_hostname.substr(subdomain_pos+1, std::string::npos); + new_cn = new_cn.substr(subcn_pos+1, std::string::npos); + subdomain_pos = new_hostname.find_first_of('.'); + subcn_pos = new_cn.find_first_of('.'); + } + return _cert_subdomain_wildcard_match(new_hostname, new_cn); + +} + +// validate that the LLSD array in llsd_set contains the llsd_value +bool _LLSDArrayIncludesValue(const LLSD& llsd_set, LLSD llsd_value) +{ + for(LLSD::array_const_iterator set_value = llsd_set.beginArray(); + set_value != llsd_set.endArray(); + set_value++) + { + if(valueCompareLLSD((*set_value), llsd_value)) + { + return TRUE; + } + } + return FALSE; +} + +void _validateCert(int validation_policy, + const LLPointer<LLCertificate> cert, + const LLSD& validation_params, + int depth) +{ + + LLSD current_cert_info = cert->getLLSD(); + // check basic properties exist in the cert + if(!current_cert_info.has(CERT_SUBJECT_NAME) || !current_cert_info.has(CERT_SUBJECT_NAME_STRING)) + { + throw LLCertException(cert, "Cert doesn't have a Subject Name"); + } + + if(!current_cert_info.has(CERT_ISSUER_NAME_STRING)) + { + throw LLCertException(cert, "Cert doesn't have an Issuer Name"); + } + + // check basic properties exist in the cert + if(!current_cert_info.has(CERT_VALID_FROM) || !current_cert_info.has(CERT_VALID_TO)) + { + throw LLCertException(cert, "Cert doesn't have an expiration period"); + } + if (!current_cert_info.has(CERT_SHA1_DIGEST)) + { + throw LLCertException(cert, "No SHA1 digest"); + } + + 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 < current_cert_info[CERT_VALID_FROM].asDate()) || + (validation_date > current_cert_info[CERT_VALID_TO].asDate())) + { + throw LLCertValidationExpirationException(cert, validation_date); + } + } + if (validation_policy & VALIDATION_POLICY_SSL_KU) + { + if (current_cert_info.has(CERT_KEY_USAGE) && current_cert_info[CERT_KEY_USAGE].isArray() && + (!(_LLSDArrayIncludesValue(current_cert_info[CERT_KEY_USAGE], + LLSD((std::string)CERT_KU_DIGITAL_SIGNATURE))) || + !(_LLSDArrayIncludesValue(current_cert_info[CERT_KEY_USAGE], + LLSD((std::string)CERT_KU_KEY_ENCIPHERMENT))))) + { + throw LLCertKeyUsageValidationException(cert); + } + // only validate EKU if the cert has it + if(current_cert_info.has(CERT_EXTENDED_KEY_USAGE) && current_cert_info[CERT_EXTENDED_KEY_USAGE].isArray() && + (!_LLSDArrayIncludesValue(current_cert_info[CERT_EXTENDED_KEY_USAGE], + LLSD((std::string)CERT_EKU_SERVER_AUTH)))) + { + throw LLCertKeyUsageValidationException(cert); + } + } + if (validation_policy & VALIDATION_POLICY_CA_KU) + { + if (current_cert_info.has(CERT_KEY_USAGE) && current_cert_info[CERT_KEY_USAGE].isArray() && + (!_LLSDArrayIncludesValue(current_cert_info[CERT_KEY_USAGE], + (std::string)CERT_KU_CERT_SIGN))) + { + throw LLCertKeyUsageValidationException(cert); + } + } + + // validate basic constraints + if ((validation_policy & VALIDATION_POLICY_CA_BASIC_CONSTRAINTS) && + current_cert_info.has(CERT_BASIC_CONSTRAINTS) && + current_cert_info[CERT_BASIC_CONSTRAINTS].isMap()) + { + if(!current_cert_info[CERT_BASIC_CONSTRAINTS].has(CERT_BASIC_CONSTRAINTS_CA) || + !current_cert_info[CERT_BASIC_CONSTRAINTS][CERT_BASIC_CONSTRAINTS_CA]) + { + throw LLCertBasicConstraintsValidationException(cert); + } + if (current_cert_info[CERT_BASIC_CONSTRAINTS].has(CERT_BASIC_CONSTRAINTS_PATHLEN) && + ((current_cert_info[CERT_BASIC_CONSTRAINTS][CERT_BASIC_CONSTRAINTS_PATHLEN].asInteger() != 0) && + (depth > current_cert_info[CERT_BASIC_CONSTRAINTS][CERT_BASIC_CONSTRAINTS_PATHLEN].asInteger()))) + { + throw LLCertBasicConstraintsValidationException(cert); + } + } +} + +bool _verify_signature(LLPointer<LLCertificate> parent, + LLPointer<LLCertificate> child) +{ + bool verify_result = FALSE; + LLSD cert1 = parent->getLLSD(); + LLSD cert2 = child->getLLSD(); + X509 *signing_cert = parent->getOpenSSLX509(); + X509 *child_cert = child->getOpenSSLX509(); + if((signing_cert != NULL) && (child_cert != NULL)) + { + EVP_PKEY *pkey = X509_get_pubkey(signing_cert); + + + if(pkey) + { + int verify_code = X509_verify(child_cert, pkey); + verify_result = ( verify_code > 0); + EVP_PKEY_free(pkey); + } + else + { + LL_WARNS("SECAPI") << "Could not validate the cert chain signature, as the public key of the signing cert could not be retrieved" << LL_ENDL; + } + + } + else + { + LL_WARNS("SECAPI") << "Signature verification failed as there are no certs in the chain" << LL_ENDL; + } + if(child_cert) + { + X509_free(child_cert); + } + if(signing_cert) + { + X509_free(signing_cert); + } + 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 +// * Hostname matching for SSL certs +// * Expiration time matching +// * Signature validation +// * Chain trust (is the cert chain trusted against the store) +// * Basic constraints +// * key usage and extended key usage +// TODO: We should add 'authority key identifier' for chaining. +// This algorithm doesn't simply validate the chain by itself +// 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<LLCertificateStore> ca_store, + const LLSD& validation_params) +{ + + if(size() < 1) + { + throw LLCertException(NULL, "No certs in chain"); + } + iterator current_cert = begin(); + LLSD current_cert_info = (*current_cert)->getLLSD(); + LLSD validation_date; + if (validation_params.has(CERT_VALIDATION_DATE)) + { + validation_date = validation_params[CERT_VALIDATION_DATE]; + } + + if (validation_policy & VALIDATION_POLICY_HOSTNAME) + { + if(!validation_params.has(CERT_HOSTNAME)) + { + throw LLCertException((*current_cert), "No hostname passed in for validation"); + } + if(!current_cert_info.has(CERT_SUBJECT_NAME) || !current_cert_info[CERT_SUBJECT_NAME].has(CERT_NAME_CN)) + { + throw LLInvalidCertificate((*current_cert)); + } + + LL_INFOS("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())) + { + throw LLCertValidationHostnameException(validation_params[CERT_HOSTNAME].asString(), + (*current_cert)); + } + } + + + int depth = 0; + LLPointer<LLCertificate> previous_cert; + // loop through the cert chain, validating the current cert against the next one. + while(current_cert != end()) + { + + int local_validation_policy = validation_policy; + if(current_cert == begin()) + { + // for the child cert, we don't validate CA stuff + local_validation_policy &= ~(VALIDATION_POLICY_CA_KU | + VALIDATION_POLICY_CA_BASIC_CONSTRAINTS); + } + else + { + // for non-child certs, we don't validate SSL Key usage + local_validation_policy &= ~VALIDATION_POLICY_SSL_KU; + if(!_verify_signature((*current_cert), + previous_cert)) + { + throw LLCertValidationInvalidSignatureException(previous_cert); + } + } + _validateCert(local_validation_policy, + (*current_cert), + validation_params, + 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()) + { + 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)) + { + LLSD cert_aki = cert_llsd[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]; + } + if(cert_aki.has(CERT_AUTHORITY_KEY_IDENTIFIER_SERIAL)) + { + cert_search_params[CERT_SERIAL_NUMBER] = cert_aki[CERT_AUTHORITY_KEY_IDENTIFIER_SERIAL]; + } + } + found_store_cert = ca_store->find(cert_search_params); + + if(found_store_cert != ca_store->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), + LLSD(), + depth); + + // verify the signature of the CA + if(!_verify_signature((*found_store_cert), + (*current_cert))) + { + throw LLCertValidationInvalidSignatureException(*current_cert); + } + // successfully validated. + return; + } + previous_cert = (*current_cert); + current_cert++; + depth++; + } + if (validation_policy & VALIDATION_POLICY_TRUSTED) + { + LLPointer<LLCertificate> untrusted_ca_cert = (*this)[size()-1]; + // we reached the end without finding a trusted cert. + throw LLCertValidationTrustException((*this)[size()-1]); + + } +} + + +// LLSecAPIBasicHandler Class +// Interface handler class for the various security storage handlers. + +// We read the file on construction, and write it on destruction. This +// means multiple processes cannot modify the datastore. +LLSecAPIBasicHandler::LLSecAPIBasicHandler(const std::string& protected_data_file, + const std::string& legacy_password_path) +{ + mProtectedDataFilename = protected_data_file; + mProtectedDataMap = LLSD::emptyMap(); + mLegacyPasswordPath = legacy_password_path; + +} + +LLSecAPIBasicHandler::LLSecAPIBasicHandler() +{ +} + + +void LLSecAPIBasicHandler::init() +{ + mProtectedDataMap = LLSD::emptyMap(); + if (mProtectedDataFilename.length() == 0) + { + mProtectedDataFilename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, + "bin_conf.dat"); + mLegacyPasswordPath = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "password.dat"); + + mProtectedDataFilename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, + "bin_conf.dat"); + std::string store_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, + "CA.pem"); + // copy the CA file to a user writable location so we can manipulate it. + // for this provider, by using a user writable file, there is a risk that + // an attacking program can modify the file, but OS dependent providers + // will reduce that risk. + // by using a user file, modifications will be limited to one user if + // we read-only the main file + if (!LLFile::isfile(store_file)) + { + + std::string ca_file_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "CA.pem"); + llifstream ca_file(ca_file_path.c_str(), llifstream::binary | llifstream::in); + llofstream copied_store_file(store_file.c_str(), llofstream::binary | llofstream::out); + + while(!ca_file.fail()) + { + char buffer[BUFFER_READ_SIZE]; + ca_file.read(buffer, sizeof(buffer)); + copied_store_file.write(buffer, ca_file.gcount()); + } + ca_file.close(); + copied_store_file.close(); + } + LL_INFOS("SECAPI") << "Loading certificate store from " << store_file << LL_ENDL; + mStore = new LLBasicCertificateStore(store_file); + } + _readProtectedData(); // initialize mProtectedDataMap + // may throw LLProtectedDataException if saved datamap is not decryptable +} +LLSecAPIBasicHandler::~LLSecAPIBasicHandler() +{ + _writeProtectedData(); +} + +void LLSecAPIBasicHandler::_readProtectedData() +{ + // attempt to load the file into our map + LLPointer<LLSDParser> parser = new LLSDXMLParser(); + llifstream protected_data_stream(mProtectedDataFilename.c_str(), + llifstream::binary); + + if (!protected_data_stream.fail()) { + int offset; + U8 salt[STORE_SALT_SIZE]; + U8 buffer[BUFFER_READ_SIZE]; + U8 decrypted_buffer[BUFFER_READ_SIZE]; + int decrypted_length; + unsigned char MACAddress[MAC_ADDRESS_BYTES]; + LLUUID::getNodeID(MACAddress); + LLXORCipher cipher(MACAddress, MAC_ADDRESS_BYTES); + + // read in the salt and key + protected_data_stream.read((char *)salt, STORE_SALT_SIZE); + offset = 0; + if (protected_data_stream.gcount() < STORE_SALT_SIZE) + { + throw LLProtectedDataException("Config file too short."); + } + + cipher.decrypt(salt, STORE_SALT_SIZE); + + // totally lame. As we're not using the OS level protected data, we need to + // at least obfuscate the data. We do this by using a salt stored at the head of the file + // to encrypt the data, therefore obfuscating it from someone using simple existing tools. + // We do include the MAC address as part of the obfuscation, which would require an + // attacker to get the MAC address as well as the protected store, which improves things + // somewhat. It would be better to use the password, but as this store + // will be used to store the SL password when the user decides to have SL remember it, + // so we can't use that. OS-dependent store implementations will use the OS password/storage + // mechanisms and are considered to be more secure. + // We've a strong intent to move to OS dependent protected data stores. + + + // read in the rest of the file. + EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX_init(&ctx); + EVP_DecryptInit(&ctx, EVP_rc4(), salt, NULL); + // allocate memory: + std::string decrypted_data; + + while(protected_data_stream.good()) { + // read data as a block: + protected_data_stream.read((char *)buffer, BUFFER_READ_SIZE); + + EVP_DecryptUpdate(&ctx, decrypted_buffer, &decrypted_length, + buffer, protected_data_stream.gcount()); + decrypted_data.append((const char *)decrypted_buffer, protected_data_stream.gcount()); + } + + // RC4 is a stream cipher, so we don't bother to EVP_DecryptFinal, as there is + // no block padding. + EVP_CIPHER_CTX_cleanup(&ctx); + std::istringstream parse_stream(decrypted_data); + if (parser->parse(parse_stream, mProtectedDataMap, + LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE) + { + throw LLProtectedDataException("Config file cannot be decrypted."); + } + } +} + +void LLSecAPIBasicHandler::_writeProtectedData() +{ + std::ostringstream formatted_data_ostream; + U8 salt[STORE_SALT_SIZE]; + U8 buffer[BUFFER_READ_SIZE]; + U8 encrypted_buffer[BUFFER_READ_SIZE]; + + + if(mProtectedDataMap.isUndefined()) + { + LLFile::remove(mProtectedDataFilename); + return; + } + // create a string with the formatted data. + LLSDSerialize::toXML(mProtectedDataMap, formatted_data_ostream); + std::istringstream formatted_data_istream(formatted_data_ostream.str()); + // generate the seed + RAND_bytes(salt, STORE_SALT_SIZE); + + + // write to a temp file so we don't clobber the initial file if there is + // an error. + std::string tmp_filename = mProtectedDataFilename + ".tmp"; + + llofstream protected_data_stream(tmp_filename.c_str(), + llofstream::binary); + try + { + + EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX_init(&ctx); + EVP_EncryptInit(&ctx, EVP_rc4(), salt, NULL); + unsigned char MACAddress[MAC_ADDRESS_BYTES]; + LLUUID::getNodeID(MACAddress); + LLXORCipher cipher(MACAddress, MAC_ADDRESS_BYTES); + cipher.encrypt(salt, STORE_SALT_SIZE); + protected_data_stream.write((const char *)salt, STORE_SALT_SIZE); + + while (formatted_data_istream.good()) + { + formatted_data_istream.read((char *)buffer, BUFFER_READ_SIZE); + if(formatted_data_istream.gcount() == 0) + { + break; + } + int encrypted_length; + EVP_EncryptUpdate(&ctx, encrypted_buffer, &encrypted_length, + buffer, formatted_data_istream.gcount()); + protected_data_stream.write((const char *)encrypted_buffer, encrypted_length); + } + + // no EVP_EncrypteFinal, as this is a stream cipher + EVP_CIPHER_CTX_cleanup(&ctx); + + protected_data_stream.close(); + } + catch (...) + { + // it's good practice to clean up any secure information on error + // (even though this file isn't really secure. Perhaps in the future + // it may be, however. + LLFile::remove(tmp_filename); + throw LLProtectedDataException("Error writing Protected Data Store"); + } + + // move the temporary file to the specified file location. + if((((LLFile::isfile(mProtectedDataFilename) != 0) && + (LLFile::remove(mProtectedDataFilename) != 0))) || + (LLFile::rename(tmp_filename, mProtectedDataFilename))) + { + LLFile::remove(tmp_filename); + throw LLProtectedDataException("Could not overwrite protected data store"); + } +} + +// instantiate a certificate from a pem string +LLPointer<LLCertificate> LLSecAPIBasicHandler::getCertificate(const std::string& pem_cert) +{ + LLPointer<LLCertificate> result = new LLBasicCertificate(pem_cert); + return result; +} + + + +// instiate a certificate from an openssl X509 structure +LLPointer<LLCertificate> LLSecAPIBasicHandler::getCertificate(X509* openssl_cert) +{ + LLPointer<LLCertificate> result = new LLBasicCertificate(openssl_cert); + return result; +} + +// instantiate a chain from an X509_STORE_CTX +LLPointer<LLCertificateChain> LLSecAPIBasicHandler::getCertificateChain(const X509_STORE_CTX* chain) +{ + LLPointer<LLCertificateChain> result = new LLBasicCertificateChain(chain); + return result; +} + +// instantiate a cert store given it's id. if a persisted version +// exists, it'll be loaded. If not, one will be created (but not +// persisted) +LLPointer<LLCertificateStore> LLSecAPIBasicHandler::getCertificateStore(const std::string& store_id) +{ + return mStore; +} + +// retrieve protected data +LLSD LLSecAPIBasicHandler::getProtectedData(const std::string& data_type, + const std::string& data_id) +{ + + if (mProtectedDataMap.has(data_type) && + mProtectedDataMap[data_type].isMap() && + mProtectedDataMap[data_type].has(data_id)) + { + return mProtectedDataMap[data_type][data_id]; + } + + return LLSD(); +} + +void LLSecAPIBasicHandler::deleteProtectedData(const std::string& data_type, + const std::string& data_id) +{ + if (mProtectedDataMap.has(data_type) && + mProtectedDataMap[data_type].isMap() && + mProtectedDataMap[data_type].has(data_id)) + { + mProtectedDataMap[data_type].erase(data_id); + } +} + + +// +// persist data in a protected store +// +void LLSecAPIBasicHandler::setProtectedData(const std::string& data_type, + const std::string& data_id, + const LLSD& data) +{ + if (!mProtectedDataMap.has(data_type) || !mProtectedDataMap[data_type].isMap()) { + mProtectedDataMap[data_type] = LLSD::emptyMap(); + } + + mProtectedDataMap[data_type][data_id] = data; +} + +// +// Create a credential object from an identifier and authenticator. credentials are +// per grid. +LLPointer<LLCredential> LLSecAPIBasicHandler::createCredential(const std::string& grid, + const LLSD& identifier, + const LLSD& authenticator) +{ + LLPointer<LLSecAPIBasicCredential> result = new LLSecAPIBasicCredential(grid); + result->setCredentialData(identifier, authenticator); + return result; +} + +// Load a credential from the credential store, given the grid +LLPointer<LLCredential> LLSecAPIBasicHandler::loadCredential(const std::string& grid) +{ + LLSD credential = getProtectedData("credential", grid); + LLPointer<LLSecAPIBasicCredential> result = new LLSecAPIBasicCredential(grid); + if(credential.isMap() && + credential.has("identifier")) + { + + LLSD identifier = credential["identifier"]; + LLSD authenticator; + if (credential.has("authenticator")) + { + authenticator = credential["authenticator"]; + } + result->setCredentialData(identifier, authenticator); + } + else + { + // credential was not in protected storage, so pull the credential + // from the legacy store. + std::string first_name = gSavedSettings.getString("FirstName"); + std::string last_name = gSavedSettings.getString("LastName"); + + if ((first_name != "") && + (last_name != "")) + { + LLSD identifier = LLSD::emptyMap(); + LLSD authenticator; + identifier["type"] = "agent"; + identifier["first_name"] = first_name; + identifier["last_name"] = last_name; + + std::string legacy_password = _legacyLoadPassword(); + if (legacy_password.length() > 0) + { + authenticator = LLSD::emptyMap(); + authenticator["type"] = "hash"; + authenticator["algorithm"] = "md5"; + authenticator["secret"] = legacy_password; + } + result->setCredentialData(identifier, authenticator); + } + } + return result; +} + +// Save the credential to the credential store. Save the authenticator also if requested. +// That feature is used to implement the 'remember password' functionality. +void LLSecAPIBasicHandler::saveCredential(LLPointer<LLCredential> cred, bool save_authenticator) +{ + LLSD credential = LLSD::emptyMap(); + credential["identifier"] = cred->getIdentifier(); + if (save_authenticator) + { + credential["authenticator"] = cred->getAuthenticator(); + } + LL_INFOS("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? + _writeProtectedData(); +} + +// Remove a credential from the credential store. +void LLSecAPIBasicHandler::deleteCredential(LLPointer<LLCredential> cred) +{ + LLSD undefVal; + deleteProtectedData("credential", cred->getGrid()); + cred->setCredentialData(undefVal, undefVal); + _writeProtectedData(); +} + +// load the legacy hash for agni, and decrypt it given the +// mac address +std::string LLSecAPIBasicHandler::_legacyLoadPassword() +{ + const S32 HASHED_LENGTH = 32; + std::vector<U8> buffer(HASHED_LENGTH); + llifstream password_file(mLegacyPasswordPath, llifstream::binary); + + if(password_file.fail()) + { + return std::string(""); + } + + password_file.read((char*)&buffer[0], buffer.size()); + if(password_file.gcount() != buffer.size()) + { + return std::string(""); + } + + // Decipher with MAC address |
