/*}}}*/
// Acquire::Item::Item - Constructor /*{{{*/
+#if __GNUC__ >= 4
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
pkgAcquire::Item::Item(pkgAcquire *Owner,
HashStringList const &ExpectedHashes,
pkgAcqMetaBase *TransactionManager)
if(TransactionManager != NULL)
TransactionManager->Add(this);
}
+#if __GNUC__ >= 4
+ #pragma GCC diagnostic pop
+#endif
/*}}}*/
// Acquire::Item::~Item - Destructor /*{{{*/
// ---------------------------------------------------------------------
Status = StatError;
// do not report as usually its not the mirrors fault, but Portal/Proxy
break;
+ case SignatureError:
+ ErrorText = _("Signature error");
+ Status = StatError;
+ break;
+ case NotClearsigned:
+ ErrorText = _("Does not start with a cleartext signature");
+ Status = StatError;
+ break;
}
return false;
}
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);
// 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;
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);
Local = true;
Desc.URI = "rred:" + FinalFile;
QueueURI(Desc);
+ ActiveSubprocess = "rred";
+#if __GNUC__ >= 4
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
Mode = "rred";
+#if __GNUC__ >= 4
+ #pragma GCC diagnostic pop
+#endif
return;
}
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)
Local = true;
Desc.URI = "rred:" + FinalFile;
QueueURI(Desc);
+ ActiveSubprocess = "rred";
+#if __GNUC__ >= 4
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
Mode = "rred";
+#if __GNUC__ >= 4
+ #pragma GCC diagnostic pop
+#endif
return;
}
// success in download/apply all diffs, clean up
<< 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<pkgAcqIndexMergeDiffs *>::const_iterator I = allPatches->begin();
}
}
/*}}}*/
+
+// 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
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);
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);
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")
+ CurrentCompressionExtension = CompressionExtensions.substr(0, CompressionExtensions.find(' '));
+ if (CurrentCompressionExtension == "uncompressed")
{
Desc.URI = URI;
if(Target)
}
else
{
- Desc.URI = URI + '.' + comprExt;
+ Desc.URI = URI + '.' + CurrentCompressionExtension;
+ DestFile = DestFile + '.' + CurrentCompressionExtension;
if(Target)
- MetaKey = string(Target->MetaKey) + '.' + comprExt;
+ MetaKey = string(Target->MetaKey) + '.' + CurrentCompressionExtension;
}
// load the filesize
/* */
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);
/* */
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) && compExt == "gz")
- FinalFile += ".gz";
+ if (_config->FindB("Acquire::GzipIndexes",false) == true)
+ FinalFile += '.' + CurrentCompressionExtension;
return FinalFile;
}
/*}}}*/
/* */
void pkgAcqIndex::ReverifyAfterIMS()
{
- std::string const compExt = CompressionExtension.substr(0, CompressionExtension.find(' '));
- if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz")
- DestFile += ".gz";
+ // 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/";
+ DestFile += URItoFileName(RealURI);
+
+ // adjust DestFile if its compressed on disk
+ if (_config->FindB("Acquire::GzipIndexes",false) == true)
+ 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
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;
QueueURI(Desc);
+ ActiveSubprocess = "copy";
+#if __GNUC__ >= 4
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
Mode = "copy";
+#if __GNUC__ >= 4
+ #pragma GCC diagnostic pop
+#endif
return;
}
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;
+ // 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;
+
+ // The files timestamp matches, reverify by copy into partial/
+ EraseFileName = "";
ReverifyAfterIMS();
return;
}
- string decompProg;
- // If we enable compressed indexes, queue for hash verification
- if (_config->FindB("Acquire::GzipIndexes",false) && compExt == "gz")
+ // 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) + ".gz";
-
- 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);
}
// 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);
- // FIXME: this points to a c++ string that goes out of scope
- Mode = decompProg.c_str();
+ ActiveSubprocess = decompProg;
+#if __GNUC__ >= 4
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+ Mode = ActiveSubprocess.c_str();
+#if __GNUC__ >= 4
+ #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 /*{{{*/
// ---------------------------------------------------------------------
/* */
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;
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)
std::clog << "AbortTransaction: " << TransactionManager << std::endl;
+ // ensure the toplevel is in error state too
for (std::vector<Item*>::iterator I = Transaction.begin();
I != Transaction.end(); ++I)
{
// 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();
return false;
}
-// Acquire::CommitTransaction - Commit a transaction /*{{{*/
+ /*}}}*/
+// AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
+// ---------------------------------------------------------------------
+/* */
void pkgAcqMetaBase::CommitTransaction()
{
if(_config->FindB("Debug::Acquire::Transaction", false) == true)
(*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)
{
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<IndexTarget*>* IndexTargets,
indexRecords* MetaIndexParser) :
- pkgAcqMetaBase(Owner, HashStringList(), TransactionManager), RealURI(URI),
- MetaIndexParser(MetaIndexParser), MetaIndexFile(MetaIndexFile),
- 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
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
- Complete = 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);
+ QueueIndexes(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);
- // 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)
{
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))
+ {
+ 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);
+ TransactionManager->TransactionStageRemoval(this, DestFile);
+
+ // only allow going further if the users explicitely wants it
+ 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);
+ QueueIndexes(true);
+ }
+ else
+ {
+ _error->Warning("Use --allow-insecure-repositories to force the update");
+ }
+
// FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
if (Cnf->LocalOnly == true ||
StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
string MetaIndexSigURI,string MetaIndexSigURIDesc, string MetaIndexSigShortDesc,
const vector<IndexTarget*>* IndexTargets,
indexRecords* MetaIndexParser) :
- pkgAcqMetaBase(Owner, HashStringList(), TransactionManager), RealURI(URI), IndexTargets(IndexTargets),
- MetaIndexParser(MetaIndexParser), AuthPass(false), IMSHit(false),
+ pkgAcqMetaBase(Owner, IndexTargets, MetaIndexParser, HashStringList(),
+ TransactionManager),
+ RealURI(URI), URIDesc(URIDesc), ShortDesc(ShortDesc),
MetaIndexSigURI(MetaIndexSigURI), MetaIndexSigURIDesc(MetaIndexSigURIDesc),
MetaIndexSigShortDesc(MetaIndexSigShortDesc)
{
// Still more retrieving to do
return;
- if (SigFile == "")
- {
- // load indexes, the signature will downloaded afterwards
- MetaIndexParser->Load(DestFile);
- QueueIndexes(true);
- }
- else
+ if (SigFile != "")
{
// There was a signature file, so pass it to gpgv for
// verification
AuthPass = true;
Desc.URI = "gpgv:" + SigFile;
QueueURI(Desc);
- Mode = "gpgv";
+ ActiveSubprocess = "gpgv";
+#if __GNUC__ >= 4
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+ Mode = "gpgv";
+#if __GNUC__ >= 4
+ #pragma GCC diagnostic pop
+#endif
return;
}
}
FinalFile += URItoFileName(RealURI);
if (SigFile == DestFile)
SigFile = FinalFile;
+
// queue for copy in place
- PartialFile = DestFile;
- DestFile = FinalFile;
+ TransactionManager->TransactionStageCopy(this, DestFile, FinalFile);
}
}
/*}}}*/
URItoFileName((*Target)->URI);
unlink(index.c_str());
// and also old gzipindexes
- index += ".gz";
- unlink(index.c_str());
+ std::vector<std::string> types = APT::Configuration::getCompressionTypes();
+ for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t)
+ {
+ index += '.' + (*t);
+ unlink(index.c_str());
+ }
}
}
#endif
// Download further indexes with verification
//
- // we do not need to download indexfiles if the Release file has not
- // changed because without a changed release file there are no new hashes
- // and we ensure that the repository is always "complete" (i.e. all
- // that is in the release file is downloaded)
- if(IMSHit == false)
- QueueIndexes(true);
+ // it would be really nice if we could simply do
+ // if (IMSHit == false) QueueIndexes(true)
+ // and skip the download if the Release file has not changed
+ // - but right now the list cleaner will needs to be tricked
+ // to not delete all our packages/source indexes in this case
+ QueueIndexes(true);
#if 0
// is it a clearsigned MetaIndex file?
#endif
}
/*}}}*/
-void pkgAcqMetaIndex::QueueIndexes(bool verify) /*{{{*/
+void pkgAcqMetaBase::QueueIndexes(bool verify) /*{{{*/
{
bool transInRelease = false;
{
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;
- }
-
- // warn if the repository is unsinged
_error->Warning(_("The data from '%s' is not signed. Packages "
"from that repository can not be authenticated."),
URIDesc.c_str());
+
// No Release file was present, or verification failed, so fall
// back to queueing Packages files without verification
- QueueIndexes(false);
+ // only allow going further if the users explicitely wants it
+ 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-insecure-repositories to force the update");
+ TransactionManager->AbortTransaction();
+ Status = StatError;
+ return;
+ }
+
}
/*}}}*/
if (FileExists(DestFile) && !StartsWithGPGClearTextSignature(DestFile))
{
pkgAcquire::Item::Failed(Message, Cnf);
- ErrorText = _("Does not start with a cleartext signature");
+ RenameOnError(NotClearsigned);
+ TransactionManager->AbortTransaction();
return;
}
pkgAcqMetaIndex::Done(Message, Size, Hashes, 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,