diff options
-rw-r--r-- | apt-pkg/acquire-item.cc | 248 | ||||
-rw-r--r-- | apt-pkg/acquire-item.h | 58 |
2 files changed, 171 insertions, 135 deletions
diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc index 675a7ed41..b3c41a178 100644 --- a/apt-pkg/acquire-item.cc +++ b/apt-pkg/acquire-item.cc @@ -933,6 +933,23 @@ void pkgAcqIndexMergeDiffs::Done(string Message,unsigned long long Size,HashStri } } /*}}}*/ + +// AcqBaseIndex::VerifyHashByMetaKey - verify hash for the given metakey /*{{{*/ +bool pkgAcqBaseIndex::VerifyHashByMetaKey(HashStringList const &Hashes) +{ + if(MetaKey != "" && Hashes.size() > 0) + { + indexRecords::checkSum *Record = MetaIndexParser->Lookup(MetaKey); + if(Record && Record->Hashes.usable() && Hashes != Record->Hashes) + { + printHashSumComparision(RealURI, Record->Hashes, Hashes); + return false; + } + } + return true; +} + + // AcqIndex::AcqIndex - Constructor /*{{{*/ // --------------------------------------------------------------------- /* The package file is added to the queue and a second class is @@ -940,8 +957,10 @@ void pkgAcqIndexMergeDiffs::Done(string Message,unsigned long long Size,HashStri pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner, string URI,string URIDesc,string ShortDesc, HashStringList const &ExpectedHash) - : pkgAcqBaseIndex(Owner, 0, NULL, ExpectedHash, NULL), RealURI(URI) + : pkgAcqBaseIndex(Owner, 0, NULL, ExpectedHash, NULL) { + RealURI = URI; + AutoSelectCompression(); Init(URI, URIDesc, ShortDesc); @@ -958,8 +977,10 @@ pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner, HashStringList const &ExpectedHash, indexRecords *MetaIndexParser) : pkgAcqBaseIndex(Owner, TransactionManager, Target, ExpectedHash, - MetaIndexParser), RealURI(Target->URI) + MetaIndexParser) { + RealURI = Target->URI; + // autoselect the compression method AutoSelectCompression(); Init(Target->URI, Target->Description, Target->ShortDesc); @@ -974,34 +995,38 @@ pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner, void pkgAcqIndex::AutoSelectCompression() { std::vector<std::string> types = APT::Configuration::getCompressionTypes(); - CompressionExtension = ""; + CompressionExtensions = ""; if (ExpectedHashes.usable()) { - for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t) - if (*t == "uncompressed" || MetaIndexParser->Exists(string(Target->MetaKey).append(".").append(*t)) == true) - CompressionExtension.append(*t).append(" "); + for (std::vector<std::string>::const_iterator t = types.begin(); + t != types.end(); ++t) + { + std::string CompressedMetaKey = string(Target->MetaKey).append(".").append(*t); + if (*t == "uncompressed" || + MetaIndexParser->Exists(CompressedMetaKey) == true) + CompressionExtensions.append(*t).append(" "); + } } else { for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t) - CompressionExtension.append(*t).append(" "); + CompressionExtensions.append(*t).append(" "); } - if (CompressionExtension.empty() == false) - CompressionExtension.erase(CompressionExtension.end()-1); + if (CompressionExtensions.empty() == false) + CompressionExtensions.erase(CompressionExtensions.end()-1); } // AcqIndex::Init - defered Constructor /*{{{*/ // --------------------------------------------------------------------- void pkgAcqIndex::Init(string const &URI, string const &URIDesc, string const &ShortDesc) { - Decompression = false; - Erase = false; + Stage = STAGE_DOWNLOAD; DestFile = _config->FindDir("Dir::State::lists") + "partial/"; DestFile += URItoFileName(URI); - std::string const comprExt = CompressionExtension.substr(0, CompressionExtension.find(' ')); - if (comprExt == "uncompressed") + ComprExt = CompressionExtensions.substr(0, CompressionExtensions.find(' ')); + if (ComprExt == "uncompressed") { Desc.URI = URI; if(Target) @@ -1009,10 +1034,10 @@ void pkgAcqIndex::Init(string const &URI, string const &URIDesc, } else { - Desc.URI = URI + '.' + comprExt; - DestFile = DestFile + '.' + comprExt; + Desc.URI = URI + '.' + ComprExt; + DestFile = DestFile + '.' + ComprExt; if(Target) - MetaKey = string(Target->MetaKey) + '.' + comprExt; + MetaKey = string(Target->MetaKey) + '.' + ComprExt; } // load the filesize @@ -1084,18 +1109,19 @@ string pkgAcqIndex::Custom600Headers() const /* */ void pkgAcqIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /*{{{*/ { - size_t const nextExt = CompressionExtension.find(' '); + size_t const nextExt = CompressionExtensions.find(' '); if (nextExt != std::string::npos) { - CompressionExtension = CompressionExtension.substr(nextExt+1); + CompressionExtensions = CompressionExtensions.substr(nextExt+1); Init(RealURI, Desc.Description, Desc.ShortDesc); return; } // on decompression failure, remove bad versions in partial/ - if (Decompression && Erase) { + if (Stage == STAGE_DECOMPRESS_AND_VERIFY) + { string s = _config->FindDir("Dir::State::lists") + "partial/"; - s.append(URItoFileName(RealURI)); + s += URItoFileName(RealURI) + '.' + ComprExt; unlink(s.c_str()); } @@ -1110,11 +1136,10 @@ void pkgAcqIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /*{{{*/ /* */ std::string pkgAcqIndex::GetFinalFilename() const { - std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' ')); std::string FinalFile = _config->FindDir("Dir::State::lists"); FinalFile += URItoFileName(RealURI); if (_config->FindB("Acquire::GzipIndexes",false) == true) - FinalFile += '.' + compExt; + FinalFile += '.' + ComprExt; return FinalFile; } /*}}}*/ @@ -1123,8 +1148,6 @@ std::string pkgAcqIndex::GetFinalFilename() const /* */ void pkgAcqIndex::ReverifyAfterIMS() { - std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' ')); - // update destfile to *not* include the compression extension when doing // a reverify (as its uncompressed on disk already) DestFile = _config->FindDir("Dir::State::lists") + "partial/"; @@ -1132,18 +1155,18 @@ void pkgAcqIndex::ReverifyAfterIMS() // adjust DestFile if its compressed on disk if (_config->FindB("Acquire::GzipIndexes",false) == true) - DestFile += '.' + compExt; + DestFile += '.' + ComprExt; // copy FinalFile into partial/ so that we check the hash again string FinalFile = GetFinalFilename(); - Decompression = true; + Stage = STAGE_DECOMPRESS_AND_VERIFY; Desc.URI = "copy:" + FinalFile; QueueURI(Desc); } /*}}}*/ -// pkgAcqIndex::ValidateFile - Validate the downloaded file /*{{{*/ -// --------------------------------------------------------------------- +// AcqIndex::ValidateFile - Validate the content of the downloaded file /*{{{*/ +// -------------------------------------------------------------------------- bool pkgAcqIndex::ValidateFile(const std::string &FileName) { // FIXME: this can go away once we only ever download stuff that @@ -1153,7 +1176,7 @@ bool pkgAcqIndex::ValidateFile(const std::string &FileName) /* Always validate the index file for correctness (all indexes must * have a Package field) (LP: #346386) (Closes: #627642) */ - FileFd fd(DestFile, FileFd::ReadOnly, FileFd::Extension); + FileFd fd(FileName, FileFd::ReadOnly, FileFd::Extension); // Only test for correctness if the content of the file is not empty // (empty is ok) if (fd.Size() > 0) @@ -1177,69 +1200,45 @@ bool pkgAcqIndex::ValidateFile(const std::string &FileName) to the uncompressed version of the file. If this is so the file is copied into the partial directory. In all other cases the file is decompressed with a compressed uri. */ -void pkgAcqIndex::Done(string Message, unsigned long long Size, +void pkgAcqIndex::Done(string Message, + unsigned long long Size, HashStringList const &Hashes, pkgAcquire::MethodConfig *Cfg) { Item::Done(Message,Size,Hashes,Cfg); - std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' ')); - if (Decompression == true) + switch(Stage) { - if (ExpectedHashes.usable() && ExpectedHashes != Hashes) - { - Desc.URI = RealURI; - RenameOnError(HashSumMismatch); - printHashSumComparision(RealURI, ExpectedHashes, Hashes); - Failed(Message, Cfg); - return; - } - - if(!ValidateFile(DestFile)) - { - RenameOnError(InvalidFormat); - Failed(Message, Cfg); - return; - } - - // FIXME: can we void the "Erase" bool here as its very non-local? - std::string CompressedFile = _config->FindDir("Dir::State::lists") + "partial/"; - CompressedFile += URItoFileName(RealURI); - if(_config->FindB("Acquire::GzipIndexes",false) == false) - CompressedFile += '.' + compExt; - - // Remove the compressed version. - if (Erase == true) - unlink(CompressedFile.c_str()); - - // Done, queue for rename on transaction finished - TransactionManager->TransactionStageCopy(this, DestFile, GetFinalFilename()); - - return; + case STAGE_DOWNLOAD: + StageDownloadDone(Message, Hashes, Cfg); + break; + case STAGE_DECOMPRESS_AND_VERIFY: + StageDecompressDone(Message, Hashes, Cfg); + break; } - - // FIXME: use the same method to find - // check the compressed hash too - if(MetaKey != "" && Hashes.size() > 0) +} + +// AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/ +void pkgAcqIndex::StageDownloadDone(string Message, + HashStringList const &Hashes, + pkgAcquire::MethodConfig *Cfg) +{ + // First check if the calculcated Hash of the (compressed) downloaded + // file matches the hash we have in the MetaIndexRecords for this file + if(VerifyHashByMetaKey(Hashes) == false) { - indexRecords::checkSum *Record = MetaIndexParser->Lookup(MetaKey); - if(Record && Record->Hashes.usable() && Hashes != Record->Hashes) - { - RenameOnError(HashSumMismatch); - printHashSumComparision(RealURI, Record->Hashes, Hashes); - Failed(Message, Cfg); - return; - } + RenameOnError(HashSumMismatch); + Failed(Message, Cfg); + return; } - Erase = false; Complete = true; // Handle the unzipd case string FileName = LookupTag(Message,"Alt-Filename"); if (FileName.empty() == false) { - Decompression = true; + Stage = STAGE_DECOMPRESS_AND_VERIFY; Local = true; DestFile += ".decomp"; Desc.URI = "copy:" + FileName; @@ -1263,43 +1262,32 @@ void pkgAcqIndex::Done(string Message, unsigned long long Size, ErrorText = "Method gave a blank filename"; } - if (FileName == DestFile) - Erase = true; - else + // Methods like e.g. "file:" will give us a (compressed) FileName that is + // not the "DestFile" we set, in this case we uncompress from the local file + if (FileName != DestFile) Local = true; - // do not reverify cdrom sources as apt-cdrom may rewrite the Packages - // file when its doing the indexcopy - if (RealURI.substr(0,6) == "cdrom:" && - StringToBool(LookupTag(Message,"IMS-Hit"),false) == true) - return; - - // The files timestamp matches, reverify by copy into partial/ - if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true) + // we need to verify the file against the current Release file again + // on if-modfied-since hit to avoid a stale attack against us + if(StringToBool(LookupTag(Message,"IMS-Hit"),false) == true) { - Erase = false; - ReverifyAfterIMS(); -#if 0 // ??? - // set destfile to the final destfile - if(_config->FindB("Acquire::GzipIndexes",false) == false) - { - DestFile = _config->FindDir("Dir::State::lists") + "partial/"; - DestFile += URItoFileName(RealURI); - } + // do not reverify cdrom sources as apt-cdrom may rewrite the Packages + // file when its doing the indexcopy + if (RealURI.substr(0,6) == "cdrom:") + return; - ReverifyAfterIMS(FileName); -#endif + // The files timestamp matches, reverify by copy into partial/ + ReverifyAfterIMS(); return; } - string decompProg; - // If we enable compressed indexes, queue for hash verification + // If we have compressed indexes enabled, queue for hash verification if (_config->FindB("Acquire::GzipIndexes",false)) { DestFile = _config->FindDir("Dir::State::lists") + "partial/"; - DestFile += URItoFileName(RealURI) + '.' + compExt; + DestFile += URItoFileName(RealURI) + '.' + ComprExt; - Decompression = true; + Stage = STAGE_DECOMPRESS_AND_VERIFY; Desc.URI = "copy:" + FileName; QueueURI(Desc); @@ -1307,16 +1295,19 @@ void pkgAcqIndex::Done(string Message, unsigned long long Size, } // get the binary name for your used compression type - decompProg = _config->Find(string("Acquire::CompressionTypes::").append(compExt),""); - if(decompProg.empty() == false); - else if(compExt == "uncompressed") + string decompProg; + if(ComprExt == "uncompressed") decompProg = "copy"; - else { - _error->Error("Unsupported extension: %s", compExt.c_str()); + else + decompProg = _config->Find(string("Acquire::CompressionTypes::").append(ComprExt),""); + if(decompProg.empty() == true) + { + _error->Error("Unsupported extension: %s", ComprExt.c_str()); return; } - Decompression = true; + // queue uri for the next stage + Stage = STAGE_DECOMPRESS_AND_VERIFY; DestFile += ".decomp"; Desc.URI = decompProg + ":" + FileName; QueueURI(Desc); @@ -1331,6 +1322,43 @@ void pkgAcqIndex::Done(string Message, unsigned long long Size, #pragma GCC diagnostic pop #endif } + /*}}}*/ +// pkgAcqIndex::StageDecompressDone - Final verification /*{{{*/ +void pkgAcqIndex::StageDecompressDone(string Message, + HashStringList const &Hashes, + pkgAcquire::MethodConfig *Cfg) +{ + if (ExpectedHashes.usable() && ExpectedHashes != Hashes) + { + Desc.URI = RealURI; + RenameOnError(HashSumMismatch); + printHashSumComparision(RealURI, ExpectedHashes, Hashes); + Failed(Message, Cfg); + return; + } + + if(!ValidateFile(DestFile)) + { + RenameOnError(InvalidFormat); + Failed(Message, Cfg); + return; + } + + // remove the compressed version of the file (if the file got uncompressed) + URI Get = LookupTag(Message, "URI"); + if (Get.Access != "copy") + { + // To account for relative paths + std::string CompressedFile = Get.Host + Get.Path; + unlink(CompressedFile.c_str()); + } + + // Done, queue for rename on transaction finished + TransactionManager->TransactionStageCopy(this, DestFile, GetFinalFilename()); + + return; +} + /*}}}*/ /*}}}*/ // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/ // --------------------------------------------------------------------- @@ -1371,10 +1399,10 @@ string pkgAcqIndexTrans::Custom600Headers() const /* */ void pkgAcqIndexTrans::Failed(string Message,pkgAcquire::MethodConfig *Cnf) { - size_t const nextExt = CompressionExtension.find(' '); + size_t const nextExt = CompressionExtensions.find(' '); if (nextExt != std::string::npos) { - CompressionExtension = CompressionExtension.substr(nextExt+1); + CompressionExtensions = CompressionExtensions.substr(nextExt+1); Init(RealURI, Desc.Description, Desc.ShortDesc); Status = StatIdle; return; diff --git a/apt-pkg/acquire-item.h b/apt-pkg/acquire-item.h index 30a8850e4..6518c9a98 100644 --- a/apt-pkg/acquire-item.h +++ b/apt-pkg/acquire-item.h @@ -601,10 +601,20 @@ class pkgAcqBaseIndex : public pkgAcquire::Item /** \brief Pointer to the IndexTarget data */ const struct IndexTarget * Target; + + /** \brief Pointer to the indexRecords parser */ indexRecords *MetaIndexParser; + /** \brief The MetaIndex Key */ std::string MetaKey; + /** \brief The URI of the index file to recreate at our end (either + * by downloading it or by applying partial patches). + */ + std::string RealURI; + + bool VerifyHashByMetaKey(HashStringList const &Hashes); + pkgAcqBaseIndex(pkgAcquire *Owner, pkgAcqMetaBase *TransactionManager, struct IndexTarget const * const Target, @@ -631,11 +641,6 @@ class pkgAcqDiffIndex : public pkgAcqBaseIndex /** \brief If \b true, debugging information will be written to std::clog. */ bool Debug; - /** \brief The URI of the index file to recreate at our end (either - * by downloading it or by applying partial patches). - */ - std::string RealURI; - /** \brief The index file which will be patched to generate the new * file. */ @@ -712,11 +717,6 @@ class pkgAcqIndexMergeDiffs : public pkgAcqBaseIndex */ bool Debug; - /** \brief URI of the package index file that is being - * reconstructed. - */ - std::string RealURI; - /** \brief description of the file being downloaded. */ std::string Description; @@ -831,11 +831,6 @@ class pkgAcqIndexDiffs : public pkgAcqBaseIndex */ bool Debug; - /** \brief The URI of the package index file that is being - * reconstructed. - */ - std::string RealURI; - /** A description of the file being downloaded. */ std::string Description; @@ -927,23 +922,36 @@ class pkgAcqIndex : public pkgAcqBaseIndex protected: - /** \brief If \b true, the index file has been decompressed. */ - bool Decompression; - - /** \brief If \b true, the partially downloaded file will be - * removed when the download completes. + /** \brief The stages the method goes through + * + * The method first downloads the indexfile, then its decompressed (or + * copied) and verified */ - bool Erase; + enum AllStages { + STAGE_DOWNLOAD, + STAGE_DECOMPRESS_AND_VERIFY, + }; + AllStages Stage; - /** \brief The object that is actually being fetched (minus any - * compression-related extensions). + /** \brief Handle what needs to be done when the download is done */ + void StageDownloadDone(std::string Message, + HashStringList const &Hashes, + pkgAcquire::MethodConfig *Cfg); + + /** \brief Handle what needs to be done when the decompression/copy is + * done */ - std::string RealURI; + void StageDecompressDone(std::string Message, + HashStringList const &Hashes, + pkgAcquire::MethodConfig *Cfg); /** \brief The compression-related file extensions that are being * added to the downloaded file one by one if first fails (e.g., "gz bz2"). */ - std::string CompressionExtension; + std::string CompressionExtensions; + + /** \brief The actual compression extension currently used */ + std::string ComprExt; /** \brief Do the changes needed to fetch via AptByHash (if needed) */ void InitByHashIfNeeded(const std::string MetaKey); |