diff options
-rw-r--r-- | apt-pkg/acquire-item.cc | 4 | ||||
-rw-r--r-- | apt-pkg/deb/debmetaindex.cc | 134 | ||||
-rw-r--r-- | apt-pkg/deb/debmetaindex.h | 3 | ||||
-rw-r--r-- | apt-pkg/sourcelist.cc | 3 | ||||
-rw-r--r-- | doc/apt-get.8.xml | 10 | ||||
-rw-r--r-- | doc/apt.conf.5.xml | 8 | ||||
-rw-r--r-- | doc/sources.list.5.xml | 55 | ||||
-rwxr-xr-x | test/integration/test-releasefile-valid-until | 9 |
8 files changed, 170 insertions, 56 deletions
diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc index 100199bc1..a30a5d154 100644 --- a/apt-pkg/acquire-item.cc +++ b/apt-pkg/acquire-item.cc @@ -1041,8 +1041,8 @@ bool pkgAcqMetaBase::VerifyVendor(string const &Message) /*{{{*/ Transformed = ""; } - if (_config->FindB("Acquire::Check-Valid-Until", true) == true && - TransactionManager->MetaIndexParser->GetValidUntil() > 0) { + if (TransactionManager->MetaIndexParser->GetValidUntil() > 0) + { time_t const invalid_since = time(NULL) - TransactionManager->MetaIndexParser->GetValidUntil(); if (invalid_since > 0) { diff --git a/apt-pkg/deb/debmetaindex.cc b/apt-pkg/deb/debmetaindex.cc index f0b859eb4..5d7e539c7 100644 --- a/apt-pkg/deb/debmetaindex.cc +++ b/apt-pkg/deb/debmetaindex.cc @@ -44,7 +44,11 @@ class APT_HIDDEN debReleaseIndexPrivate /*{{{*/ std::vector<debSectionEntry> DebEntries; std::vector<debSectionEntry> DebSrcEntries; - debReleaseIndexPrivate() {} + metaIndex::TriState CheckValidUntil; + time_t ValidUntilMin; + time_t ValidUntilMax; + + debReleaseIndexPrivate() : CheckValidUntil(metaIndex::TRI_UNSET), ValidUntilMin(0), ValidUntilMax(0) {} }; /*}}}*/ // ReleaseIndex::MetaIndex* - display helpers /*{{{*/ @@ -283,43 +287,56 @@ bool debReleaseIndex::Load(std::string const &Filename, std::string * const Erro return false; } - std::string const Label = Section.FindS("Label"); - std::string const StrValidUntil = Section.FindS("Valid-Until"); + bool CheckValidUntil = _config->FindB("Acquire::Check-Valid-Until", true); + if (d->CheckValidUntil == metaIndex::TRI_NO) + CheckValidUntil = false; + else if (d->CheckValidUntil == metaIndex::TRI_YES) + CheckValidUntil = true; - // if we have a Valid-Until header in the Release file, use it as default - if (StrValidUntil.empty() == false) + if (CheckValidUntil == true) { - if(RFC1123StrToTime(StrValidUntil.c_str(), ValidUntil) == false) + std::string const Label = Section.FindS("Label"); + std::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) { - if (ErrorText != NULL) - strprintf(*ErrorText, _("Invalid 'Valid-Until' entry in Release file %s"), Filename.c_str()); - return false; + if(RFC1123StrToTime(StrValidUntil.c_str(), ValidUntil) == false) + { + if (ErrorText != NULL) + strprintf(*ErrorText, _("Invalid 'Valid-Until' entry in Release file %s"), Filename.c_str()); + return false; + } + } + // get the user settings for this archive and use what expires earlier + time_t MaxAge = d->ValidUntilMax; + if (MaxAge == 0) + { + MaxAge = _config->FindI("Acquire::Max-ValidTime", 0); + if (Label.empty() == false) + MaxAge = _config->FindI(("Acquire::Max-ValidTime::" + Label).c_str(), MaxAge); + } + time_t MinAge = d->ValidUntilMin; + if (MinAge == 0) + { + MinAge = _config->FindI("Acquire::Min-ValidTime", 0); + if (Label.empty() == false) + MinAge = _config->FindI(("Acquire::Min-ValidTime::" + Label).c_str(), MinAge); } - } - // get the user settings for this archive and use what expires earlier - int MaxAge = _config->FindI("Acquire::Max-ValidTime", 0); - if (Label.empty() == false) - MaxAge = _config->FindI(("Acquire::Max-ValidTime::" + Label).c_str(), MaxAge); - int MinAge = _config->FindI("Acquire::Min-ValidTime", 0); - if (Label.empty() == false) - MinAge = _config->FindI(("Acquire::Min-ValidTime::" + Label).c_str(), MinAge); - - LoadedSuccessfully = TRI_YES; - if(MaxAge == 0 && - (MinAge == 0 || ValidUntil == 0)) // No user settings, use the one from the Release file - return true; - if (MinAge != 0 && ValidUntil != 0) { - time_t const min_date = Date + MinAge; - if (ValidUntil < min_date) - ValidUntil = min_date; - } - if (MaxAge != 0) { - time_t const max_date = Date + MaxAge; - if (ValidUntil == 0 || ValidUntil > max_date) - ValidUntil = max_date; + if (MinAge != 0 && ValidUntil != 0) { + time_t const min_date = Date + MinAge; + if (ValidUntil < min_date) + ValidUntil = min_date; + } + if (MaxAge != 0) { + time_t const max_date = Date + MaxAge; + if (ValidUntil == 0 || ValidUntil > max_date) + ValidUntil = max_date; + } } + LoadedSuccessfully = TRI_YES; return true; } /*}}}*/ @@ -411,7 +428,7 @@ bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool const &GetAll)/*{{{*/ return true; } /*}}}*/ -// ReleaseIndex::IsTrusted /*{{{*/ +// ReleaseIndex::Set* TriState options /*{{{*/ bool debReleaseIndex::SetTrusted(TriState const pTrusted) { if (Trusted == TRI_UNSET) @@ -421,6 +438,32 @@ bool debReleaseIndex::SetTrusted(TriState const pTrusted) return _error->Error(_("Conflicting values set for option %s concerning source %s %s"), "Trusted", URI.c_str(), Dist.c_str()); return true; } +bool debReleaseIndex::SetCheckValidUntil(TriState const pCheckValidUntil) +{ + if (d->CheckValidUntil == TRI_UNSET) + d->CheckValidUntil = pCheckValidUntil; + else if (d->CheckValidUntil != pCheckValidUntil) + return _error->Error(_("Conflicting values set for option %s concerning source %s %s"), "Check-Valid-Until", URI.c_str(), Dist.c_str()); + return true; +} +bool debReleaseIndex::SetValidUntilMin(time_t const Valid) +{ + if (d->ValidUntilMin == 0) + d->ValidUntilMin = Valid; + else if (d->ValidUntilMin != Valid) + return _error->Error(_("Conflicting values set for option %s concerning source %s %s"), "Min-ValidTime", URI.c_str(), Dist.c_str()); + return true; +} +bool debReleaseIndex::SetValidUntilMax(time_t const Valid) +{ + if (d->ValidUntilMax == 0) + d->ValidUntilMax = Valid; + else if (d->ValidUntilMax != Valid) + return _error->Error(_("Conflicting values set for option %s concerning source %s %s"), "Max-ValidTime", URI.c_str(), Dist.c_str()); + return true; +} + /*}}}*/ +// ReleaseIndex::IsTrusted /*{{{*/ bool debReleaseIndex::IsTrusted() const { if (Trusted == TRI_YES) @@ -601,6 +644,22 @@ static std::vector<std::string> parsePlusMinusOptions(std::string const &Name, / /*}}}*/ class APT_HIDDEN debSLTypeDebian : public pkgSourceList::Type /*{{{*/ { + metaIndex::TriState GetTriStateOption(std::map<std::string, std::string>const &Options, char const * const name) const + { + std::map<std::string, std::string>::const_iterator const opt = Options.find(name); + if (opt != Options.end()) + return StringToBool(opt->second, false) ? metaIndex::TRI_YES : metaIndex::TRI_NO; + return metaIndex::TRI_DONTCARE; + } + + time_t GetTimeOption(std::map<std::string, std::string>const &Options, char const * const name) const + { + std::map<std::string, std::string>::const_iterator const opt = Options.find(name); + if (opt == Options.end()) + return 0; + return strtoull(opt->second.c_str(), NULL, 10); + } + protected: bool CreateItemInternal(std::vector<metaIndex *> &List, std::string const &URI, @@ -641,13 +700,10 @@ class APT_HIDDEN debSLTypeDebian : public pkgSourceList::Type /*{{{*/ parsePlusMinusOptions("lang", Options, APT::Configuration::getLanguages(true)) ); - std::map<std::string, std::string>::const_iterator const trusted = Options.find("trusted"); - if (trusted != Options.end()) - { - if (Deb->SetTrusted(StringToBool(trusted->second, false) ? debReleaseIndex::TRI_YES : debReleaseIndex::TRI_NO) == false) - return false; - } - else if (Deb->SetTrusted(debReleaseIndex::TRI_DONTCARE) == false) + if (Deb->SetTrusted(GetTriStateOption(Options, "trusted")) == false || + Deb->SetCheckValidUntil(GetTriStateOption(Options, "check-valid-until")) == false || + Deb->SetValidUntilMax(GetTimeOption(Options, "valid-until-max")) == false || + Deb->SetValidUntilMin(GetTimeOption(Options, "valid-until-min")) == false) return false; return true; diff --git a/apt-pkg/deb/debmetaindex.h b/apt-pkg/deb/debmetaindex.h index 19fe6806c..879eb3bfc 100644 --- a/apt-pkg/deb/debmetaindex.h +++ b/apt-pkg/deb/debmetaindex.h @@ -53,6 +53,9 @@ class APT_HIDDEN debReleaseIndex : public metaIndex virtual std::vector <pkgIndexFile *> *GetIndexFiles(); bool SetTrusted(TriState const Trusted); + bool SetCheckValidUntil(TriState const Trusted); + bool SetValidUntilMin(time_t const Valid); + bool SetValidUntilMax(time_t const Valid); virtual bool IsTrusted() const; diff --git a/apt-pkg/sourcelist.cc b/apt-pkg/sourcelist.cc index 0502f0e1d..0d65558ed 100644 --- a/apt-pkg/sourcelist.cc +++ b/apt-pkg/sourcelist.cc @@ -103,6 +103,9 @@ bool pkgSourceList::Type::ParseStanza(vector<metaIndex *> &List, /*{{{*/ APT_PLUSMINUS("Targets", "target"); #undef APT_PLUSMINUS mapping.insert(std::make_pair("Trusted", "trusted")); + mapping.insert(std::make_pair("Check-Valid-Until", "check-valid-until")); + mapping.insert(std::make_pair("Valid-Until-Min", "valid-until-min")); + mapping.insert(std::make_pair("Valid-Until-Max", "valid-until-max")); for (std::map<char const * const, char const * const>::const_iterator m = mapping.begin(); m != mapping.end(); ++m) if (Tags.Exists(m->first)) diff --git a/doc/apt-get.8.xml b/doc/apt-get.8.xml index 5b6788ed4..b0fe390df 100644 --- a/doc/apt-get.8.xml +++ b/doc/apt-get.8.xml @@ -531,9 +531,13 @@ </varlistentry> <varlistentry><term><option>--allow-unauthenticated</option></term> - <listitem><para>Ignore if packages can't be authenticated and don't prompt about it. - This is useful for tools like pbuilder. - Configuration Item: <literal>APT::Get::AllowUnauthenticated</literal>.</para></listitem> + <listitem><para>Ignore if packages can't be authenticated and don't prompt + about it. This can be useful while working with local repositories, + but is a huge security risk if data authenticity isn't ensured in + another way by the user itself. The usage of the + <option>Trusted</option> option for &sources-list; entries should + usually be preferred over this global override. Configuration Item: + <literal>APT::Get::AllowUnauthenticated</literal>.</para></listitem> </varlistentry> <varlistentry><term><option>--no-allow-insecure-repositories</option></term> diff --git a/doc/apt.conf.5.xml b/doc/apt.conf.5.xml index 7d5f7e9b3..103d0622c 100644 --- a/doc/apt.conf.5.xml +++ b/doc/apt.conf.5.xml @@ -301,6 +301,8 @@ DPkg::Pre-Install-Pkgs {"/usr/sbin/dpkg-preconfigure --apt";}; <literal>Valid-Until</literal> header, but if they don't or a stricter value is desired the <literal>Max-ValidTime</literal> option below can be used. + The <option>Check-Valid-Until</option> option of &sources-list; entries should be + preferred to disable the check selectively instead of using this global override. </para></listitem> </varlistentry> @@ -312,7 +314,8 @@ DPkg::Pre-Install-Pkgs {"/usr/sbin/dpkg-preconfigure --apt";}; the earlier date of the two is used as the expiration date. The default value is <literal>0</literal> which stands for "valid forever". Archive specific settings can be made by appending the label of the archive - to the option name. + to the option name. Preferably, the same can be achieved for specific + &sources-list; entries by using the <option>Valid-Until-Max</option> option there. </para></listitem> </varlistentry> @@ -324,7 +327,8 @@ DPkg::Pre-Install-Pkgs {"/usr/sbin/dpkg-preconfigure --apt";}; frequently updated archive with a <literal>Valid-Until</literal> header instead of completely disabling the expiration date checking. Archive specific settings can and should be used by appending the label of - the archive to the option name. + the archive to the option name. Preferably, the same can be achieved for specific + &sources-list; entries by using the <option>Valid-Until-Min</option> option there. </para></listitem> </varlistentry> diff --git a/doc/sources.list.5.xml b/doc/sources.list.5.xml index f87dcda23..aded8ecef 100644 --- a/doc/sources.list.5.xml +++ b/doc/sources.list.5.xml @@ -202,26 +202,26 @@ deb-src [ option1=value1 option2=value2 ] uri suite [component1] [component2] [. APT versions. <itemizedlist> - <listitem><para><literal>Architectures</literal> - (<literal>arch</literal>) is a multivalue option defining for + <listitem><para><option>Architectures</option> + (<option>arch</option>) is a multivalue option defining for which architectures information should be downloaded. If this option isn't set the default is all architectures as defined by - the <literal>APT::Architectures</literal> config option. + the <option>APT::Architectures</option> config option. </para></listitem> - <listitem><para><literal>Languages</literal> - (<literal>lang</literal>) is a multivalue option defining for + <listitem><para><option>Languages</option> + (<option>lang</option>) is a multivalue option defining for which languages information like translated package descriptions should be downloaded. If this option isn't set the default is all languages as defined by the - <literal>Acquire::Languages</literal> config option. + <option>Acquire::Languages</option> config option. </para></listitem> - <listitem><para><literal>Targets</literal> - (<literal>target</literal>) is a multivalue option defining + <listitem><para><option>Targets</option> + (<option>target</option>) is a multivalue option defining which download targets apt will try to acquire from this source. If not specified, the default set is defined by the - <literal>APT::Acquire::Targets</literal> configuration scope. + <option>APT::Acquire::Targets</option> configuration scope. </para></listitem> </itemizedlist> @@ -232,7 +232,7 @@ deb-src [ option1=value1 option2=value2 ] uri suite [component1] [component2] [. anomalies. <itemizedlist> - <listitem><para><literal>Trusted</literal> (<literal>trusted</literal>) + <listitem><para><option>Trusted</option> (<option>trusted</option>) is a tri-state value which defaults to APT deciding if a source is considered trusted or if warnings should be raised before e.g. packages are installed from this source. This option can be used @@ -245,6 +245,41 @@ deb-src [ option1=value1 option2=value2 ] uri suite [component1] [component2] [. as untrusted even if the authentication checks passed successfully. The default value can't be set explicitly. </para></listitem> + + <listitem><para><option>Check-Valid-Until</option> (<option>check-valid-until</option>) + is a yes/no value which controls if APT should try to detect + replay attacks. A repository creator can declare until then the + data provided in the repository should be considered valid and + if this time is reached, but no new data is provided the data + is considered expired and an error is raised. Beside + increasing security as a malicious attacker can't sent old data + forever denying a user to be able to upgrade to a new version, + this also helps users identify mirrors which are no longer + updated. Some repositories like historic archives aren't + updated anymore by design through, so this check can be + disabled by setting this option to <literal>no</literal>. + Defaults to the value of configuration option + <option>Acquire::Check-Valid-Until</option> which itself + defaults to <literal>yes</literal>. + </para></listitem> + + <listitem><para><option>Valid-Until-Min</option> + (<option>check-valid-min</option>) and + <option>Valid-Until-Max</option> + (<option>valid-until-max</option>) can be used to raise or + lower the time period in seconds in which the data from this + repository is considered valid. -Max can be especially useful + if the repository provides no Valid-Until field on its Release + file to set your own value, while -Min can be used to increase + the valid time on seldomly updated (local) mirrors of a more + frequently updated but less accessible archive (which is in the + sources.list as well) instead of disabling the check entirely. + Default to the value of the configuration options + <option>Acquire::Min-ValidTime</option> and + <option>Acquire::Max-ValidTime</option> which are both unset by + default. + </para></listitem> + </itemizedlist> </para> diff --git a/test/integration/test-releasefile-valid-until b/test/integration/test-releasefile-valid-until index e000abf5d..43574ec3e 100755 --- a/test/integration/test-releasefile-valid-until +++ b/test/integration/test-releasefile-valid-until @@ -46,3 +46,12 @@ runtest 'accepted' 'good Min-Valid (bad Until, good Max-Valid) <' 'now - 7 days' 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 + +sed -i -e 's#\(deb\(-src\)\?\) #\1 [check-valid-until=no] #' rootdir/etc/apt/sources.list.d/* +runtest 'accepted' 'bad Until but overriden by sources option' 'now - 7 days' 'now - 4 days' + +sed -i -e 's#\(deb\(-src\)\?\) \[check-valid-until=no\] #\1 [valid-until-max=86400] #' rootdir/etc/apt/sources.list.d/* +runtest 'rejected' 'bad Max-Valid (good Until) via sources option' 'now - 7 days' 'now + 4 days' + +sed -i -e 's#\(deb\(-src\)\?\) \[valid-until-max=86400\] #\1 [valid-until-min=1209600] #' rootdir/etc/apt/sources.list.d/* +runtest 'accepted' 'good Min-Valid (bad Until) via sources option' 'now - 7 days' 'now - 4 days' |