X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/8c782efd93342c6119e8ba2ff6989b7a164b7f3d..30b683f4f3021cd191ffef04bfaf2deb65820a52:/apt-pkg/acquire-item.cc diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc index 3feb17ffa..eee1097e9 100644 --- a/apt-pkg/acquire-item.cc +++ b/apt-pkg/acquire-item.cc @@ -64,10 +64,12 @@ static void printHashSumComparision(std::string const &URI, HashStringList const /*}}}*/ // Acquire::Item::Item - Constructor /*{{{*/ -pkgAcquire::Item::Item(pkgAcquire *Owner, HashStringList const &ExpectedHashes) : - Owner(Owner), FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false), - Local(false), QueueCounter(0), ExpectedAdditionalItems(0), - ExpectedHashes(ExpectedHashes) +pkgAcquire::Item::Item(pkgAcquire *Owner, + HashStringList const &ExpectedHashes, + unsigned long TransactionID) + : Owner(Owner), FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false), + Local(false), QueueCounter(0), TransactionID(TransactionID), + ExpectedAdditionalItems(0), ExpectedHashes(ExpectedHashes) { Owner->Add(this); Status = StatIdle; @@ -88,7 +90,8 @@ pkgAcquire::Item::~Item() void pkgAcquire::Item::Failed(string Message,pkgAcquire::MethodConfig *Cnf) { Status = StatIdle; - ErrorText = LookupTag(Message,"Message"); + if(ErrorText == "") + ErrorText = LookupTag(Message,"Message"); UsedMirror = LookupTag(Message,"UsedMirror"); if (QueueCounter <= 1) { @@ -134,7 +137,7 @@ void pkgAcquire::Item::Done(string Message,unsigned long long Size,HashStringLis { // We just downloaded something.. string FileName = LookupTag(Message,"Filename"); - UsedMirror = LookupTag(Message,"UsedMirror"); + UsedMirror = LookupTag(Message,"UsedMirror"); if (Complete == false && !Local && FileName == DestFile) { if (Owner->Log != 0) @@ -238,10 +241,12 @@ void pkgAcquire::Item::ReportMirrorFailure(string FailCode) // --------------------------------------------------------------------- /* Get a sub-index file based on checksums from a 'master' file and possibly query additional files */ -pkgAcqSubIndex::pkgAcqSubIndex(pkgAcquire *Owner, string const &URI, - string const &URIDesc, string const &ShortDesc, - HashStringList const &ExpectedHashes) - : Item(Owner, ExpectedHashes) +pkgAcqSubIndex::pkgAcqSubIndex(pkgAcquire *Owner, + unsigned long TransactionID, + string const &URI, + string const &URIDesc, string const &ShortDesc, + HashStringList const &ExpectedHashes) + : Item(Owner, ExpectedHashes, TransactionID) { /* XXX: Beware: Currently this class does nothing (of value) anymore ! */ Debug = _config->FindB("Debug::pkgAcquire::SubIndex",false); @@ -354,10 +359,12 @@ bool pkgAcqSubIndex::ParseIndex(string const &IndexFile) /*{{{*/ * the original packages file */ pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire *Owner, + unsigned long TransactionID, IndexTarget const * const Target, HashStringList const &ExpectedHashes, indexRecords *MetaIndexParser) - : pkgAcqBaseIndex(Owner, Target, ExpectedHashes, MetaIndexParser) + : pkgAcqBaseIndex(Owner, TransactionID, Target, ExpectedHashes, + MetaIndexParser) { Debug = _config->FindB("Debug::pkgAcquire::Diffs",false); @@ -455,7 +462,8 @@ bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile) /*{{{*/ std::clog << "Package file is up-to-date" << std::endl; // list cleanup needs to know that this file as well as the already // present index is ours, so we create an empty diff to save it for us - new pkgAcqIndexDiffs(Owner, Target, ExpectedHashes, MetaIndexParser, + new pkgAcqIndexDiffs(Owner, TransactionID, Target, + ExpectedHashes, MetaIndexParser, ServerSha1, available_patches); return true; } @@ -542,14 +550,17 @@ bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile) /*{{{*/ if (pdiff_merge == false) { - new pkgAcqIndexDiffs(Owner, Target, ExpectedHashes, MetaIndexParser, + new pkgAcqIndexDiffs(Owner, TransactionID, Target, ExpectedHashes, + MetaIndexParser, ServerSha1, available_patches); } else { std::vector *diffs = new std::vector(available_patches.size()); for(size_t i = 0; i < available_patches.size(); ++i) - (*diffs)[i] = new pkgAcqIndexMergeDiffs(Owner, Target, + (*diffs)[i] = new pkgAcqIndexMergeDiffs(Owner, + TransactionID, + Target, ExpectedHashes, MetaIndexParser, available_patches[i], @@ -577,7 +588,7 @@ void pkgAcqDiffIndex::Failed(string Message,pkgAcquire::MethodConfig * /*Cnf*/)/ std::clog << "pkgAcqDiffIndex failed: " << Desc.URI << " with " << Message << std::endl << "Falling back to normal index file acquire" << std::endl; - new pkgAcqIndex(Owner, Target, ExpectedHashes, MetaIndexParser); + new pkgAcqIndex(Owner, TransactionID, Target, ExpectedHashes, MetaIndexParser); Complete = false; Status = StatDone; @@ -620,12 +631,13 @@ void pkgAcqDiffIndex::Done(string Message,unsigned long long Size,HashStringList * for each diff and the index */ pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire *Owner, + unsigned long TransactionID, struct IndexTarget const * const Target, HashStringList const &ExpectedHashes, indexRecords *MetaIndexParser, string ServerSha1, vector diffs) - : pkgAcqBaseIndex(Owner, Target, ExpectedHashes, MetaIndexParser), + : pkgAcqBaseIndex(Owner, TransactionID, Target, ExpectedHashes, MetaIndexParser), available_patches(diffs), ServerSha1(ServerSha1) { @@ -657,19 +669,28 @@ void pkgAcqIndexDiffs::Failed(string Message,pkgAcquire::MethodConfig * /*Cnf*/) if(Debug) std::clog << "pkgAcqIndexDiffs failed: " << Desc.URI << " with " << Message << std::endl << "Falling back to normal index file acquire" << std::endl; - new pkgAcqIndex(Owner, Target, ExpectedHashes, MetaIndexParser); + new pkgAcqIndex(Owner, TransactionID, Target, ExpectedHashes, MetaIndexParser); Finish(); } /*}}}*/ // Finish - helper that cleans the item out of the fetcher queue /*{{{*/ void pkgAcqIndexDiffs::Finish(bool allDone) { + if(Debug) + std::clog << "pkgAcqIndexDiffs::Finish(): " + << allDone << " " + << Desc.URI << std::endl; + // we restore the original name, this is required, otherwise // the file will be cleaned if(allDone) { DestFile = _config->FindDir("Dir::State::lists"); DestFile += URItoFileName(RealURI); + + // FIXME: we want the rred stuff to use the real transactional update + // this is just a workaround + PartialFile = DestFile; if(HashSums().usable() && !HashSums().VerifyFile(DestFile)) { @@ -797,7 +818,7 @@ void pkgAcqIndexDiffs::Done(string Message,unsigned long long Size, HashStringLi // see if there is more to download if(available_patches.empty() == false) { - new pkgAcqIndexDiffs(Owner, Target, + new pkgAcqIndexDiffs(Owner, TransactionID, Target, ExpectedHashes, MetaIndexParser, ServerSha1, available_patches); return Finish(); @@ -808,12 +829,13 @@ void pkgAcqIndexDiffs::Done(string Message,unsigned long long Size, HashStringLi /*}}}*/ // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/ pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire *Owner, + unsigned long TransactionID, struct IndexTarget const * const Target, HashStringList const &ExpectedHashes, indexRecords *MetaIndexParser, DiffInfo const &patch, std::vector const * const allPatches) - : pkgAcqBaseIndex(Owner, Target, ExpectedHashes, MetaIndexParser), + : pkgAcqBaseIndex(Owner, TransactionID, Target, ExpectedHashes, MetaIndexParser), patch(patch), allPatches(allPatches), State(StateFetchDiff) { @@ -856,7 +878,7 @@ void pkgAcqIndexMergeDiffs::Failed(string Message,pkgAcquire::MethodConfig * /*C // first failure means we should fallback State = StateErrorDiff; std::clog << "Falling back to normal index file acquire" << std::endl; - new pkgAcqIndex(Owner, Target, ExpectedHashes, MetaIndexParser); + new pkgAcqIndex(Owner, TransactionID, Target, ExpectedHashes, MetaIndexParser); } /*}}}*/ void pkgAcqIndexMergeDiffs::Done(string Message,unsigned long long Size,HashStringList const &Hashes, /*{{{*/ @@ -916,6 +938,8 @@ void pkgAcqIndexMergeDiffs::Done(string Message,unsigned long long Size,HashStri // otherwise lists cleanup will eat the file DestFile = FinalFile; + // FIXME: make the merged rred code really transactional + PartialFile = FinalFile; // ensure the ed's are gone regardless of list-cleanup for (std::vector::const_iterator I = allPatches->begin(); @@ -939,28 +963,39 @@ void pkgAcqIndexMergeDiffs::Done(string Message,unsigned long long Size,HashStri pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner, string URI,string URIDesc,string ShortDesc, HashStringList const &ExpectedHash, string comprExt) - : pkgAcqBaseIndex(Owner, NULL, ExpectedHash, NULL), RealURI(URI) + : pkgAcqBaseIndex(Owner, 0, NULL, ExpectedHash, NULL), RealURI(URI) { - if(comprExt.empty() == true) - { - // autoselect the compression method - std::vector types = APT::Configuration::getCompressionTypes(); - for (std::vector::const_iterator t = types.begin(); t != types.end(); ++t) - comprExt.append(*t).append(" "); - if (comprExt.empty() == false) - comprExt.erase(comprExt.end()-1); - } - CompressionExtension = comprExt; - + AutoSelectCompression(); Init(URI, URIDesc, ShortDesc); + + if(_config->FindB("Debug::Acquire::Transaction", false) == true) + std::clog << "New pkgIndex with TransactionID " + << TransactionID << std::endl; } -pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner, IndexTarget const *Target, + /*}}}*/ +// AcqIndex::AcqIndex - Constructor /*{{{*/ +// --------------------------------------------------------------------- +pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner, + unsigned long TransactionID, + IndexTarget const *Target, HashStringList const &ExpectedHash, indexRecords *MetaIndexParser) - : pkgAcqBaseIndex(Owner, Target, ExpectedHash, MetaIndexParser), - RealURI(Target->URI) + : pkgAcqBaseIndex(Owner, TransactionID, Target, ExpectedHash, + MetaIndexParser), RealURI(Target->URI) { // autoselect the compression method + AutoSelectCompression(); + Init(Target->URI, Target->Description, Target->ShortDesc); + + if(_config->FindB("Debug::Acquire::Transaction", false) == true) + std::clog << "New pkgIndex with TransactionID " + << TransactionID << std::endl; +} + /*}}}*/ +// AcqIndex::AutoSelectCompression - Select compression /*{{{*/ +// --------------------------------------------------------------------- +void pkgAcqIndex::AutoSelectCompression() +{ std::vector types = APT::Configuration::getCompressionTypes(); CompressionExtension = ""; if (ExpectedHashes.usable()) @@ -976,10 +1011,7 @@ pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner, IndexTarget const *Target, } if (CompressionExtension.empty() == false) CompressionExtension.erase(CompressionExtension.end()-1); - - Init(Target->URI, Target->Description, Target->ShortDesc); } - /*}}}*/ // AcqIndex::Init - defered Constructor /*{{{*/ void pkgAcqIndex::Init(string const &URI, string const &URIDesc, string const &ShortDesc) { Decompression = false; @@ -989,7 +1021,6 @@ void pkgAcqIndex::Init(string const &URI, string const &URIDesc, string const &S DestFile += URItoFileName(URI); std::string const comprExt = CompressionExtension.substr(0, CompressionExtension.find(' ')); - std::string MetaKey; if (comprExt == "uncompressed") { Desc.URI = URI; @@ -1074,6 +1105,9 @@ string pkgAcqIndex::Custom600Headers() const return msg; } /*}}}*/ +// pkgAcqIndex::Failed - getting the indexfile failed /*{{{*/ +// --------------------------------------------------------------------- +/* */ void pkgAcqIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /*{{{*/ { size_t const nextExt = CompressionExtension.find(' '); @@ -1092,19 +1126,52 @@ void pkgAcqIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /*{{{*/ } Item::Failed(Message,Cnf); + + /// cancel the entire transaction + Owner->AbortTransaction(TransactionID); } /*}}}*/ +// pkgAcqIndex::GetFinalFilename - Return the full final file path /*{{{*/ +// --------------------------------------------------------------------- +/* */ +std::string pkgAcqIndex::GetFinalFilename(std::string const &URI, + std::string const &compExt) +{ + std::string FinalFile = _config->FindDir("Dir::State::lists"); + FinalFile += URItoFileName(URI); + if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz") + FinalFile += ".gz"; + return FinalFile; +} + /*}}}*/ +// AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void pkgAcqIndex::ReverifyAfterIMS(std::string const &FileName) +{ + std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' ')); + if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz") + DestFile += ".gz"; + + // copy FinalFile into partial/ so that we check the hash again + string FinalFile = GetFinalFilename(RealURI, compExt); + Decompression = true; + Desc.URI = "copy:" + FinalFile; + QueueURI(Desc); +} + /*}}}*/ // AcqIndex::Done - Finished a fetch /*{{{*/ // --------------------------------------------------------------------- /* This goes through a number of states.. On the initial fetch the method could possibly return an alternate filename which points 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 gzip uri. */ + is decompressed with a compressed uri. */ 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) { @@ -1112,6 +1179,7 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,HashStringList con { RenameOnError(HashSumMismatch); printHashSumComparision(RealURI, ExpectedHashes, Hashes); + Failed(Message, Cfg); return; } @@ -1121,9 +1189,10 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,HashStringList con /* Always verify the index file for correctness (all indexes must * have a Package field) (LP: #346386) (Closes: #627642) */ - FileFd fd(DestFile, FileFd::ReadOnly); - // Only test for correctness if the file is not empty (empty is ok) - if (fd.FileSize() > 0) + FileFd fd(DestFile, FileFd::ReadOnly, FileFd::Extension); + // Only test for correctness if the content of the file is not empty + // (empty is ok) + if (fd.Size() > 0) { pkgTagSection sec; pkgTagFile tag(&fd); @@ -1132,27 +1201,38 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,HashStringList con if (_error->PendingError() == true || tag.Step(sec) == false || sec.Exists("Package") == false) { RenameOnError(InvalidFormat); + Failed(Message, Cfg); return; } } - // Done, move it into position - string FinalFile = _config->FindDir("Dir::State::lists"); - FinalFile += URItoFileName(RealURI); - Rename(DestFile,FinalFile); - chmod(FinalFile.c_str(),0644); - - /* We restore the original name to DestFile so that the clean operation - will work OK */ - DestFile = _config->FindDir("Dir::State::lists") + "partial/"; - DestFile += URItoFileName(RealURI); - + // 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); // Remove the compressed version. if (Erase == true) - unlink(DestFile.c_str()); + unlink(CompressedFile.c_str()); + + // Done, queue for rename on transaction finished + PartialFile = DestFile; + DestFile = GetFinalFilename(RealURI, compExt); return; } + + // FIXME: use the same method to find + // check the compressed hash too + if(MetaKey != "" && Hashes.size() > 0) + { + 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; + } + } Erase = false; Complete = true; @@ -1163,7 +1243,10 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,HashStringList con { // The files timestamp matches if (StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false) == true) + { + ReverifyAfterIMS(FileName); return; + } Decompression = true; Local = true; DestFile += ".decomp"; @@ -1180,13 +1263,10 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,HashStringList con ErrorText = "Method gave a blank filename"; } - std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' ')); - // The files timestamp matches - if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true) { - if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz") - // Update DestFile for .gz suffix so that the clean operation keeps it - DestFile += ".gz"; + if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true) + { + ReverifyAfterIMS(FileName); return; } @@ -1199,14 +1279,9 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,HashStringList con // If we enable compressed indexes and already have gzip, keep it if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz" && !Local) { - string FinalFile = _config->FindDir("Dir::State::lists"); - FinalFile += URItoFileName(RealURI) + ".gz"; - Rename(DestFile,FinalFile); - chmod(FinalFile.c_str(),0644); - - // Update DestFile for .gz suffix so that the clean operation keeps it - DestFile = _config->FindDir("Dir::State::lists") + "partial/"; - DestFile += URItoFileName(RealURI) + ".gz"; + // Done, queue for rename on transaction finished + PartialFile = DestFile; + DestFile = GetFinalFilename(RealURI, compExt); return; } @@ -1237,9 +1312,13 @@ pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner, : pkgAcqIndex(Owner, URI, URIDesc, ShortDesc, HashStringList(), "") { } -pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner, IndexTarget const * const Target, - HashStringList const &ExpectedHashes, indexRecords *MetaIndexParser) - : pkgAcqIndex(Owner, Target, ExpectedHashes, MetaIndexParser) + /*}}}*/ +pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner, + unsigned long TransactionID, + IndexTarget const * const Target, + HashStringList const &ExpectedHashes, + indexRecords *MetaIndexParser) + : pkgAcqIndex(Owner, TransactionID, Target, ExpectedHashes, MetaIndexParser) { // load the filesize indexRecords::checkSum *Record = MetaIndexParser->Lookup(string(Target->MetaKey)); @@ -1274,6 +1353,7 @@ void pkgAcqIndexTrans::Failed(string Message,pkgAcquire::MethodConfig *Cnf) return; } + // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor if (Cnf->LocalOnly == true || StringToBool(LookupTag(Message,"Transient-Failure"),false) == false) { @@ -1287,15 +1367,58 @@ void pkgAcqIndexTrans::Failed(string Message,pkgAcquire::MethodConfig *Cnf) Item::Failed(Message,Cnf); } /*}}}*/ -pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner, /*{{{*/ + +pkgAcqMetaSigBase::pkgAcqMetaSigBase(pkgAcquire *Owner, + HashStringList const &ExpectedHashes, + unsigned long TransactionID) + : Item(Owner, ExpectedHashes, TransactionID) +{ +} + /*{{{*/ +bool pkgAcqMetaSigBase::GenerateAuthWarning(const std::string &RealURI, + const std::string &Message) +{ + string Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI); + + if(FileExists(Final)) + { + Status = StatTransientNetworkError; + _error->Warning(_("An error occurred during the signature " + "verification. The repository is not updated " + "and the previous index files will be used. " + "GPG error: %s: %s\n"), + Desc.Description.c_str(), + LookupTag(Message,"Message").c_str()); + RunScripts("APT::Update::Auth-Failure"); + return true; + } else if (LookupTag(Message,"Message").find("NODATA") != string::npos) { + /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */ + _error->Error(_("GPG error: %s: %s"), + Desc.Description.c_str(), + LookupTag(Message,"Message").c_str()); + Status = StatError; + return true; + } else { + _error->Warning(_("GPG error: %s: %s"), + Desc.Description.c_str(), + LookupTag(Message,"Message").c_str()); + } + // gpgv method failed + ReportMirrorFailure("GPGFailure"); + return false; +} + /*}}}*/ + + +pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner, /*{{{*/ + unsigned long TransactionID, string URI,string URIDesc,string ShortDesc, - string MetaIndexURI, string MetaIndexURIDesc, - string MetaIndexShortDesc, + string MetaIndexFile, const vector* IndexTargets, indexRecords* MetaIndexParser) : - Item(Owner, HashStringList()), RealURI(URI), MetaIndexURI(MetaIndexURI), - MetaIndexURIDesc(MetaIndexURIDesc), MetaIndexShortDesc(MetaIndexShortDesc), - MetaIndexParser(MetaIndexParser), IndexTargets(IndexTargets) + pkgAcqMetaSigBase(Owner, HashStringList(), TransactionID), RealURI(URI), + MetaIndexParser(MetaIndexParser), MetaIndexFile(MetaIndexFile), + IndexTargets(IndexTargets), AuthPass(false), IMSHit(false) { DestFile = _config->FindDir("Dir::State::lists") + "partial/"; DestFile += URItoFileName(URI); @@ -1305,42 +1428,22 @@ pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner, /*{{{*/ // partial download anyway unlink(DestFile.c_str()); + // set the TransactionID + if(_config->FindB("Debug::Acquire::Transaction", false) == true) + std::clog << "New pkgAcqMetaSig with TransactionID " + << TransactionID << std::endl; + // Create the item Desc.Description = URIDesc; Desc.Owner = this; Desc.ShortDesc = ShortDesc; Desc.URI = URI; - - string Final = _config->FindDir("Dir::State::lists"); - Final += URItoFileName(RealURI); - if (RealFileExists(Final) == true) - { - // File was already in place. It needs to be re-downloaded/verified - // because Release might have changed, we do give it a different - // name than DestFile because otherwise the http method will - // send If-Range requests and there are too many broken servers - // out there that do not understand them - LastGoodSig = DestFile+".reverify"; - Rename(Final,LastGoodSig); - } - - // we expect the indextargets + one additional Release file - ExpectedAdditionalItems = IndexTargets->size() + 1; QueueURI(Desc); } /*}}}*/ pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/ { - // if the file was never queued undo file-changes done in the constructor - if (QueueCounter == 1 && Status == StatIdle && FileSize == 0 && Complete == false && - LastGoodSig.empty() == false) - { - string const Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI); - if (RealFileExists(Final) == false && RealFileExists(LastGoodSig) == true) - Rename(LastGoodSig, Final); - } - } /*}}}*/ // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/ @@ -1348,8 +1451,11 @@ pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/ /* The only header we use is the last-modified header. */ string pkgAcqMetaSig::Custom600Headers() const { + string FinalFile = _config->FindDir("Dir::State::lists"); + FinalFile += URItoFileName(RealURI); + struct stat Buf; - if (stat(LastGoodSig.c_str(),&Buf) != 0) + if (stat(FinalFile.c_str(),&Buf) != 0) return "\nIndex-File: true"; return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime); @@ -1377,21 +1483,40 @@ void pkgAcqMetaSig::Done(string Message,unsigned long long Size, HashStringList return; } - Complete = true; + if(StringToBool(LookupTag(Message,"IMS-Hit"),false) == true) + IMSHit = true; - // at this point pkgAcqMetaIndex takes over - ExpectedAdditionalItems = 0; + // adjust paths if its a ims-hit + if(IMSHit) + { + string FinalFile = _config->FindDir("Dir::State::lists"); + FinalFile += URItoFileName(RealURI); + + DestFile = PartialFile = FinalFile; + } - // put the last known good file back on i-m-s hit (it will - // be re-verified again) - // Else do nothing, we have the new file in DestFile then - if(StringToBool(LookupTag(Message,"IMS-Hit"),false) == true) - Rename(LastGoodSig, DestFile); + // queue for verify + if(AuthPass == false) + { + AuthPass = true; + Desc.URI = "gpgv:" + DestFile; + DestFile = MetaIndexFile; + QueueURI(Desc); + return; + } + + // queue to copy the file in place if it was not a ims hit, on ims + // hit the file is already at the right place + if(IMSHit == false) + { + PartialFile = _config->FindDir("Dir::State::lists") + "partial/"; + PartialFile += URItoFileName(RealURI); + + DestFile = _config->FindDir("Dir::State::lists"); + DestFile += URItoFileName(RealURI); + } - // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved - new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc, - MetaIndexShortDesc, DestFile, IndexTargets, - MetaIndexParser); + Complete = true; } /*}}}*/ @@ -1399,29 +1524,21 @@ void pkgAcqMetaSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf)/*{{{*/ { string Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI); - // at this point pkgAcqMetaIndex takes over - ExpectedAdditionalItems = 0; + // this ensures that any file in the lists/ dir is removed by the + // transaction + DestFile = _config->FindDir("Dir::State::lists") + "partial/"; + DestFile += URItoFileName(RealURI); + PartialFile = ""; - // if we get a network error we fail gracefully - if(Status == StatTransientNetworkError) + // FIXME: duplicated code from pkgAcqMetaIndex + if (AuthPass == true) { - Item::Failed(Message,Cnf); - // move the sigfile back on transient network failures - if(FileExists(LastGoodSig)) - Rename(LastGoodSig,Final); - - // set the status back to , Item::Failed likes to reset it - Status = pkgAcquire::Item::StatTransientNetworkError; - return; + bool Stop = GenerateAuthWarning(RealURI, Message); + if(Stop) + return; } - // Delete any existing sigfile when the acquire failed - unlink(Final.c_str()); - - // queue a pkgAcqMetaIndex with no sigfile - new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc, - "", IndexTargets, MetaIndexParser); - + // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor if (Cnf->LocalOnly == true || StringToBool(LookupTag(Message,"Transient-Failure"),false) == false) { @@ -1431,33 +1548,46 @@ void pkgAcqMetaSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf)/*{{{*/ Dequeue(); return; } - Item::Failed(Message,Cnf); } /*}}}*/ pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire *Owner, /*{{{*/ + unsigned long TransactionID, string URI,string URIDesc,string ShortDesc, - string SigFile, + string MetaIndexSigURI,string MetaIndexSigURIDesc, string MetaIndexSigShortDesc, const vector* IndexTargets, indexRecords* MetaIndexParser) : - Item(Owner, HashStringList()), RealURI(URI), SigFile(SigFile), IndexTargets(IndexTargets), - MetaIndexParser(MetaIndexParser), AuthPass(false), IMSHit(false) + pkgAcqMetaSigBase(Owner, HashStringList(), TransactionID), RealURI(URI), IndexTargets(IndexTargets), + MetaIndexParser(MetaIndexParser), AuthPass(false), IMSHit(false), + MetaIndexSigURI(MetaIndexSigURI), MetaIndexSigURIDesc(MetaIndexSigURIDesc), + MetaIndexSigShortDesc(MetaIndexSigShortDesc) +{ + if(TransactionID == 0) + this->TransactionID = (unsigned long)this; + + if(_config->FindB("Debug::Acquire::Transaction", false) == true) + std::clog << "New pkgAcqMetaIndex with TransactionID " + << TransactionID << std::endl; + + Init(URIDesc, ShortDesc); +} + /*}}}*/ +// pkgAcqMetaIndex::Init - Delayed constructor /*{{{*/ +void pkgAcqMetaIndex::Init(std::string URIDesc, std::string ShortDesc) { DestFile = _config->FindDir("Dir::State::lists") + "partial/"; - DestFile += URItoFileName(URI); + DestFile += URItoFileName(RealURI); // Create the item Desc.Description = URIDesc; Desc.Owner = this; Desc.ShortDesc = ShortDesc; - Desc.URI = URI; + Desc.URI = RealURI; // we expect more item ExpectedAdditionalItems = IndexTargets->size(); - QueueURI(Desc); } - /*}}}*/ // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/ // --------------------------------------------------------------------- /* The only header we use is the last-modified header. */ @@ -1498,25 +1628,12 @@ void pkgAcqMetaIndex::Done(string Message,unsigned long long Size,HashStringList if (SigFile == "") { - // There was no signature file, so we are finished. Download - // the indexes and do only hashsum verification if possible + // load indexes, the signature will downloaded afterwards MetaIndexParser->Load(DestFile); - QueueIndexes(false); + QueueIndexes(true); } else { - // FIXME: move this into pkgAcqMetaClearSig::Done on the next - // ABI break - - // if we expect a ClearTextSignature (InRelase), ensure that - // this is what we get and if not fail to queue a - // Release/Release.gpg, see #346386 - if (SigFile == DestFile && !StartsWithGPGClearTextSignature(DestFile)) - { - Failed(Message, Cfg); - return; - } - // There was a signature file, so pass it to gpgv for // verification if (_config->FindB("Debug::pkgAcquire::Auth", false)) @@ -1536,8 +1653,8 @@ void pkgAcqMetaIndex::Done(string Message,unsigned long long Size,HashStringList FinalFile += URItoFileName(RealURI); if (SigFile == DestFile) SigFile = FinalFile; - Rename(DestFile,FinalFile); - chmod(FinalFile.c_str(),0644); + // queue for copy in place + PartialFile = DestFile; DestFile = FinalFile; } } @@ -1572,14 +1689,24 @@ void pkgAcqMetaIndex::RetrievalDone(string Message) /*{{{*/ if (SigFile == DestFile) { SigFile = FinalFile; +#if 0 // constructor of pkgAcqMetaClearSig moved it out of the way, // now move it back in on IMS hit for the 'old' file string const OldClearSig = DestFile + ".reverify"; if (RealFileExists(OldClearSig) == true) Rename(OldClearSig, FinalFile); +#endif } DestFile = FinalFile; } + + // queue a signature + if(SigFile != DestFile) + new pkgAcqMetaSig(Owner, TransactionID, + MetaIndexSigURI, MetaIndexSigURIDesc, + MetaIndexSigShortDesc, DestFile, IndexTargets, + MetaIndexParser); + Complete = true; } /*}}}*/ @@ -1609,6 +1736,7 @@ void pkgAcqMetaIndex::AuthDone(string Message) /*{{{*/ // Download further indexes with verification QueueIndexes(true); +#if 0 // is it a clearsigned MetaIndex file? if (DestFile == SigFile) return; @@ -1618,20 +1746,11 @@ void pkgAcqMetaIndex::AuthDone(string Message) /*{{{*/ URItoFileName(RealURI) + ".gpg"; Rename(SigFile,VerifiedSigFile); chmod(VerifiedSigFile.c_str(),0644); +#endif } /*}}}*/ void pkgAcqMetaIndex::QueueIndexes(bool verify) /*{{{*/ { -#if 0 - /* Reject invalid, existing Release files (LP: #346386) (Closes: #627642) - * FIXME: Disabled; it breaks unsigned repositories without hashes */ - if (!verify && FileExists(DestFile) && !MetaIndexParser->Load(DestFile)) - { - Status = StatError; - ErrorText = MetaIndexParser->ErrorText; - return; - } -#endif bool transInRelease = false; { std::vector const keys = MetaIndexParser->MetaKeys(); @@ -1694,15 +1813,16 @@ void pkgAcqMetaIndex::QueueIndexes(bool verify) /*{{{*/ if ((*Target)->IsOptional() == true) { if ((*Target)->IsSubIndex() == true) - new pkgAcqSubIndex(Owner, (*Target)->URI, (*Target)->Description, + new pkgAcqSubIndex(Owner, TransactionID, + (*Target)->URI, (*Target)->Description, (*Target)->ShortDesc, ExpectedIndexHashes); else if (transInRelease == false || Record != NULL || compressedAvailable == true) { if (_config->FindB("Acquire::PDiffs",true) == true && transInRelease == true && MetaIndexParser->Exists((*Target)->MetaKey + ".diff/Index") == true) - new pkgAcqDiffIndex(Owner, *Target, ExpectedIndexHashes, MetaIndexParser); + new pkgAcqDiffIndex(Owner, TransactionID, *Target, ExpectedIndexHashes, MetaIndexParser); else - new pkgAcqIndexTrans(Owner, *Target, ExpectedIndexHashes, MetaIndexParser); + new pkgAcqIndexTrans(Owner, TransactionID, *Target, ExpectedIndexHashes, MetaIndexParser); } continue; } @@ -1713,9 +1833,9 @@ void pkgAcqMetaIndex::QueueIndexes(bool verify) /*{{{*/ instead, but passing the required info to it is to much hassle */ if(_config->FindB("Acquire::PDiffs",true) == true && (verify == false || MetaIndexParser->Exists((*Target)->MetaKey + ".diff/Index") == true)) - new pkgAcqDiffIndex(Owner, *Target, ExpectedIndexHashes, MetaIndexParser); + new pkgAcqDiffIndex(Owner, TransactionID, *Target, ExpectedIndexHashes, MetaIndexParser); else - new pkgAcqIndex(Owner, *Target, ExpectedIndexHashes, MetaIndexParser); + new pkgAcqIndex(Owner, TransactionID, *Target, ExpectedIndexHashes, MetaIndexParser); } } /*}}}*/ @@ -1799,44 +1919,16 @@ bool pkgAcqMetaIndex::VerifyVendor(string Message) /*{{{*/ // pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/ // --------------------------------------------------------------------- /* */ -void pkgAcqMetaIndex::Failed(string Message,pkgAcquire::MethodConfig * /*Cnf*/) +void pkgAcqMetaIndex::Failed(string Message, + pkgAcquire::MethodConfig * /*Cnf*/) { + string Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI); + if (AuthPass == true) { - // gpgv method failed, if we have a good signature - string LastGoodSigFile = _config->FindDir("Dir::State::lists").append("partial/").append(URItoFileName(RealURI)); - if (DestFile != SigFile) - LastGoodSigFile.append(".gpg"); - LastGoodSigFile.append(".reverify"); - - if(FileExists(LastGoodSigFile)) - { - string VerifiedSigFile = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI); - if (DestFile != SigFile) - VerifiedSigFile.append(".gpg"); - Rename(LastGoodSigFile, VerifiedSigFile); - Status = StatTransientNetworkError; - _error->Warning(_("An error occurred during the signature " - "verification. The repository is not updated " - "and the previous index files will be used. " - "GPG error: %s: %s\n"), - Desc.Description.c_str(), - LookupTag(Message,"Message").c_str()); - RunScripts("APT::Update::Auth-Failure"); - return; - } else if (LookupTag(Message,"Message").find("NODATA") != string::npos) { - /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */ - _error->Error(_("GPG error: %s: %s"), - Desc.Description.c_str(), - LookupTag(Message,"Message").c_str()); - return; - } else { - _error->Warning(_("GPG error: %s: %s"), - Desc.Description.c_str(), - LookupTag(Message,"Message").c_str()); - } - // gpgv method failed - ReportMirrorFailure("GPGFailure"); + bool Stop = GenerateAuthWarning(RealURI, Message); + if(Stop) + return; } /* Always move the meta index, even if gpgv failed. This ensures @@ -1853,9 +1945,9 @@ void pkgAcqMetaIndex::Failed(string Message,pkgAcquire::MethodConfig * /*Cnf*/) "Release"); SigFile = FinalFile; } - Rename(DestFile,FinalFile); - chmod(FinalFile.c_str(),0644); + // Done, queue for rename on transaction finished + PartialFile = DestFile; DestFile = FinalFile; } @@ -1864,22 +1956,33 @@ void pkgAcqMetaIndex::Failed(string Message,pkgAcquire::MethodConfig * /*Cnf*/) QueueIndexes(false); } /*}}}*/ + +void pkgAcqMetaIndex::Finished() +{ + if(_config->FindB("Debug::Acquire::Transaction", false) == true) + std::clog << "Finished: " << DestFile <TransactionHasError(TransactionID) == false && + TransactionID > 0) + Owner->CommitTransaction(TransactionID); +} + + pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire *Owner, /*{{{*/ string const &URI, string const &URIDesc, string const &ShortDesc, string const &MetaIndexURI, string const &MetaIndexURIDesc, string const &MetaIndexShortDesc, string const &MetaSigURI, string const &MetaSigURIDesc, string const &MetaSigShortDesc, const vector* IndexTargets, indexRecords* MetaIndexParser) : - pkgAcqMetaIndex(Owner, URI, URIDesc, ShortDesc, "", IndexTargets, MetaIndexParser), - MetaIndexURI(MetaIndexURI), MetaIndexURIDesc(MetaIndexURIDesc), MetaIndexShortDesc(MetaIndexShortDesc), - MetaSigURI(MetaSigURI), MetaSigURIDesc(MetaSigURIDesc), MetaSigShortDesc(MetaSigShortDesc) + pkgAcqMetaIndex(Owner, (unsigned long)this, URI, URIDesc, ShortDesc, MetaSigURI, MetaSigURIDesc,MetaSigShortDesc, IndexTargets, MetaIndexParser), + MetaIndexURI(MetaIndexURI), MetaIndexURIDesc(MetaIndexURIDesc), MetaIndexShortDesc(MetaIndexShortDesc), + MetaSigURI(MetaSigURI), MetaSigURIDesc(MetaSigURIDesc), MetaSigShortDesc(MetaSigShortDesc) { SigFile = DestFile; // index targets + (worst case:) Release/Release.gpg ExpectedAdditionalItems = IndexTargets->size() + 2; - +#if 0 // keep the old InRelease around in case of transistent network errors string const Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI); if (RealFileExists(Final) == true) @@ -1887,10 +1990,12 @@ pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire *Owner, /*{{{*/ string const LastGoodSig = DestFile + ".reverify"; Rename(Final,LastGoodSig); } +#endif } /*}}}*/ pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/ { +#if 0 // if the file was never queued undo file-changes done in the constructor if (QueueCounter == 1 && Status == StatIdle && FileSize == 0 && Complete == false) { @@ -1899,6 +2004,7 @@ pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/ if (RealFileExists(Final) == false && RealFileExists(LastGoodSig) == true) Rename(LastGoodSig, Final); } +#endif } /*}}}*/ // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/ @@ -1912,7 +2018,6 @@ string pkgAcqMetaClearSig::Custom600Headers() const struct stat Buf; if (stat(Final.c_str(),&Buf) != 0) { - Final = DestFile + ".reverify"; if (stat(Final.c_str(),&Buf) != 0) return "\nIndex-File: true\nFail-Ignore: true\n"; } @@ -1920,6 +2025,24 @@ string pkgAcqMetaClearSig::Custom600Headers() const return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime); } /*}}}*/ +// pkgAcqMetaClearSig::Done - We got a file /*{{{*/ +// --------------------------------------------------------------------- +void pkgAcqMetaClearSig::Done(std::string Message,unsigned long long Size, + HashStringList const &Hashes, + pkgAcquire::MethodConfig *Cnf) +{ + // if we expect a ClearTextSignature (InRelase), ensure that + // this is what we get and if not fail to queue a + // Release/Release.gpg, see #346386 + if (FileExists(DestFile) && !StartsWithGPGClearTextSignature(DestFile)) + { + pkgAcquire::Item::Failed(Message, Cnf); + ErrorText = _("Does not start with a cleartext signature"); + return; + } + pkgAcqMetaIndex::Done(Message, Size, Hashes, Cnf); +} + /*}}}*/ void pkgAcqMetaClearSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /*{{{*/ { // we failed, we will not get additional items from this method @@ -1927,16 +2050,17 @@ void pkgAcqMetaClearSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /* if (AuthPass == false) { - // Remove the 'old' InRelease file if we try Release.gpg now as otherwise - // the file will stay around and gives a false-auth impression (CVE-2012-0214) + // Queue the 'old' InRelease file for removal if we try Release.gpg + // as otherwise the file will stay around and gives a false-auth + // impression (CVE-2012-0214) string FinalFile = _config->FindDir("Dir::State::lists"); FinalFile.append(URItoFileName(RealURI)); - if (FileExists(FinalFile)) - unlink(FinalFile.c_str()); + PartialFile = ""; + DestFile = FinalFile; - new pkgAcqMetaSig(Owner, - MetaSigURI, MetaSigURIDesc, MetaSigShortDesc, + new pkgAcqMetaIndex(Owner, TransactionID, MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc, + MetaSigURI, MetaSigURIDesc, MetaSigShortDesc, IndexTargets, MetaIndexParser); if (Cnf->LocalOnly == true || StringToBool(LookupTag(Message, "Transient-Failure"), false) == false)