X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/c36db2b56a08bb7542d0c1be900ee90808efa770..1d970e6ce97385ed719a1ca169ec5cc7bfb82fea:/apt-pkg/acquire-item.cc?ds=inline diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc index d6b00f9b7..3c66369cf 100644 --- a/apt-pkg/acquire-item.cc +++ b/apt-pkg/acquire-item.cc @@ -527,6 +527,21 @@ void pkgAcqDiffIndex::Done(string Message,unsigned long long Size,HashStringList Item::Done(Message, Size, Hashes, Cnf); + // verify the index target + if(Target && Target->MetaKey != "" && MetaIndexParser && Hashes.usable()) + { + std::string IndexMetaKey = Target->MetaKey + ".diff/Index"; + indexRecords::checkSum *Record = MetaIndexParser->Lookup(IndexMetaKey); + if(Record && Record->Hashes.usable() && Hashes != Record->Hashes) + { + RenameOnError(HashSumMismatch); + printHashSumComparision(RealURI, Record->Hashes, Hashes); + Failed(Message, Cnf); + return; + } + + } + string FinalFile; FinalFile = _config->FindDir("Dir::State::lists")+URItoFileName(RealURI); @@ -627,7 +642,9 @@ void pkgAcqIndexDiffs::Finish(bool allDone) // this happens if we have a up-to-date indexfile if(!FileExists(PartialFile)) PartialFile = DestFile; - + + TransactionManager->TransactionStageCopy(this, PartialFile, DestFile); + // this is for the "real" finish Complete = true; Status = StatDone; @@ -713,6 +730,8 @@ void pkgAcqIndexDiffs::Done(string Message,unsigned long long Size, HashStringLi Item::Done(Message, Size, Hashes, Cnf); + // FIXME: verify this download too before feeding it to rred + string FinalFile; FinalFile = _config->FindDir("Dir::State::lists")+"partial/"+URItoFileName(RealURI); @@ -834,6 +853,8 @@ void pkgAcqIndexMergeDiffs::Done(string Message,unsigned long long Size,HashStri Item::Done(Message,Size,Hashes,Cnf); + // FIXME: verify download before feeding it to rred + string const FinalFile = _config->FindDir("Dir::State::lists") + "partial/" + URItoFileName(RealURI); if (State == StateFetchDiff) @@ -892,8 +913,7 @@ void pkgAcqIndexMergeDiffs::Done(string Message,unsigned long long Size,HashStri << DestFile << " -> " << FinalFile << std::endl; // queue for copy by the transaction manager - PartialFile = DestFile; - DestFile = FinalFile; + TransactionManager->TransactionStageCopy(this, DestFile, FinalFile); // ensure the ed's are gone regardless of list-cleanup for (std::vector::const_iterator I = allPatches->begin(); @@ -913,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.usable()) + { + 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 @@ -920,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); @@ -938,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); @@ -954,34 +995,38 @@ pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner, void pkgAcqIndex::AutoSelectCompression() { std::vector types = APT::Configuration::getCompressionTypes(); - CompressionExtension = ""; + CompressionExtensions = ""; if (ExpectedHashes.usable()) { - for (std::vector::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::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::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") + CurrentCompressionExtension = CompressionExtensions.substr(0, CompressionExtensions.find(' ')); + if (CurrentCompressionExtension == "uncompressed") { Desc.URI = URI; if(Target) @@ -989,10 +1034,10 @@ void pkgAcqIndex::Init(string const &URI, string const &URIDesc, } else { - Desc.URI = URI + '.' + comprExt; - DestFile = DestFile + '.' + comprExt; + Desc.URI = URI + '.' + CurrentCompressionExtension; + DestFile = DestFile + '.' + CurrentCompressionExtension; if(Target) - MetaKey = string(Target->MetaKey) + '.' + comprExt; + MetaKey = string(Target->MetaKey) + '.' + CurrentCompressionExtension; } // load the filesize @@ -1064,19 +1109,18 @@ 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) { - string s = _config->FindDir("Dir::State::lists") + "partial/"; - s.append(URItoFileName(RealURI)); - unlink(s.c_str()); + if (Stage == STAGE_DECOMPRESS_AND_VERIFY) + { + unlink(EraseFileName.c_str()); } Item::Failed(Message,Cnf); @@ -1090,11 +1134,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 += '.' + CurrentCompressionExtension; return FinalFile; } /*}}}*/ @@ -1103,8 +1146,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/"; @@ -1112,15 +1153,44 @@ void pkgAcqIndex::ReverifyAfterIMS() // adjust DestFile if its compressed on disk if (_config->FindB("Acquire::GzipIndexes",false) == true) - DestFile += compExt; + DestFile += '.' + CurrentCompressionExtension; // 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); } /*}}}*/ + +// 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 + // has a valid hash and we never do GET based probing + // FIXME2: this also leaks debian-isms into the code and should go therefore + + /* Always validate the index file for correctness (all indexes must + * have a Package field) (LP: #346386) (Closes: #627642) + */ + 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) + { + pkgTagSection sec; + pkgTagFile tag(&fd); + + // all our current indexes have a field 'Package' in each section + if (_error->PendingError() == true || + tag.Step(sec) == false || + sec.Exists("Package") == false) + return false; + } + return true; +} + /*}}}*/ // AcqIndex::Done - Finished a fetch /*{{{*/ // --------------------------------------------------------------------- /* This goes through a number of states.. On the initial fetch the @@ -1128,84 +1198,45 @@ void pkgAcqIndex::ReverifyAfterIMS() 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; - } - - // FIXME: this can go away once we only ever download stuff that - // has a valid hash and we never do GET based probing - // - /* Always verify the index file for correctness (all indexes must - * have a Package field) (LP: #346386) (Closes: #627642) - */ - 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); - - // all our current indexes have a field 'Package' in each section - if (_error->PendingError() == true || tag.Step(sec) == false || sec.Exists("Package") == false) - { - 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); - - // Remove the compressed version. - if (Erase == true) - unlink(CompressedFile.c_str()); - - // Done, queue for rename on transaction finished - PartialFile = DestFile; - 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; @@ -1229,43 +1260,35 @@ 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; + else + EraseFileName = FileName; - // 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/ + EraseFileName = ""; + 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"); - DestFile += URItoFileName(RealURI) + '.' + compExt; - - Decompression = true; + DestFile = _config->FindDir("Dir::State::lists") + "partial/"; + DestFile += URItoFileName(RealURI) + '.' + CurrentCompressionExtension; + EraseFileName = ""; + Stage = STAGE_DECOMPRESS_AND_VERIFY; Desc.URI = "copy:" + FileName; QueueURI(Desc); @@ -1273,16 +1296,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(CurrentCompressionExtension == "uncompressed") decompProg = "copy"; - else { - _error->Error("Unsupported extension: %s", compExt.c_str()); + else + decompProg = _config->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension),""); + if(decompProg.empty() == true) + { + _error->Error("Unsupported extension: %s", CurrentCompressionExtension.c_str()); return; } - Decompression = true; + // queue uri for the next stage + Stage = STAGE_DECOMPRESS_AND_VERIFY; DestFile += ".decomp"; Desc.URI = decompProg + ":" + FileName; QueueURI(Desc); @@ -1297,6 +1323,37 @@ 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 + unlink(EraseFileName.c_str()); + + // Done, queue for rename on transaction finished + TransactionManager->TransactionStageCopy(this, DestFile, GetFinalFilename()); + + return; +} + /*}}}*/ /*}}}*/ // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/ // --------------------------------------------------------------------- @@ -1337,10 +1394,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; @@ -1360,12 +1417,17 @@ void pkgAcqIndexTrans::Failed(string Message,pkgAcquire::MethodConfig *Cnf) Item::Failed(Message,Cnf); } /*}}}*/ - +// AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/ +// --------------------------------------------------------------------- +/* */ void pkgAcqMetaBase::Add(Item *I) { Transaction.push_back(I); } - + /*}}}*/ +// AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/ +// --------------------------------------------------------------------- +/* */ void pkgAcqMetaBase::AbortTransaction() { if(_config->FindB("Debug::Acquire::Transaction", false) == true) @@ -1380,9 +1442,19 @@ void pkgAcqMetaBase::AbortTransaction() // the transaction will abort, so stop anything that is idle if ((*I)->Status == pkgAcquire::Item::StatIdle) (*I)->Status = pkgAcquire::Item::StatDone; + + // kill files in partial + string PartialFile = _config->FindDir("Dir::State::lists"); + PartialFile += "partial/"; + PartialFile += flNotDir((*I)->DestFile); + if(FileExists(PartialFile)) + Rename(PartialFile, PartialFile + ".FAILED"); } } /*}}}*/ +// AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/ +// --------------------------------------------------------------------- +/* */ bool pkgAcqMetaBase::TransactionHasError() { for (pkgAcquire::ItemIterator I = Transaction.begin(); @@ -1393,7 +1465,10 @@ bool pkgAcqMetaBase::TransactionHasError() return false; } -// Acquire::CommitTransaction - Commit a transaction /*{{{*/ + /*}}}*/ +// AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/ +// --------------------------------------------------------------------- +/* */ void pkgAcqMetaBase::CommitTransaction() { if(_config->FindB("Debug::Acquire::Transaction", false) == true) @@ -1427,8 +1502,32 @@ void pkgAcqMetaBase::CommitTransaction() (*I)->TransactionManager = 0; } } - + /*}}}*/ +// AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void pkgAcqMetaBase::TransactionStageCopy(Item *I, + const std::string &From, + const std::string &To) +{ + I->PartialFile = From; + I->DestFile = To; +} + /*}}}*/ +// AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void pkgAcqMetaBase::TransactionStageRemoval(Item *I, + const std::string &FinalFile) +{ + I->PartialFile = ""; + I->DestFile = FinalFile; +} + /*}}}*/ /*{{{*/ +// AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/ +// --------------------------------------------------------------------- +/* */ bool pkgAcqMetaBase::GenerateAuthWarning(const std::string &RealURI, const std::string &Message) { @@ -1462,21 +1561,22 @@ bool pkgAcqMetaBase::GenerateAuthWarning(const std::string &RealURI, return false; } /*}}}*/ - - -pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner, /*{{{*/ +// AcqMetaSig::AcqMetaSig - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner, pkgAcqMetaBase *TransactionManager, string URI,string URIDesc,string ShortDesc, string MetaIndexFile, const vector* IndexTargets, indexRecords* MetaIndexParser) : - pkgAcqMetaBase(Owner, HashStringList(), TransactionManager), RealURI(URI), - MetaIndexParser(MetaIndexParser), MetaIndexFile(MetaIndexFile), - URIDesc(URIDesc), ShortDesc(ShortDesc), - IndexTargets(IndexTargets), AuthPass(false), IMSHit(false) + pkgAcqMetaBase(Owner, IndexTargets, MetaIndexParser, + HashStringList(), TransactionManager), + RealURI(URI), MetaIndexFile(MetaIndexFile), URIDesc(URIDesc), + ShortDesc(ShortDesc) { DestFile = _config->FindDir("Dir::State::lists") + "partial/"; - DestFile += URItoFileName(URI); + DestFile += URItoFileName(RealURI); // remove any partial downloaded sig-file in partial/. // it may confuse proxies and is too small to warrant a @@ -1515,118 +1615,134 @@ string pkgAcqMetaSig::Custom600Headers() const return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime); } - -void pkgAcqMetaSig::Done(string Message,unsigned long long Size, HashStringList const &Hashes, + /*}}}*/ +// pkgAcqMetaSig::Done - The signature was downloaded/verified /*{{{*/ +// --------------------------------------------------------------------- +/* The only header we use is the last-modified header. */ +void pkgAcqMetaSig::Done(string Message,unsigned long long Size, + HashStringList const &Hashes, pkgAcquire::MethodConfig *Cfg) { Item::Done(Message, Size, Hashes, Cfg); - string FileName = LookupTag(Message,"Filename"); - if (FileName.empty() == true) + if(AuthPass == false) { - Status = StatError; - ErrorText = "Method gave a blank filename"; - return; - } + // queue for verify, note that we change DestFile here to point to + // the file we want to verify (needed to make gpgv work) - if (FileName != DestFile) - { - // We have to copy it into place - Local = true; - Desc.URI = "copy:" + FileName; - QueueURI(Desc); - return; - } + string FileName = LookupTag(Message,"Filename"); + if (FileName.empty() == true) + { + Status = StatError; + ErrorText = "Method gave a blank filename"; + return; + } - if(StringToBool(LookupTag(Message,"IMS-Hit"),false) == true) - IMSHit = true; + if (FileName != DestFile) + { + // We have to copy it into place + Local = true; + Desc.URI = "copy:" + FileName; + QueueURI(Desc); + return; + } - // adjust paths if its a ims-hit - if(IMSHit) - { - string FinalFile = _config->FindDir("Dir::State::lists"); - FinalFile += URItoFileName(RealURI); - - DestFile = PartialFile = FinalFile; - } + if(StringToBool(LookupTag(Message,"IMS-Hit"),false) == true) + { + IMSHit = true; + // adjust DestFile on i-m-s hit to the one we already have on disk + DestFile = _config->FindDir("Dir::State::lists"); + DestFile += URItoFileName(RealURI); + } + + // this is the file we verify from + MetaIndexFileSignature = DestFile; - // queue for verify - if(AuthPass == false) - { AuthPass = true; - Desc.URI = "gpgv:" + DestFile; + Desc.URI = "gpgv:" + MetaIndexFileSignature; DestFile = MetaIndexFile; QueueURI(Desc); + ActiveSubprocess = "gpgv"; 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) + else { - PartialFile = _config->FindDir("Dir::State::lists") + "partial/"; - PartialFile += URItoFileName(RealURI); - - DestFile = _config->FindDir("Dir::State::lists"); - DestFile += URItoFileName(RealURI); - } + // verify was successful - // we parse the MetaIndexFile here because at this point we can - // trust the data - if(AuthPass == true) - { + // we parse the MetaIndexFile here (and not right after getting + // the pkgAcqMetaIndex) because at this point we can trust the data + // // load indexes and queue further downloads MetaIndexParser->Load(MetaIndexFile); - ((pkgAcqMetaIndex*)TransactionManager)->QueueIndexes(true); - } + QueueIndexes(true); - Complete = true; + // DestFile points to the the MetaIndeFile at this point, make it + // point back to the Release.gpg file + std::string FinalFile = _config->FindDir("Dir::State::lists"); + FinalFile += URItoFileName(RealURI); + TransactionManager->TransactionStageCopy(this, MetaIndexFileSignature, FinalFile); + + Complete = true; + } } /*}}}*/ void pkgAcqMetaSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf)/*{{{*/ { string Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI); - + + // FIXME: duplicated code from pkgAcqMetaIndex + if (AuthPass == true) + { + bool Stop = GenerateAuthWarning(RealURI, Message); + if(Stop) + return; + } + // FIXME: meh, this is not really elegant string InReleaseURI = RealURI.replace(RealURI.rfind("Release.gpg"), 12, "InRelease"); string FinalInRelease = _config->FindDir("Dir::State::lists") + URItoFileName(InReleaseURI); - if(RealFileExists(Final) || RealFileExists(FinalInRelease)) + if (RealFileExists(Final) || RealFileExists(FinalInRelease)) { - _error->Error("The repository '%s' is no longer signed.", - URIDesc.c_str()); - Rename(MetaIndexFile, MetaIndexFile+".FAILED"); - Status = pkgAcquire::Item::StatError; - TransactionManager->AbortTransaction(); - return; + std::string downgrade_msg; + strprintf(downgrade_msg, _("The repository '%s' is no longer signed."), + URIDesc.c_str()); + if(_config->FindB("Acquire::AllowDowngradeToInsecureRepositories")) + { + // meh, the users wants to take risks (we still mark the packages + // from this repository as unauthenticated) + _error->Warning("%s", downgrade_msg.c_str()); + _error->Warning(_("This is normally not allowed, but the option " + "Acquire::AllowDowngradeToInsecureRepositories was " + "given to override it.")); + + } else { + _error->Error("%s", downgrade_msg.c_str()); + Rename(MetaIndexFile, MetaIndexFile+".FAILED"); + Status = pkgAcquire::Item::StatError; + TransactionManager->AbortTransaction(); + return; + } } // 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 = ""; - - // FIXME: duplicated code from pkgAcqMetaIndex - if (AuthPass == true) - { - bool Stop = GenerateAuthWarning(RealURI, Message); - if(Stop) - return; - } + TransactionManager->TransactionStageRemoval(this, DestFile); // only allow going further if the users explicitely wants it - if(_config->FindB("APT::Get::AllowUnauthenticated", false) == true) + if(_config->FindB("Acquire::AllowInsecureRepositories") == true) { // we parse the indexes here because at this point the user wanted // a repository that may potentially harm him MetaIndexParser->Load(MetaIndexFile); - ((pkgAcqMetaIndex*)TransactionManager)->QueueIndexes(true); + QueueIndexes(true); } else { - _error->Warning("Use --allow-unauthenticated to force the update"); + _error->Warning("Use --allow-insecure-repositories to force the update"); } // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor @@ -1648,9 +1764,9 @@ pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire *Owner, /*{{{*/ string MetaIndexSigURI,string MetaIndexSigURIDesc, string MetaIndexSigShortDesc, const vector* IndexTargets, indexRecords* MetaIndexParser) : - pkgAcqMetaBase(Owner, HashStringList(), TransactionManager), RealURI(URI), IndexTargets(IndexTargets), - URIDesc(URIDesc), ShortDesc(ShortDesc), - MetaIndexParser(MetaIndexParser), AuthPass(false), IMSHit(false), + pkgAcqMetaBase(Owner, IndexTargets, MetaIndexParser, HashStringList(), + TransactionManager), + RealURI(URI), URIDesc(URIDesc), ShortDesc(ShortDesc), MetaIndexSigURI(MetaIndexSigURI), MetaIndexSigURIDesc(MetaIndexSigURIDesc), MetaIndexSigShortDesc(MetaIndexSigShortDesc) { @@ -1751,9 +1867,9 @@ void pkgAcqMetaIndex::Done(string Message,unsigned long long Size,HashStringList FinalFile += URItoFileName(RealURI); if (SigFile == DestFile) SigFile = FinalFile; + // queue for copy in place - PartialFile = DestFile; - DestFile = FinalFile; + TransactionManager->TransactionStageCopy(this, DestFile, FinalFile); } } /*}}}*/ @@ -1881,7 +1997,7 @@ void pkgAcqMetaIndex::AuthDone(string Message) /*{{{*/ #endif } /*}}}*/ -void pkgAcqMetaIndex::QueueIndexes(bool verify) /*{{{*/ +void pkgAcqMetaBase::QueueIndexes(bool verify) /*{{{*/ { bool transInRelease = false; { @@ -2059,27 +2175,6 @@ void pkgAcqMetaIndex::Failed(string Message, return; } - /* Always move the meta index, even if gpgv failed. This ensures - * that PackageFile objects are correctly filled in */ - if (FileExists(DestFile)) - { - string FinalFile = _config->FindDir("Dir::State::lists"); - FinalFile += URItoFileName(RealURI); - /* InRelease files become Release files, otherwise - * they would be considered as trusted later on */ - if (SigFile == DestFile) { - RealURI = RealURI.replace(RealURI.rfind("InRelease"), 9, - "Release"); - FinalFile = FinalFile.replace(FinalFile.rfind("InRelease"), 9, - "Release"); - SigFile = FinalFile; - } - - // Done, queue for rename on transaction finished - PartialFile = DestFile; - DestFile = FinalFile; - } - _error->Warning(_("The data from '%s' is not signed. Packages " "from that repository can not be authenticated."), URIDesc.c_str()); @@ -2087,13 +2182,37 @@ void pkgAcqMetaIndex::Failed(string Message, // No Release file was present, or verification failed, so fall // back to queueing Packages files without verification // only allow going further if the users explicitely wants it - if(_config->FindB("APT::Get::AllowUnauthenticated", false) == true) + if(_config->FindB("Acquire::AllowInsecureRepositories") == true) { + /* Always move the meta index, even if gpgv failed. This ensures + * that PackageFile objects are correctly filled in */ + if (FileExists(DestFile)) + { + string FinalFile = _config->FindDir("Dir::State::lists"); + FinalFile += URItoFileName(RealURI); + /* InRelease files become Release files, otherwise + * they would be considered as trusted later on */ + if (SigFile == DestFile) { + RealURI = RealURI.replace(RealURI.rfind("InRelease"), 9, + "Release"); + FinalFile = FinalFile.replace(FinalFile.rfind("InRelease"), 9, + "Release"); + SigFile = FinalFile; + } + + // Done, queue for rename on transaction finished + TransactionManager->TransactionStageCopy(this, DestFile, FinalFile); + } + QueueIndexes(false); } else { // warn if the repository is unsinged - _error->Warning("Use --allow-unauthenticated to force the update"); + _error->Warning("Use --allow-insecure-repositories to force the update"); + TransactionManager->AbortTransaction(); + Status = StatError; + return; } + } /*}}}*/ @@ -2196,8 +2315,7 @@ void pkgAcqMetaClearSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /* // impression (CVE-2012-0214) string FinalFile = _config->FindDir("Dir::State::lists"); FinalFile.append(URItoFileName(RealURI)); - PartialFile = ""; - DestFile = FinalFile; + TransactionManager->TransactionStageRemoval(this, FinalFile); new pkgAcqMetaIndex(Owner, TransactionManager, MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc,