From 4d1e45f20f924f070d0f0139878c2c96e698fb07 Mon Sep 17 00:00:00 2001
From: "Andrew A. de Laix" <alain@lindenlab.com>
Date: Thu, 4 Nov 2010 17:14:12 -0700
Subject: [PATCH] added hash validation of downloaded file.

---
 .../updater/llupdatedownloader.cpp            | 41 ++++++++++++++++---
 1 file changed, 36 insertions(+), 5 deletions(-)

diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp
index 23772e021e0..59e929d99fa 100644
--- a/indra/viewer_components/updater/llupdatedownloader.cpp
+++ b/indra/viewer_components/updater/llupdatedownloader.cpp
@@ -29,6 +29,7 @@
 #include <curl/curl.h>
 #include "lldir.h"
 #include "llfile.h"
+#include "llmd5.h"
 #include "llsd.h"
 #include "llsdserialize.h"
 #include "llthread.h"
@@ -58,6 +59,7 @@ class LLUpdateDownloader::Implementation:
 	void run(void);
 	void startDownloading(LLURI const & uri, std::string const & hash);
 	void throwOnCurlError(CURLcode code);
+	bool validateDownload(void);
 
 	LOG_CLASS(LLUpdateDownloader::Implementation);
 };
@@ -130,6 +132,7 @@ namespace {
 		return bytes;
 	}
 
+
 	size_t header_function(void * data, size_t blockSize, size_t blocks, void * downloader)
 	{
 		size_t bytes = blockSize * blocks;
@@ -219,10 +222,18 @@ void LLUpdateDownloader::Implementation::run(void)
 {
 	CURLcode code = curl_easy_perform(mCurl);
 	if(code == CURLE_OK) {
-		LL_INFOS("UpdateDownload") << "download successful" << LL_ENDL;
-		mClient.downloadComplete();
+		if(validateDownload()) {
+			LL_INFOS("UpdateDownload") << "download successful" << LL_ENDL;
+			mClient.downloadComplete();
+		} else {
+			LL_INFOS("UpdateDownload") << "download failed hash check" << LL_ENDL;
+			std::string filePath = mDownloadData["path"].asString();
+			if(filePath.size() != 0) LLFile::remove(filePath);
+			mClient.downloadError("failed hash check");
+		}
 	} else {
-		LL_WARNS("UpdateDownload") << "download failed with error " << code << LL_ENDL;
+		LL_WARNS("UpdateDownload") << "download failed with error '" << 
+			curl_easy_strerror(code) << "'" << LL_ENDL;
 		mClient.downloadError("curl error");
 	}
 }
@@ -253,6 +264,7 @@ void LLUpdateDownloader::Implementation::resumeDownloading(LLSD const & download
 {
 }
 
+
 /*
 bool LLUpdateDownloader::Implementation::shouldResumeOngoingDownload(LLURI const & uri, LLSD & downloadData)
 {
@@ -289,8 +301,9 @@ void LLUpdateDownloader::Implementation::startDownloading(LLURI const & uri, std
 	std::string filePath = gDirUtilp->getExpandedFilename(LL_PATH_TEMP, fileName);
 	mDownloadData["path"] = filePath;
 
-	LL_INFOS("UpdateDownload") << "downloading " << filePath << "\n"
-		<< "from " << uri.asString() << LL_ENDL;
+	LL_INFOS("UpdateDownload") << "downloading " << filePath
+		<< " from " << uri.asString() << LL_ENDL;
+	LL_INFOS("UpdateDownload") << "hash of file is " << hash << LL_ENDL;
 		
 	llofstream dataStream(mDownloadRecordPath);
 	LLSDSerialize parser;
@@ -315,3 +328,21 @@ void LLUpdateDownloader::Implementation::throwOnCurlError(CURLcode code)
 		; // No op.
 	}
 }
+
+
+bool LLUpdateDownloader::Implementation::validateDownload(void)
+{
+	std::string filePath = mDownloadData["path"].asString();
+	llifstream fileStream(filePath);
+	if(!fileStream) return false;
+
+	std::string hash = mDownloadData["hash"].asString();
+	if(hash.size() != 0) {
+		LL_INFOS("UpdateDownload") << "checking hash..." << LL_ENDL;
+		char digest[33];
+		LLMD5(fileStream).hex_digest(digest);
+		return hash == digest;
+	} else {
+		return true; // No hash check provided.
+	}
+}
-- 
GitLab