diff options
author | Jacek Antonelli | 2008-10-08 00:59:21 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-10-08 00:59:26 -0500 |
commit | f6276d08ec2d6a7ce1ac568c77771162bd8cece5 (patch) | |
tree | bf90071e73ded161624c5c1cd77fc1a57a79de4d /linden/indra/llmessage | |
parent | Second Life viewer sources 1.21.4-RC (diff) | |
download | meta-impy-f6276d08ec2d6a7ce1ac568c77771162bd8cece5.zip meta-impy-f6276d08ec2d6a7ce1ac568c77771162bd8cece5.tar.gz meta-impy-f6276d08ec2d6a7ce1ac568c77771162bd8cece5.tar.bz2 meta-impy-f6276d08ec2d6a7ce1ac568c77771162bd8cece5.tar.xz |
Second Life viewer sources 1.21.5-RC
Diffstat (limited to 'linden/indra/llmessage')
-rw-r--r-- | linden/indra/llmessage/llurlrequest.cpp | 42 | ||||
-rw-r--r-- | linden/indra/llmessage/llxfermanager.cpp | 119 | ||||
-rw-r--r-- | linden/indra/llmessage/llxfermanager.h | 16 |
3 files changed, 150 insertions, 27 deletions
diff --git a/linden/indra/llmessage/llurlrequest.cpp b/linden/indra/llmessage/llurlrequest.cpp index fbd002b..ee62798 100644 --- a/linden/indra/llmessage/llurlrequest.cpp +++ b/linden/indra/llmessage/llurlrequest.cpp | |||
@@ -484,27 +484,29 @@ static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user) | |||
484 | // Per HTTP spec the first header line must be the status line. | 484 | // Per HTTP spec the first header line must be the status line. |
485 | if (!complete->haveHTTPStatus()) | 485 | if (!complete->haveHTTPStatus()) |
486 | { | 486 | { |
487 | std::string::iterator end = header.end(); | 487 | if (header.substr(0,5) == "HTTP/") |
488 | std::string::iterator pos1 = std::find(header.begin(), end, ' '); | ||
489 | if (pos1 != end) ++pos1; | ||
490 | std::string::iterator pos2 = std::find(pos1, end, ' '); | ||
491 | if (pos2 != end) ++pos2; | ||
492 | std::string::iterator pos3 = std::find(pos2, end, '\r'); | ||
493 | |||
494 | std::string version(header.begin(), pos1); | ||
495 | std::string status(pos1, pos2); | ||
496 | std::string reason(pos2, pos3); | ||
497 | |||
498 | int statusCode = atoi(status.c_str()); | ||
499 | if (statusCode > 0) | ||
500 | { | 488 | { |
501 | complete->httpStatus((U32)statusCode, reason); | 489 | std::string::iterator end = header.end(); |
502 | } | 490 | std::string::iterator pos1 = std::find(header.begin(), end, ' '); |
503 | else | 491 | if (pos1 != end) ++pos1; |
504 | { | 492 | std::string::iterator pos2 = std::find(pos1, end, ' '); |
505 | llwarns << "Unable to parse http response status line: " | 493 | if (pos2 != end) ++pos2; |
506 | << header << llendl; | 494 | std::string::iterator pos3 = std::find(pos2, end, '\r'); |
507 | complete->httpStatus(499,"Unable to parse status line."); | 495 | |
496 | std::string version(header.begin(), pos1); | ||
497 | std::string status(pos1, pos2); | ||
498 | std::string reason(pos2, pos3); | ||
499 | |||
500 | int statusCode = atoi(status.c_str()); | ||
501 | if (statusCode >= 300 && statusCode < 400) | ||
502 | { | ||
503 | // This is a redirect, ignore it and all headers | ||
504 | // until we find a normal status code. | ||
505 | } | ||
506 | else if (statusCode > 0) | ||
507 | { | ||
508 | complete->httpStatus((U32)statusCode, reason); | ||
509 | } | ||
508 | } | 510 | } |
509 | return header_len; | 511 | return header_len; |
510 | } | 512 | } |
diff --git a/linden/indra/llmessage/llxfermanager.cpp b/linden/indra/llmessage/llxfermanager.cpp index f40612c..8173b7c 100644 --- a/linden/indra/llmessage/llxfermanager.cpp +++ b/linden/indra/llmessage/llxfermanager.cpp | |||
@@ -713,6 +713,78 @@ void LLXferManager::sendConfirmPacket (LLMessageSystem *mesgsys, U64 id, S32 pac | |||
713 | 713 | ||
714 | /////////////////////////////////////////////////////////// | 714 | /////////////////////////////////////////////////////////// |
715 | 715 | ||
716 | static bool find_and_remove(std::multiset<std::string>& files, | ||
717 | const std::string& filename) | ||
718 | { | ||
719 | std::multiset<std::string>::iterator ptr; | ||
720 | if ( (ptr = files.find(filename)) != files.end()) | ||
721 | { | ||
722 | //erase(filename) erases *all* entries with that key | ||
723 | files.erase(ptr); | ||
724 | return true; | ||
725 | } | ||
726 | return false; | ||
727 | } | ||
728 | |||
729 | void LLXferManager::expectFileForRequest(const std::string& filename) | ||
730 | { | ||
731 | mExpectedRequests.insert(filename); | ||
732 | } | ||
733 | |||
734 | bool LLXferManager::validateFileForRequest(const std::string& filename) | ||
735 | { | ||
736 | return find_and_remove(mExpectedRequests, filename); | ||
737 | } | ||
738 | |||
739 | void LLXferManager::expectFileForTransfer(const std::string& filename) | ||
740 | { | ||
741 | mExpectedTransfers.insert(filename); | ||
742 | } | ||
743 | |||
744 | bool LLXferManager::validateFileForTransfer(const std::string& filename) | ||
745 | { | ||
746 | return find_and_remove(mExpectedTransfers, filename); | ||
747 | } | ||
748 | |||
749 | static bool remove_prefix(std::string& filename, const std::string& prefix) | ||
750 | { | ||
751 | if (std::equal(prefix.begin(), prefix.end(), filename.begin())) | ||
752 | { | ||
753 | filename = filename.substr(prefix.length()); | ||
754 | return true; | ||
755 | } | ||
756 | return false; | ||
757 | } | ||
758 | |||
759 | static bool verify_cache_filename(const std::string& filename) | ||
760 | { | ||
761 | //NOTE: This routine is only used to check file names that our own | ||
762 | // code places in the cache directory. As such, it can be limited | ||
763 | // to this very restrictive file name pattern. It does not need to | ||
764 | // handle other characters. | ||
765 | |||
766 | size_t len = filename.size(); | ||
767 | //const boost::regex expr("[a-zA-Z0-9][-_.a-zA-Z0-9]<0,49>"); | ||
768 | if (len < 1 || len > 50) | ||
769 | { | ||
770 | return false; | ||
771 | } | ||
772 | for(unsigned i=0; i<len; ++i) | ||
773 | { | ||
774 | char c = filename[i]; | ||
775 | bool ok = isalnum(c); | ||
776 | if (!ok && i > 0) | ||
777 | { | ||
778 | ok = '_'==c || '-'==c || '.'==c; | ||
779 | } | ||
780 | if (!ok) | ||
781 | { | ||
782 | return false; | ||
783 | } | ||
784 | } | ||
785 | return true; | ||
786 | } | ||
787 | |||
716 | void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user_data*/) | 788 | void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user_data*/) |
717 | { | 789 | { |
718 | 790 | ||
@@ -734,16 +806,11 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user | |||
734 | 806 | ||
735 | mesgsys->getStringFast(_PREHASH_XferID, _PREHASH_Filename, local_filename); | 807 | mesgsys->getStringFast(_PREHASH_XferID, _PREHASH_Filename, local_filename); |
736 | 808 | ||
737 | U8 local_path_u8; | ||
738 | mesgsys->getU8("XferID", "FilePath", local_path_u8); | ||
739 | if( local_path_u8 < (U8)LL_PATH_LAST ) | ||
740 | { | 809 | { |
810 | U8 local_path_u8; | ||
811 | mesgsys->getU8("XferID", "FilePath", local_path_u8); | ||
741 | local_path = (ELLPath)local_path_u8; | 812 | local_path = (ELLPath)local_path_u8; |
742 | } | 813 | } |
743 | else | ||
744 | { | ||
745 | llwarns << "Invalid file path in LLXferManager::processFileRequest() " << (U32)local_path_u8 << llendl; | ||
746 | } | ||
747 | 814 | ||
748 | mesgsys->getUUIDFast(_PREHASH_XferID, _PREHASH_VFileID, uuid); | 815 | mesgsys->getUUIDFast(_PREHASH_XferID, _PREHASH_VFileID, uuid); |
749 | mesgsys->getS16Fast(_PREHASH_XferID, _PREHASH_VFileType, type_s16); | 816 | mesgsys->getS16Fast(_PREHASH_XferID, _PREHASH_VFileType, type_s16); |
@@ -782,6 +849,43 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user | |||
782 | } | 849 | } |
783 | else if (!local_filename.empty()) | 850 | else if (!local_filename.empty()) |
784 | { | 851 | { |
852 | // See DEV-21775 for detailed security issues | ||
853 | |||
854 | if (local_path == LL_PATH_NONE) | ||
855 | { | ||
856 | // this handles legacy simulators that are passing objects | ||
857 | // by giving a filename that explicitly names the cache directory | ||
858 | static const std::string legacy_cache_prefix = "data/"; | ||
859 | if (remove_prefix(local_filename, legacy_cache_prefix)) | ||
860 | { | ||
861 | local_path = LL_PATH_CACHE; | ||
862 | } | ||
863 | } | ||
864 | |||
865 | switch (local_path) | ||
866 | { | ||
867 | case LL_PATH_NONE: | ||
868 | if(!validateFileForTransfer(local_filename)) | ||
869 | { | ||
870 | llwarns << "SECURITY: Unapproved filename '" << local_filename << llendl; | ||
871 | return; | ||
872 | } | ||
873 | break; | ||
874 | |||
875 | case LL_PATH_CACHE: | ||
876 | if(!verify_cache_filename(local_filename)) | ||
877 | { | ||
878 | llwarns << "SECURITY: Illegal cache filename '" << local_filename << llendl; | ||
879 | return; | ||
880 | } | ||
881 | break; | ||
882 | |||
883 | default: | ||
884 | llwarns << "SECURITY: Restricted file dir enum: " << (U32)local_path << llendl; | ||
885 | return; | ||
886 | } | ||
887 | |||
888 | |||
785 | std::string expanded_filename = gDirUtilp->getExpandedFilename( local_path, local_filename ); | 889 | std::string expanded_filename = gDirUtilp->getExpandedFilename( local_path, local_filename ); |
786 | llinfos << "starting file transfer: " << expanded_filename << " to " << mesgsys->getSender() << llendl; | 890 | llinfos << "starting file transfer: " << expanded_filename << " to " << mesgsys->getSender() << llendl; |
787 | 891 | ||
@@ -861,6 +965,7 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user | |||
861 | } | 965 | } |
862 | } | 966 | } |
863 | 967 | ||
968 | |||
864 | /////////////////////////////////////////////////////////// | 969 | /////////////////////////////////////////////////////////// |
865 | 970 | ||
866 | void LLXferManager::processConfirmation (LLMessageSystem *mesgsys, void ** /*user_data*/) | 971 | void LLXferManager::processConfirmation (LLMessageSystem *mesgsys, void ** /*user_data*/) |
diff --git a/linden/indra/llmessage/llxfermanager.h b/linden/indra/llmessage/llxfermanager.h index 77f3f60..4bcf5de 100644 --- a/linden/indra/llmessage/llxfermanager.h +++ b/linden/indra/llmessage/llxfermanager.h | |||
@@ -108,6 +108,8 @@ class LLXferManager | |||
108 | // implementation methods | 108 | // implementation methods |
109 | virtual void startPendingDownloads(); | 109 | virtual void startPendingDownloads(); |
110 | virtual void addToList(LLXfer* xferp, LLXfer*& head, BOOL is_priority); | 110 | virtual void addToList(LLXfer* xferp, LLXfer*& head, BOOL is_priority); |
111 | std::multiset<std::string> mExpectedTransfers; // files that are authorized to transfer out | ||
112 | std::multiset<std::string> mExpectedRequests; // files that are authorized to be downloaded on top of | ||
111 | 113 | ||
112 | public: | 114 | public: |
113 | LLXferManager(LLVFS *vfs); | 115 | LLXferManager(LLVFS *vfs); |
@@ -168,6 +170,20 @@ class LLXferManager | |||
168 | const LLHost& remote_host, | 170 | const LLHost& remote_host, |
169 | void (*callback)(void**,S32,LLExtStat), void** user_data, | 171 | void (*callback)(void**,S32,LLExtStat), void** user_data, |
170 | BOOL is_priority = FALSE); | 172 | BOOL is_priority = FALSE); |
173 | /** | ||
174 | When arbitrary files are requested to be transfered (by giving a dir of LL_PATH_NONE) | ||
175 | they must be "expected", but having something pre-authorize them. This pair of functions | ||
176 | maintains a pre-authorized list. The first function adds something to the list, the second | ||
177 | checks if is authorized, removing it if so. In this way, a file is only authorized for | ||
178 | a single use. | ||
179 | */ | ||
180 | virtual void expectFileForTransfer(const std::string& filename); | ||
181 | virtual bool validateFileForTransfer(const std::string& filename); | ||
182 | /** | ||
183 | Same idea, but for the viewer about to call InitiateDownload to track what it requested. | ||
184 | */ | ||
185 | virtual void expectFileForRequest(const std::string& filename); | ||
186 | virtual bool validateFileForRequest(const std::string& filename); | ||
171 | 187 | ||
172 | /* | 188 | /* |
173 | // xfer request (may be memory or file) | 189 | // xfer request (may be memory or file) |