HashStringList const &ExpectedHashes,
pkgAcqMetaBase *TransactionManager)
: Item(Owner, ExpectedHashes, TransactionManager),
- MetaIndexParser(MetaIndexParser), IndexTargets(IndexTargets),
+ MetaIndexParser(MetaIndexParser), LastMetaIndexParser(NULL), IndexTargets(IndexTargets),
AuthPass(false), RealURI(RealURI), IMSHit(false)
{
}
Transaction.clear();
}
/*}}}*/
+bool pkgAcqMetaBase::TransactionState(TransactionStates const state) /*{{{*/
+{
+ // Do not remove InRelease on IMSHit of Release.gpg [yes, this is very edgecasey]
+ if (TransactionManager->IMSHit == false)
+ return pkgAcquire::Item::TransactionState(state);
+ return true;
+}
+ /*}}}*/
// AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
void pkgAcqMetaBase::TransactionStageCopy(Item *I,
const std::string &From,
}
/*}}}*/
// AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
-bool pkgAcqMetaBase::CheckStopAuthentication(const std::string &Message)
+bool pkgAcqMetaBase::CheckStopAuthentication(pkgAcquire::Item * const I, const std::string &Message)
{
// FIXME: this entire function can do now that we disallow going to
// a unauthenticated state and can cleanly rollback
- string const Final = GetFinalFilename();
+ string const Final = I->GetFinalFilename();
if(FileExists(Final))
{
- Status = StatTransientNetworkError;
+ I->Status = StatTransientNetworkError;
_error->Warning(_("An error occurred during the signature "
"verification. The repository is not updated "
"and the previous index files will be used. "
_error->Error(_("GPG error: %s: %s"),
Desc.Description.c_str(),
LookupTag(Message,"Message").c_str());
- Status = StatError;
+ I->Status = StatError;
return true;
} else {
_error->Warning(_("GPG error: %s: %s"),
/*}}}*/
// 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, IndexTargets, MetaIndexParser, URI,
- HashStringList(), TransactionManager),
- MetaIndexFile(MetaIndexFile), URIDesc(URIDesc),
- ShortDesc(ShortDesc)
+ pkgAcqMetaBase *TransactionManager,
+ string const &URI, string const &URIDesc,string const &ShortDesc,
+ pkgAcqMetaIndex * const MetaIndex) :
+ pkgAcquire::Item(Owner, HashStringList(), TransactionManager), MetaIndex(MetaIndex),
+ URIDesc(URIDesc), RealURI(URI)
{
- DestFile = GetPartialFileNameFromURI(RealURI);
+ DestFile = GetPartialFileNameFromURI(URI);
// remove any partial downloaded sig-file in partial/.
// it may confuse proxies and is too small to warrant a
Desc.ShortDesc = ShortDesc;
Desc.URI = URI;
- QueueURI(Desc);
+ // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
+ // so we skip the download step and go instantly to verification
+ if (TransactionManager->IMSHit == true && RealFileExists(GetFinalFilename()))
+ {
+ Complete = true;
+ Status = StatDone;
+ PartialFile = DestFile = GetFinalFilename();
+ MetaIndexFileSignature = DestFile;
+ MetaIndex->QueueForSignatureVerify(this, MetaIndex->DestFile, DestFile);
+ }
+ else
+ QueueURI(Desc);
}
/*}}}*/
pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
{
+}
+ /*}}}*/
+// pkgAcqMetaSig::GetFinalFilename - Return the full final file path /*{{{*/
+std::string pkgAcqMetaSig::GetFinalFilename() const
+{
+ return GetFinalFileNameFromURI(RealURI);
}
/*}}}*/
// pkgAcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
HashStringList const &Hashes,
pkgAcquire::MethodConfig *Cfg)
{
+ if (MetaIndexFileSignature.empty() == false)
+ {
+ DestFile = MetaIndexFileSignature;
+ MetaIndexFileSignature.clear();
+ }
Item::Done(Message, Size, Hashes, Cfg);
- if(AuthPass == false)
+ if(MetaIndex->AuthPass == false)
{
- if(CheckDownloadDone(Message, Hashes) == true)
+ if(MetaIndex->CheckDownloadDone(this, Message, Hashes) == true)
{
- // destfile will be modified to point to MetaIndexFile for the
- // gpgv method, so we need to save it here
- MetaIndexFileSignature = DestFile;
- QueueForSignatureVerify(MetaIndexFile, MetaIndexFileSignature);
+ // destfile will be modified to point to MetaIndexFile for the
+ // gpgv method, so we need to save it here
+ MetaIndexFileSignature = DestFile;
+ MetaIndex->QueueForSignatureVerify(this, MetaIndex->DestFile, DestFile);
}
return;
}
- else if(CheckAuthDone(Message) == true)
- TransactionManager->TransactionStageCopy(this, MetaIndexFileSignature, GetFinalFilename());
+ else if(MetaIndex->CheckAuthDone(Message) == true)
+ {
+ if (TransactionManager->IMSHit == false)
+ {
+ TransactionManager->TransactionStageCopy(this, DestFile, GetFinalFilename());
+ TransactionManager->TransactionStageCopy(MetaIndex, MetaIndex->DestFile, MetaIndex->GetFinalFilename());
+ }
+ }
}
/*}}}*/
void pkgAcqMetaSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf)/*{{{*/
Item::Failed(Message,Cnf);
// check if we need to fail at this point
- if (AuthPass == true && CheckStopAuthentication(Message))
+ if (MetaIndex->AuthPass == true && MetaIndex->CheckStopAuthentication(this, Message))
return;
- // FIXME: meh, this is not really elegant
- string const Final = GetFinalFileNameFromURI(RealURI);
- string const InReleaseURI = RealURI.replace(RealURI.rfind("Release.gpg"), 12,
- "InRelease");
- string const FinalInRelease = GetFinalFileNameFromURI(InReleaseURI);
+ string const FinalRelease = MetaIndex->GetFinalFilename();
+ string const FinalReleasegpg = GetFinalFilename();
+ string const FinalInRelease = TransactionManager->GetFinalFilename();
- if (RealFileExists(Final) || RealFileExists(FinalInRelease))
+ if (RealFileExists(FinalReleasegpg) || RealFileExists(FinalInRelease))
{
std::string downgrade_msg;
strprintf(downgrade_msg, _("The repository '%s' is no longer signed."),
- URIDesc.c_str());
+ MetaIndex->URIDesc.c_str());
if(_config->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
{
// meh, the users wants to take risks (we still mark the packages
} else {
_error->Error("%s", downgrade_msg.c_str());
if (TransactionManager->IMSHit == false)
- Rename(MetaIndexFile, MetaIndexFile+".FAILED");
+ Rename(MetaIndex->DestFile, MetaIndex->DestFile + ".FAILED");
Item::Failed("Message: " + downgrade_msg, Cnf);
TransactionManager->AbortTransaction();
return;
else
_error->Warning(_("The data from '%s' is not signed. Packages "
"from that repository can not be authenticated."),
- URIDesc.c_str());
+ MetaIndex->URIDesc.c_str());
- // this ensures that any file in the lists/ dir is removed by the
- // transaction
- DestFile = GetPartialFileNameFromURI(RealURI);
+ // ensures that a Release.gpg file in the lists/ is removed by the transaction
TransactionManager->TransactionStageRemoval(this, DestFile);
// only allow going further if the users explicitely wants it
- if(AllowInsecureRepositories(MetaIndexParser, TransactionManager, this) == true)
+ if(AllowInsecureRepositories(MetaIndex->MetaIndexParser, TransactionManager, this) == true)
{
+ if (RealFileExists(FinalReleasegpg) || RealFileExists(FinalInRelease))
+ {
+ // open the last Release if we have it
+ if (TransactionManager->IMSHit == false)
+ {
+ MetaIndex->LastMetaIndexParser = new indexRecords;
+ _error->PushToStack();
+ if (RealFileExists(FinalInRelease))
+ MetaIndex->LastMetaIndexParser->Load(FinalInRelease);
+ else
+ MetaIndex->LastMetaIndexParser->Load(FinalRelease);
+ // its unlikely to happen, but if what we have is bad ignore it
+ if (_error->PendingError())
+ {
+ delete MetaIndex->LastMetaIndexParser;
+ MetaIndex->LastMetaIndexParser = NULL;
+ }
+ _error->RevertToStack();
+ }
+ }
+
// we parse the indexes here because at this point the user wanted
// a repository that may potentially harm him
- MetaIndexParser->Load(MetaIndexFile);
- if (!VerifyVendor(Message))
+ MetaIndex->MetaIndexParser->Load(MetaIndex->DestFile);
+ if (MetaIndex->VerifyVendor(Message) == false)
/* expired Release files are still a problem you need extra force for */;
else
- QueueIndexes(true);
+ MetaIndex->QueueIndexes(true);
+
+ TransactionManager->TransactionStageCopy(MetaIndex, MetaIndex->DestFile, MetaIndex->GetFinalFilename());
}
// FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
{
Item::Done(Message,Size,Hashes,Cfg);
- if(CheckDownloadDone(Message, Hashes))
+ if(CheckDownloadDone(this, Message, Hashes))
{
// we have a Release file, now download the Signature, all further
// verify/queue for additional downloads will be done in the
// pkgAcqMetaSig::Done() code
- std::string const MetaIndexFile = DestFile;
- new pkgAcqMetaSig(Owner, TransactionManager,
+ new pkgAcqMetaSig(Owner, TransactionManager,
MetaIndexSigURI, MetaIndexSigURIDesc,
- MetaIndexSigShortDesc, MetaIndexFile, IndexTargets,
- MetaIndexParser);
-
- TransactionManager->TransactionStageCopy(this, DestFile, GetFinalFilename());
+ MetaIndexSigShortDesc, this);
}
}
/*}}}*/
// perform additional verification of its contents, and use them
// to verify the indexes we are about to download
+ if (TransactionManager->IMSHit == false)
+ {
+ // open the last (In)Release if we have it
+ std::string const FinalFile = GetFinalFilename();
+ std::string FinalRelease;
+ std::string FinalInRelease;
+ if (APT::String::Endswith(FinalFile, "InRelease"))
+ {
+ FinalInRelease = FinalFile;
+ FinalRelease = FinalFile.substr(0, FinalFile.length() - strlen("InRelease")) + "Release";
+ }
+ else
+ {
+ FinalInRelease = FinalFile.substr(0, FinalFile.length() - strlen("Release")) + "InRelease";
+ FinalRelease = FinalFile;
+ }
+ if (RealFileExists(FinalInRelease) || RealFileExists(FinalRelease))
+ {
+ LastMetaIndexParser = new indexRecords;
+ _error->PushToStack();
+ if (RealFileExists(FinalInRelease))
+ LastMetaIndexParser->Load(FinalInRelease);
+ else
+ LastMetaIndexParser->Load(FinalRelease);
+ // its unlikely to happen, but if what we have is bad ignore it
+ if (_error->PendingError())
+ {
+ delete LastMetaIndexParser;
+ LastMetaIndexParser = NULL;
+ }
+ _error->RevertToStack();
+ }
+ }
+
if (!MetaIndexParser->Load(DestFile))
{
Status = StatAuthError;
}
/*}}}*/
// pkgAcqMetaBase::QueueForSignatureVerify /*{{{*/
-void pkgAcqMetaBase::QueueForSignatureVerify(const std::string &MetaIndexFile,
- const std::string &MetaIndexFileSignature)
+void pkgAcqMetaBase::QueueForSignatureVerify(pkgAcquire::Item * const I, std::string const &File, std::string const &Signature)
{
AuthPass = true;
- Desc.URI = "gpgv:" + MetaIndexFileSignature;
- DestFile = MetaIndexFile;
- QueueURI(Desc);
- SetActiveSubprocess("gpgv");
+ I->Desc.URI = "gpgv:" + Signature;
+ I->DestFile = File;
+ QueueURI(I->Desc);
+ I->SetActiveSubprocess("gpgv");
}
/*}}}*/
// pkgAcqMetaBase::CheckDownloadDone /*{{{*/
-bool pkgAcqMetaBase::CheckDownloadDone(const std::string &Message, HashStringList const &Hashes)
+bool pkgAcqMetaBase::CheckDownloadDone(pkgAcquire::Item * const I, const std::string &Message, HashStringList const &Hashes) const
{
// We have just finished downloading a Release file (it is not
// verified yet)
- string FileName = LookupTag(Message,"Filename");
+ string const FileName = LookupTag(Message,"Filename");
if (FileName.empty() == true)
{
- Status = StatError;
- ErrorText = "Method gave a blank filename";
+ I->Status = StatError;
+ I->ErrorText = "Method gave a blank filename";
return false;
}
- if (FileName != DestFile)
+ if (FileName != I->DestFile)
{
- Local = true;
- Desc.URI = "copy:" + FileName;
- QueueURI(Desc);
+ I->Local = true;
+ I->Desc.URI = "copy:" + FileName;
+ I->QueueURI(I->Desc);
return false;
}
// make sure to verify against the right file on I-M-S hit
- IMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false);
- if (IMSHit == false)
+ bool IMSHit = StringToBool(LookupTag(Message,"IMS-Hit"), false);
+ if (IMSHit == false && Hashes.usable())
{
// detect IMS-Hits servers haven't detected by Hash comparison
- std::string FinalFile = GetFinalFilename();
+ std::string const FinalFile = I->GetFinalFilename();
if (RealFileExists(FinalFile) && Hashes.VerifyFile(FinalFile) == true)
{
IMSHit = true;
- unlink(DestFile.c_str());
+ unlink(I->DestFile.c_str());
}
}
// even if it doesn't exist.
if (TransactionManager != NULL)
TransactionManager->IMSHit = true;
- DestFile = GetFinalFilename();
+ I->PartialFile = I->DestFile = I->GetFinalFilename();
}
// set Item to complete as the remaining work is all local (verify etc)
- Complete = true;
+ I->Complete = true;
return true;
}
}
}
+ /* Did we get a file older than what we have? This is a last minute IMS hit and doubles
+ as a prevention of downgrading us to older (still valid) files */
+ if (TransactionManager->IMSHit == false && LastMetaIndexParser != NULL &&
+ LastMetaIndexParser->GetDate() > MetaIndexParser->GetDate())
+ {
+ TransactionManager->IMSHit = true;
+ unlink(DestFile.c_str());
+ PartialFile = DestFile = GetFinalFilename();
+ delete MetaIndexParser;
+ MetaIndexParser = LastMetaIndexParser;
+ LastMetaIndexParser = NULL;
+ }
+
if (_config->FindB("Debug::pkgAcquire::Auth", false))
{
std::cerr << "Got Codename: " << MetaIndexParser->GetDist() << std::endl;
{
// index targets + (worst case:) Release/Release.gpg
ExpectedAdditionalItems = IndexTargets->size() + 2;
-
}
/*}}}*/
pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
}
/*}}}*/
// pkgAcqMetaClearSig::Done - We got a file /*{{{*/
-// ---------------------------------------------------------------------
+class APT_HIDDEN DummyItem : public pkgAcquire::Item
+{
+ std::string URI;
+ public:
+ virtual std::string DescURI() {return URI;};
+
+ DummyItem(pkgAcquire *Owner, std::string const &URI) : pkgAcquire::Item(Owner), URI(URI)
+ {
+ Status = StatDone;
+ DestFile = GetFinalFileNameFromURI(URI);
+ }
+};
void pkgAcqMetaClearSig::Done(std::string Message,unsigned long long Size,
HashStringList const &Hashes,
pkgAcquire::MethodConfig *Cnf)
{
Item::Done(Message, Size, Hashes, Cnf);
- // if we expect a ClearTextSignature (InRelase), ensure that
+ // if we expect a ClearTextSignature (InRelease), ensure that
// this is what we get and if not fail to queue a
// Release/Release.gpg, see #346386
if (FileExists(DestFile) && !StartsWithGPGClearTextSignature(DestFile))
if(AuthPass == false)
{
- if(CheckDownloadDone(Message, Hashes) == true)
- QueueForSignatureVerify(DestFile, DestFile);
+ if(CheckDownloadDone(this, Message, Hashes) == true)
+ QueueForSignatureVerify(this, DestFile, DestFile);
return;
}
else if(CheckAuthDone(Message) == true)
- TransactionManager->TransactionStageCopy(this, DestFile, GetFinalFilename());
+ {
+ if (TransactionManager->IMSHit == false)
+ TransactionManager->TransactionStageCopy(this, DestFile, GetFinalFilename());
+ else if (RealFileExists(GetFinalFilename()) == false)
+ {
+ // We got an InRelease file IMSHit, but we haven't one, which means
+ // we had a valid Release/Release.gpg combo stepping in, which we have
+ // to 'acquire' now to ensure list cleanup isn't removing them
+ new DummyItem(Owner, MetaIndexURI);
+ new DummyItem(Owner, MetaSigURI);
+ }
+ }
}
/*}}}*/
void pkgAcqMetaClearSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /*{{{*/
}
else
{
- if(CheckStopAuthentication(Message))
+ if(CheckStopAuthentication(this, Message))
return;
_error->Warning(_("The data from '%s' is not signed. Packages "
/** \brief A package-system-specific parser for the meta-index file. */
indexRecords *MetaIndexParser;
+ indexRecords *LastMetaIndexParser;
/** \brief The index files which should be looked up in the meta-index
* and then downloaded.
* \param Message The message block received from the fetch
* subprocess.
*/
- bool CheckDownloadDone(const std::string &Message, HashStringList const &Hashes);
+ bool CheckDownloadDone(pkgAcquire::Item * const I, const std::string &Message, HashStringList const &Hashes) const;
/** \brief Queue the downloaded Signature for verification */
- void QueueForSignatureVerify(const std::string &MetaIndexFile,
- const std::string &MetaIndexFileSignature);
+ void QueueForSignatureVerify(pkgAcquire::Item * const I, std::string const &File, std::string const &Signature);
#if APT_PKG_ABI >= 413
virtual std::string Custom600Headers() const;
bool CheckAuthDone(std::string Message);
/** Check if the current item should fail at this point */
- bool CheckStopAuthentication(const std::string &Message);
+ bool CheckStopAuthentication(pkgAcquire::Item * const I, const std::string &Message);
/** \brief Check that the release file is a release file for the
* correct distribution.
*/
bool VerifyVendor(std::string Message);
- /** \brief Get the full pathname of the final file for the current URI */
- virtual std::string GetFinalFilename() const;
+ virtual bool TransactionState(TransactionStates const state);
public:
// This refers more to the Transaction-Manager than the actual file
*/
void TransactionStageRemoval(Item *I, const std::string &FinalFile);
+ /** \brief Get the full pathname of the final file for the current URI */
+ virtual std::string GetFinalFilename() const;
+
pkgAcqMetaBase(pkgAcquire *Owner,
const std::vector<IndexTarget*>* IndexTargets,
indexRecords* MetaIndexParser,
pkgAcqMetaBase *TransactionManager=NULL);
};
/*}}}*/
-/** \brief An acquire item that downloads the detached signature {{{
- * of a meta-index (Release) file, then queues up the release
- * file itself.
- *
- * \todo Why protected members?
- *
- * \sa pkgAcqMetaIndex
- */
-class APT_HIDDEN pkgAcqMetaSig : public pkgAcqMetaBase
-{
- void *d;
-
- protected:
-
- /** \brief The file we need to verify */
- std::string MetaIndexFile;
-
- /** \brief The file we use to verify the MetaIndexFile with */
- std::string MetaIndexFileSignature;
-
- /** \brief Long URI description used in the acquire system */
- std::string URIDesc;
-
- /** \brief Short URI description used in the acquire system */
- std::string ShortDesc;
-
- public:
-
- // Specialized action members
- virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
- virtual void Done(std::string Message,unsigned long long Size,
- HashStringList const &Hashes,
- pkgAcquire::MethodConfig *Cnf);
-
- /** \brief Create a new pkgAcqMetaSig. */
- pkgAcqMetaSig(pkgAcquire *Owner,
- pkgAcqMetaBase *TransactionManager,
- std::string URI,std::string URIDesc, std::string ShortDesc,
- std::string MetaIndexFile,
- const std::vector<IndexTarget*>* IndexTargets,
- indexRecords* MetaIndexParser);
- virtual ~pkgAcqMetaSig();
-};
- /*}}}*/
/** \brief An item that is responsible for downloading the meta-index {{{
* file (i.e., Release) itself and verifying its signature.
*
std::string MetaIndexSigURI, std::string MetaIndexSigURIDesc, std::string MetaIndexSigShortDesc,
const std::vector<IndexTarget*>* IndexTargets,
indexRecords* MetaIndexParser);
+
+ friend class pkgAcqMetaSig;
+};
+ /*}}}*/
+/** \brief An acquire item that downloads the detached signature {{{
+ * of a meta-index (Release) file, then queues up the release
+ * file itself.
+ *
+ * \todo Why protected members?
+ *
+ * \sa pkgAcqMetaIndex
+ */
+class APT_HIDDEN pkgAcqMetaSig : public pkgAcquire::Item
+{
+ void *d;
+
+ pkgAcqMetaIndex * const MetaIndex;
+
+ /** \brief The file we use to verify the MetaIndexFile with (not always set!) */
+ std::string MetaIndexFileSignature;
+
+ protected:
+
+ /** \brief Long URI description used in the acquire system */
+ std::string URIDesc;
+
+ /** \brief URI used to get the file */
+ std::string RealURI;
+
+ /** \brief Get the full pathname of the final file for the current URI */
+ virtual std::string GetFinalFilename() const;
+
+ public:
+ virtual std::string DescURI() {return RealURI;};
+
+ // Specialized action members
+ virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
+ virtual void Done(std::string Message,unsigned long long Size,
+ HashStringList const &Hashes,
+ pkgAcquire::MethodConfig *Cnf);
+
+ /** \brief Create a new pkgAcqMetaSig. */
+ pkgAcqMetaSig(pkgAcquire *Owner,
+ pkgAcqMetaBase *TransactionManager,
+ std::string const &URI,std::string const &URIDesc,
+ std::string const &ShortDesc, pkgAcqMetaIndex * const MetaIndex);
+ virtual ~pkgAcqMetaSig();
};
/*}}}*/
/** \brief An item repsonsible for downloading clearsigned metaindexes {{{*/
return this->ValidUntil;
}
+APT_PURE time_t indexRecords::GetDate() const
+{
+ return this->Date;
+}
+
APT_PURE indexRecords::checkSum *indexRecords::Lookup(const string MetaKey)
{
std::map<std::string, indexRecords::checkSum* >::const_iterator sum = Entries.find(MetaKey);
return false;
}
- string Label = Section.FindS("Label");
- string StrDate = Section.FindS("Date");
- string StrValidUntil = Section.FindS("Valid-Until");
+ string const StrDate = Section.FindS("Date");
+ if (RFC1123StrToTime(StrDate.c_str(), Date) == false)
+ {
+ strprintf(ErrorText, _("Invalid 'Date' entry in Release file %s"), Filename.c_str());
+ return false;
+ }
+
+ string const Label = Section.FindS("Label");
+ string const StrValidUntil = Section.FindS("Valid-Until");
// if we have a Valid-Until header in the Release file, use it as default
if (StrValidUntil.empty() == false)
(MinAge == 0 || ValidUntil == 0)) // No user settings, use the one from the Release file
return true;
- time_t date;
- if (RFC1123StrToTime(StrDate.c_str(), date) == false)
- {
- strprintf(ErrorText, _("Invalid 'Date' entry in Release file %s"), Filename.c_str());
- return false;
- }
-
if (MinAge != 0 && ValidUntil != 0) {
- time_t const min_date = date + MinAge;
+ time_t const min_date = Date + MinAge;
if (ValidUntil < min_date)
ValidUntil = min_date;
}
if (MaxAge != 0) {
- time_t const max_date = date + MaxAge;
+ time_t const max_date = Date + MaxAge;
if (ValidUntil == 0 || ValidUntil > max_date)
ValidUntil = max_date;
}
std::string Dist;
std::string Suite;
std::string ExpectedDist;
+ time_t Date;
time_t ValidUntil;
bool SupportsAcquireByHash;
std::string GetSuite() const;
bool GetSupportsAcquireByHash() const;
time_t GetValidUntil() const;
+ time_t GetDate() const;
std::string GetExpectedDist() const;
/** \brief check if source is marked as always trusted */
shift
msgtest "Test for correctness of file" "$FILE"
if [ -z "$*" ]; then
- echo -n "" | checkdiff $FILE - && msgpass || msgfail
+ echo -n "" | checkdiff - $FILE && msgpass || msgfail
else
- echo "$*" | checkdiff $FILE - && msgpass || msgfail
+ echo "$*" | checkdiff - $FILE && msgpass || msgfail
fi
}
testaptautotestnodpkgwarning() {
local TESTCALL="$1"
while [ -n "$2" ]; do
- if expr match "$2" '^-[a-z]*s' >/dev/null 2>&1; then return; fi
+ if expr match "$2" '^-[a-z]*s' >/dev/null 2>&1; then return; fi # simulation mode
+ if expr match "$2" '^-dy\?' >/dev/null 2>&1; then return; fi # download-only mode
shift
done
testfailure grep '^dpkg: warning:.*ignor.*' "${TMPWORKINGDIRECTORY}/rootdir/tmp-before/${TESTCALL}.output"
testfileequal 'listsdir.lst' "$(listcurrentlistsdirectory)"
# ensure that we still do a hash check for other files on ims hit of Release
- if grep -q '^Hit .* \(InRelease\|Release.gpg\)$' expected.output ; then
+ if grep -q '^Hit .* InRelease$' expected.output || ! grep -q '^Ign .* Release\(\.gpg\)\?$' expected.output; then
$TEST aptget update -o Debug::Acquire::gpgv=1
cp rootdir/tmp/${TEST}.output goodsign.output
testfileequal 'listsdir.lst' "$(listcurrentlistsdirectory)"
EXPECT='Ign http://localhost:8080 unstable InRelease
404 Not Found
Hit http://localhost:8080 unstable Release
-Hit http://localhost:8080 unstable Release.gpg
Reading package lists...'
find aptarchive -name 'InRelease' -delete
echo 'Acquire::GzipIndexes "0";' > rootdir/etc/apt/apt.conf.d/02compressindex
Ign http://localhost:8080 unstable Release.gpg
404 Not Found
Reading package lists...
-W: The data from 'http://localhost:8080 unstable Release.gpg' is not signed. Packages from that repository can not be authenticated."
+W: The data from 'http://localhost:8080 unstable Release' is not signed. Packages from that repository can not be authenticated."
find aptarchive -name 'Release.gpg' -delete
echo 'Acquire::GzipIndexes "0";' > rootdir/etc/apt/apt.conf.d/02compressindex
runtest 'warning'
EXPECT='Ign http://localhost:8080 unstable InRelease
404 Not Found
Hit http://localhost:8080 unstable Release
-Hit http://localhost:8080 unstable Release.gpg
-E: Release file for http://localhost:8080/dists/unstable/Release.gpg is expired (invalid since). Updates for this repository will not be applied.'
+E: Release file for http://localhost:8080/dists/unstable/Release is expired (invalid since). Updates for this repository will not be applied.'
find aptarchive -name 'InRelease' -delete
echo 'Acquire::GzipIndexes "0";' > rootdir/etc/apt/apt.conf.d/02compressindex
runtest 'failure'
Hit http://localhost:8080 unstable Release
Ign http://localhost:8080 unstable Release.gpg
404 Not Found
-W: The data from 'http://localhost:8080 unstable Release.gpg' is not signed. Packages from that repository can not be authenticated.
-E: Release file for http://localhost:8080/dists/unstable/InRelease is expired (invalid since). Updates for this repository will not be applied."
+W: The data from 'http://localhost:8080 unstable Release' is not signed. Packages from that repository can not be authenticated.
+E: Release file for http://localhost:8080/dists/unstable/Release is expired (invalid since). Updates for this repository will not be applied."
find aptarchive -name 'Release.gpg' -delete
echo 'Acquire::GzipIndexes "0";' > rootdir/etc/apt/apt.conf.d/02compressindex
runtest 'failure' 'warning'
simulate_mitm_and_inject_evil_package()
{
+ redatereleasefiles '+1 hour'
rm -f $APTARCHIVE/dists/unstable/InRelease
rm -f $APTARCHIVE/dists/unstable/Release.gpg
inject_evil_package
assert_update_is_refused_and_last_good_state_used()
{
- testfailureequal "E: The repository 'file: unstable Release.gpg' is no longer signed." aptget update -qq
+ testfailuremsg "E: The repository 'file: unstable Release' is no longer signed." aptget update
assert_repo_is_intact
}
echo "Some evil data" >> $APTARCHIVE/dists/unstable/Release
inject_evil_package
- testwarningequal "W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: file: unstable Release.gpg: The following signatures were invalid: BADSIG 5A90D141DBAC8DAE Joe Sixpack (APT Testcases Dummy) <joe@example.org>
+ testwarningequal "W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: file: unstable Release: The following signatures were invalid: BADSIG 5A90D141DBAC8DAE Joe Sixpack (APT Testcases Dummy) <joe@example.org>
W: Failed to fetch file:${APTARCHIVE}/dists/unstable/Release.gpg The following signatures were invalid: BADSIG 5A90D141DBAC8DAE Joe Sixpack (APT Testcases Dummy) <joe@example.org>
testsuccessequal "Ign $1 unstable InRelease
404 Not Found
Hit $1 unstable Release
-Hit $1 unstable Release.gpg
Reading package lists..." aptget update
testfileequal 'listsdir.lst' "$(listcurrentlistsdirectory)"
testsuccessequal "Ign $1 unstable InRelease
404 Not Found
Hit $1 unstable Release
-Hit $1 unstable Release.gpg
Reading package lists..." aptget update
testfileequal 'listsdir-without-amd64.lst' "$(listcurrentlistsdirectory)"
testsuccessequal "Ign $1 unstable InRelease
404 Not Found
Hit $1 unstable Release
-Hit $1 unstable Release.gpg
Get:1 $1 unstable/main amd64 Packages [$(stat -c '%s' 'aptarchive/dists/unstable/main/binary-amd64/Packages.gz') B]
Reading package lists..." aptget update
testfileequal 'listsdir.lst' "$(listcurrentlistsdirectory)"
testsuccessequal "Ign $1 unstable InRelease
404 Not Found
Get:1 $1 unstable Release [$(stat -c '%s' 'aptarchive/dists/unstable/Release') B]
-Get:2 $1 unstable Release.gpg [$(stat -c '%s' 'aptarchive/dists/unstable/Release.gpg') B]
Reading package lists..." aptget update
webserverconfig 'aptwebserver::support::modified-since' 'true'
webserverconfig 'aptwebserver::support::last-modified' 'true'
rm $APTARCHIVE/dists/unstable/Release.gpg
# update fails
- testfailureequal "E: The repository 'file: unstable Release.gpg' is no longer signed." aptget update -qq
+ testfailureequal "E: The repository 'file: unstable Release' is no longer signed." aptget update -qq
# test that security downgrade was not successful
testfileequal lists.before "$(listcurrentlistsdirectory)"
break_repository_sources_index '+1hour'
# ensure error
- testfailureequal "E: The repository 'file: unstable Release.gpg' is no longer signed." aptget update -qq # -o Debug::acquire::transaction=1
+ testfailureequal "E: The repository 'file: unstable Release' is no longer signed." aptget update -qq # -o Debug::acquire::transaction=1
# ensure that the Packages file is also rolled back
testfileequal lists.before "$(listcurrentlistsdirectory)"
--- /dev/null
+#!/bin/sh
+set -e
+
+TESTDIR=$(readlink -f $(dirname $0))
+. $TESTDIR/framework
+setupenvironment
+configarchitecture 'i386'
+
+insertpackage 'wheezy' 'apt' 'all' '0.8.15'
+
+setupaptarchive --no-update
+
+# we don't complain as the server could have just sent a 'Hit' here and this
+# 'downgrade attack' is usually performed by out-of-sync mirrors. Valid-Until
+# catches the 'real' downgrade attacks (expect that it finds stale mirrors).
+# Scaring users with an error here serves hence no point.
+
+msgmsg 'InRelease file is silently rejected if' 'new Date is before old Date'
+rm -rf rootdir/var/lib/apt/lists
+generatereleasefiles 'now' 'now + 7 days'
+signreleasefiles
+testsuccess aptget update
+listcurrentlistsdirectory > listsdir.lst
+redatereleasefiles 'now - 2 days'
+testsuccess aptget update
+testfileequal 'listsdir.lst' "$(listcurrentlistsdirectory)"
+
+msgmsg 'Release.gpg file is silently rejected if' 'new Date is before old Date'
+rm -rf rootdir/var/lib/apt/lists
+generatereleasefiles 'now' 'now + 7 days'
+signreleasefiles
+find aptarchive -name 'InRelease' -delete
+testsuccess aptget update
+listcurrentlistsdirectory > listsdir.lst
+redatereleasefiles 'now - 2 days'
+find aptarchive -name 'InRelease' -delete
+testsuccess aptget update
+testfileequal 'listsdir.lst' "$(listcurrentlistsdirectory)"
+
+msgmsg 'Crisscross InRelease/Release.gpg file is silently rejected if' 'new Date is before old Date'
+rm -rf rootdir/var/lib/apt/lists
+generatereleasefiles 'now' 'now + 7 days'
+signreleasefiles
+find aptarchive -name 'Release.gpg' -delete
+testsuccess aptget update
+listcurrentlistsdirectory > listsdir.lst
+redatereleasefiles 'now - 2 days'
+find aptarchive -name 'InRelease' -delete
+testsuccess aptget update
+testfileequal 'listsdir.lst' "$(listcurrentlistsdirectory)"
+
+msgmsg 'Crisscross Release.gpg/InRelease file is silently rejected if' 'new Date is before old Date'
+rm -rf rootdir/var/lib/apt/lists
+generatereleasefiles 'now' 'now + 7 days'
+signreleasefiles
+find aptarchive -name 'InRelease' -delete
+testsuccess aptget update
+listcurrentlistsdirectory > listsdir.lst
+redatereleasefiles 'now - 2 days'
+find aptarchive -name 'Release.gpg' -delete
+testsuccess aptget update
+testfileequal 'listsdir.lst' "$(listcurrentlistsdirectory)"
runtest() {
local MSG="$1"
- msgtest "$1" "$2"
+ msgtest "Release file is $MSG as it has" "$2"
rm -rf rootdir/var/lib/apt/lists
- aptget clean
generatereleasefiles "$3" "$4"
signreleasefiles
shift 4
- if expr match "$MSG" '.*accepted.*' >/dev/null; then
+ if [ "$MSG" = 'accepted' ]; then
testsuccess --nomsg aptget update "$@"
testfailure grep -q 'is expired' rootdir/tmp/testsuccess.output
else
fi
}
-runtest 'Release file is accepted as it has' 'no Until' '' ''
-runtest 'Release file is accepted as it has' 'no Until and good Max-Valid' '' '' -o Acquire::Max-ValidTime=3600
-runtest 'Release file is rejected as it has' 'no Until, but bad Max-Valid' 'now - 2 days' '' -o Acquire::Max-ValidTime=3600
-runtest 'Release file is accepted as it has' 'good Until' 'now - 3 days' 'now + 1 day'
-runtest 'Release file is rejected as it has' 'bad Until' 'now - 7 days' 'now - 4 days'
-runtest 'Release file is rejected as it has' 'bad Until (ignore good Max-Valid)' 'now - 7 days' 'now - 4 days' -o Acquire::Max-ValidTime=1209600
-runtest 'Release file is rejected as it has' 'bad Max-Valid (bad Until)' 'now - 7 days' 'now - 4 days' -o Acquire::Max-ValidTime=86400
-runtest 'Release file is rejected as it has' 'bad Max-Valid (good Until)' 'now - 7 days' 'now + 4 days' -o Acquire::Max-ValidTime=86400
-runtest 'Release file is accepted as it has' 'good labeled Max-Valid' 'now - 7 days' 'now + 4 days' -o Acquire::Max-ValidTime=86400 -o Acquire::Max-ValidTime::Testcases=1209600
-runtest 'Release file is rejected as it has' 'bad labeled Max-Valid' 'now - 7 days' 'now + 4 days' -o Acquire::Max-ValidTime=1209600 -o Acquire::Max-ValidTime::Testcases=86400
-runtest 'Release file is accepted as it has' 'good Until (good Min-Valid, no Max-Valid)' 'now - 7 days' 'now + 1 days' -o Acquire::Min-ValidTime=1209600
-runtest 'Release file is accepted as it has' 'good Min-Valid (bad Until, no Max-Valid)' 'now - 7 days' 'now - 4 days' -o Acquire::Min-ValidTime=1209600
-runtest 'Release file is accepted as it has' 'good Min-Valid (bad Until, good Max-Valid) <' 'now - 7 days' 'now - 2 days' -o Acquire::Min-ValidTime=1209600 -o Acquire::Max-ValidTime=2419200
-runtest 'Release file is rejected as it has' 'bad Max-Valid (bad Until, good Min-Valid) >' 'now - 7 days' 'now - 2 days' -o Acquire::Max-ValidTime=12096 -o Acquire::Min-ValidTime=2419200
-runtest 'Release file is rejected as it has' 'bad Max-Valid (bad Until, bad Min-Valid) <' 'now - 7 days' 'now - 2 days' -o Acquire::Min-ValidTime=12096 -o Acquire::Max-ValidTime=241920
-runtest 'Release file is rejected as it has' 'bad Max-Valid (bad Until, bad Min-Valid) >' 'now - 7 days' 'now - 2 days' -o Acquire::Max-ValidTime=12096 -o Acquire::Min-ValidTime=241920
+runtest 'accepted' 'no Until' '' ''
+runtest 'accepted' 'no Until and good Max-Valid' '' '' -o Acquire::Max-ValidTime=3600
+runtest 'rejected' 'no Until, but bad Max-Valid' 'now - 2 days' '' -o Acquire::Max-ValidTime=3600
+runtest 'accepted' 'good Until' 'now - 3 days' 'now + 1 day'
+runtest 'rejected' 'bad Until' 'now - 7 days' 'now - 4 days'
+runtest 'rejected' 'bad Until (ignore good Max-Valid)' 'now - 7 days' 'now - 4 days' -o Acquire::Max-ValidTime=1209600
+runtest 'rejected' 'bad Max-Valid (bad Until)' 'now - 7 days' 'now - 4 days' -o Acquire::Max-ValidTime=86400
+runtest 'rejected' 'bad Max-Valid (good Until)' 'now - 7 days' 'now + 4 days' -o Acquire::Max-ValidTime=86400
+runtest 'accepted' 'good labeled Max-Valid' 'now - 7 days' 'now + 4 days' -o Acquire::Max-ValidTime=86400 -o Acquire::Max-ValidTime::Testcases=1209600
+runtest 'rejected' 'bad labeled Max-Valid' 'now - 7 days' 'now + 4 days' -o Acquire::Max-ValidTime=1209600 -o Acquire::Max-ValidTime::Testcases=86400
+runtest 'accepted' 'good Until (good Min-Valid, no Max-Valid)' 'now - 7 days' 'now + 1 days' -o Acquire::Min-ValidTime=1209600
+runtest 'accepted' 'good Min-Valid (bad Until, no Max-Valid)' 'now - 7 days' 'now - 4 days' -o Acquire::Min-ValidTime=1209600
+runtest 'accepted' 'good Min-Valid (bad Until, good Max-Valid) <' 'now - 7 days' 'now - 2 days' -o Acquire::Min-ValidTime=1209600 -o Acquire::Max-ValidTime=2419200
+runtest 'rejected' 'bad Max-Valid (bad Until, good Min-Valid) >' 'now - 7 days' 'now - 2 days' -o Acquire::Max-ValidTime=12096 -o Acquire::Min-ValidTime=2419200
+runtest 'rejected' 'bad Max-Valid (bad Until, bad Min-Valid) <' 'now - 7 days' 'now - 2 days' -o Acquire::Min-ValidTime=12096 -o Acquire::Max-ValidTime=241920
+runtest 'rejected' 'bad Max-Valid (bad Until, bad Min-Valid) >' 'now - 7 days' 'now - 2 days' -o Acquire::Max-ValidTime=12096 -o Acquire::Min-ValidTime=241920
PKGFILE="${TESTDIR}/$(echo "$(basename $0)" | sed 's#^test-#Packages-#')"
-updatesuccess() {
- local LOG='update.log'
- if aptget update >$LOG 2>&1 || grep -q -E '^(W|E): ' $LOG; then
- msgpass
- else
- cat $LOG
- msgfail
- fi
-}
-
-updatefailure() {
- local LOG='update.log'
- aptget update >$LOG 2>&1 || true
- if grep -q -E "$1" $LOG; then
- msgpass
- else
- cat $LOG
- msgfail
- fi
+updatewithwarnings() {
+ testwarning aptget update
+ testsuccess grep -E "$1" rootdir/tmp/testwarning.output
}
runtest() {
rm -rf rootdir/var/lib/apt/lists
signreleasefiles 'Joe Sixpack'
find aptarchive/ -name "$DELETEFILE" -delete
- msgtest 'Cold archive signed by' 'Joe Sixpack'
- updatesuccess
+ msgmsg 'Cold archive signed by' 'Joe Sixpack'
+ testsuccess aptget update
testsuccessequal "$(cat ${PKGFILE})
" aptcache show apt
installaptold
prepare ${PKGFILE}-new
signreleasefiles 'Joe Sixpack'
find aptarchive/ -name "$DELETEFILE" -delete
- msgtest 'Good warm archive signed by' 'Joe Sixpack'
- updatesuccess
+ msgmsg 'Good warm archive signed by' 'Joe Sixpack'
+ testsuccess aptget update
testsuccessequal "$(cat ${PKGFILE}-new)
" aptcache show apt
installaptnew
cp keys/rexexpired.pub rootdir/etc/apt/trusted.gpg.d/rexexpired.gpg
signreleasefiles 'Rex Expired'
find aptarchive/ -name "$DELETEFILE" -delete
- msgtest 'Cold archive signed by' 'Rex Expired'
- updatefailure '^W: .* KEYEXPIRED'
+ msgmsg 'Cold archive signed by' 'Rex Expired'
+ updatewithwarnings '^W: .* KEYEXPIRED'
testsuccessequal "$(cat ${PKGFILE})
" aptcache show apt
failaptold
rm -rf rootdir/var/lib/apt/lists
signreleasefiles 'Marvin Paranoid'
find aptarchive/ -name "$DELETEFILE" -delete
- msgtest 'Cold archive signed by' 'Marvin Paranoid'
- updatefailure '^W: .* NO_PUBKEY'
+ msgmsg 'Cold archive signed by' 'Marvin Paranoid'
+ updatewithwarnings '^W: .* NO_PUBKEY'
testsuccessequal "$(cat ${PKGFILE})
" aptcache show apt
failaptold
done
signreleasefiles 'Joe Sixpack'
find aptarchive/ -name "$DELETEFILE" -delete
- msgtest 'Bad warm archive signed by' 'Joe Sixpack'
- updatesuccess
+ msgmsg 'Bad warm archive signed by' 'Joe Sixpack'
+ testsuccess aptget update
testsuccessequal "$(cat ${PKGFILE}-new)
" aptcache show apt
installaptnew
rm -rf rootdir/var/lib/apt/lists
signreleasefiles 'Joe Sixpack'
find aptarchive/ -name "$DELETEFILE" -delete
- msgtest 'Cold archive signed by' 'Joe Sixpack'
- updatesuccess
+ msgmsg 'Cold archive signed by' 'Joe Sixpack'
+ testsuccess aptget update
testsuccessequal "$(cat ${PKGFILE})
" aptcache show apt
installaptold
prepare ${PKGFILE}-new
signreleasefiles 'Marvin Paranoid'
find aptarchive/ -name "$DELETEFILE" -delete
- msgtest 'Good warm archive signed by' 'Marvin Paranoid'
- updatefailure '^W: .* NO_PUBKEY'
+ msgmsg 'Good warm archive signed by' 'Marvin Paranoid'
+ updatewithwarnings '^W: .* NO_PUBKEY'
testsuccessequal "$(cat ${PKGFILE})
" aptcache show apt
installaptold
cp keys/rexexpired.pub rootdir/etc/apt/trusted.gpg.d/rexexpired.gpg
signreleasefiles 'Rex Expired'
find aptarchive/ -name "$DELETEFILE" -delete
- msgtest 'Good warm archive signed by' 'Rex Expired'
- updatefailure '^W: .* KEYEXPIRED'
+ msgmsg 'Good warm archive signed by' 'Rex Expired'
+ updatewithwarnings '^W: .* KEYEXPIRED'
testsuccessequal "$(cat ${PKGFILE})
" aptcache show apt
installaptold
prepare ${PKGFILE}-new
signreleasefiles
find aptarchive/ -name "$DELETEFILE" -delete
- msgtest 'Good warm archive signed by' 'Joe Sixpack'
- updatesuccess
+ msgmsg 'Good warm archive signed by' 'Joe Sixpack'
+ testsuccess aptget update
testsuccessequal "$(cat ${PKGFILE}-new)
" aptcache show apt
installaptnew
prepare ${PKGFILE}
rm -rf rootdir/var/lib/apt/lists
signreleasefiles 'Joe Sixpack'
- msgtest 'Cold archive signed by' 'Joe Sixpack'
- updatesuccess
+ msgmsg 'Cold archive signed by' 'Joe Sixpack'
+ testsuccess aptget update
# New .deb but now an unsigned archive. For example MITM to circumvent
# package verification.
prepare ${PKGFILE}-new
find aptarchive/ -name InRelease -delete
find aptarchive/ -name Release.gpg -delete
- msgtest 'Warm archive signed by' 'nobody'
- updatesuccess
+ msgmsg 'Warm archive signed by' 'nobody'
+ updatewithwarnings 'W: .* no longer signed.'
testsuccessequal "$(cat ${PKGFILE}-new)
" aptcache show apt
failaptnew
# Unsigned archive from the beginning must also be detected.
rm -rf rootdir/var/lib/apt/lists
- msgtest 'Cold archive signed by' 'nobody'
- updatesuccess
+ msgmsg 'Cold archive signed by' 'nobody'
+ updatewithwarnings 'W: .* is not signed.'
testsuccessequal "$(cat ${PKGFILE}-new)
" aptcache show apt
failaptnew