Просмотр исходного кода

add insecure (and weak) allow-options for sources.list

Weak had no dedicated option before and Insecure and Downgrade were both
global options, which given the effect they all have on security is
rather bad. Setting them for individual repositories only isn't great
but at least slightly better and also more consistent with other
settings for repositories.
David Kalnischkies лет назад: 10
Родитель
Сommit
d03b947b0c

+ 43 - 9
apt-pkg/acquire-item.cc

@@ -175,7 +175,7 @@ static void ReportMirrorFailureToCentral(pkgAcquire::Item const &I, std::string
 }
 }
 									/*}}}*/
 									/*}}}*/
 
 
-static bool MessageInsecureRepository(bool const isError, char const * const msg, std::string const &repo)/*{{{*/
+static APT_NONNULL(2) bool MessageInsecureRepository(bool const isError, char const * const msg, std::string const &repo)/*{{{*/
 {
 {
    std::string m;
    std::string m;
    strprintf(m, msg, repo.c_str());
    strprintf(m, msg, repo.c_str());
@@ -195,7 +195,28 @@ static bool MessageInsecureRepository(bool const isError, char const * const msg
 									/*}}}*/
 									/*}}}*/
 // AllowInsecureRepositories						/*{{{*/
 // AllowInsecureRepositories						/*{{{*/
 enum class InsecureType { UNSIGNED, WEAK, NORELEASE };
 enum class InsecureType { UNSIGNED, WEAK, NORELEASE };
-static bool APT_NONNULL(3, 4, 5) AllowInsecureRepositories(InsecureType msg, std::string const &repo,
+static bool TargetIsAllowedToBe(IndexTarget const &Target, InsecureType const type)
+{
+   if (_config->FindB("Acquire::AllowInsecureRepositories"))
+      return true;
+
+   if (Target.OptionBool(IndexTarget::ALLOW_INSECURE))
+      return true;
+
+   switch (type)
+   {
+      case InsecureType::UNSIGNED: break;
+      case InsecureType::NORELEASE: break;
+      case InsecureType::WEAK:
+	 if (_config->FindB("Acquire::AllowWeakRepositories"))
+	    return true;
+	 if (Target.OptionBool(IndexTarget::ALLOW_WEAK))
+	    return true;
+	 break;
+   }
+   return false;
+}
+static bool APT_NONNULL(3, 4, 5) AllowInsecureRepositories(InsecureType const msg, std::string const &repo,
       metaIndex const * const MetaIndexParser, pkgAcqMetaClearSig * const TransactionManager, pkgAcquire::Item * const I)
       metaIndex const * const MetaIndexParser, pkgAcqMetaClearSig * const TransactionManager, pkgAcquire::Item * const I)
 {
 {
    // we skip weak downgrades as its unlikely that a repository gets really weaker –
    // we skip weak downgrades as its unlikely that a repository gets really weaker –
@@ -213,7 +234,8 @@ static bool APT_NONNULL(3, 4, 5) AllowInsecureRepositories(InsecureType msg, std
 	    case InsecureType::NORELEASE: msgstr = _("The repository '%s' does no longer have a Release file."); break;
 	    case InsecureType::NORELEASE: msgstr = _("The repository '%s' does no longer have a Release file."); break;
 	    case InsecureType::WEAK: /* unreachable */ break;
 	    case InsecureType::WEAK: /* unreachable */ break;
 	 }
 	 }
-	 if (_config->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
+	 if (_config->FindB("Acquire::AllowDowngradeToInsecureRepositories") ||
+	       TransactionManager->Target.OptionBool(IndexTarget::ALLOW_DOWNGRADE_TO_INSECURE))
 	 {
 	 {
 	    // meh, the users wants to take risks (we still mark the packages
 	    // meh, the users wants to take risks (we still mark the packages
 	    // from this repository as unauthenticated)
 	    // from this repository as unauthenticated)
@@ -241,7 +263,7 @@ static bool APT_NONNULL(3, 4, 5) AllowInsecureRepositories(InsecureType msg, std
       case InsecureType::WEAK: msgstr = _("The repository '%s' provides only weak security information."); break;
       case InsecureType::WEAK: msgstr = _("The repository '%s' provides only weak security information."); break;
    }
    }
 
 
-   if (_config->FindB("Acquire::AllowInsecureRepositories") == true)
+   if (TargetIsAllowedToBe(TransactionManager->Target, msg) == true)
    {
    {
       MessageInsecureRepository(false, msgstr, repo);
       MessageInsecureRepository(false, msgstr, repo);
       return true;
       return true;
@@ -277,7 +299,20 @@ APT_CONST bool pkgAcqTransactionItem::HashesRequired() const
       we can at least trust them for integrity of the download itself.
       we can at least trust them for integrity of the download itself.
       Only repositories without a Release file can (obviously) not have
       Only repositories without a Release file can (obviously) not have
       hashes – and they are very uncommon and strongly discouraged */
       hashes – and they are very uncommon and strongly discouraged */
-   return TransactionManager->MetaIndexParser->GetLoadedSuccessfully() == metaIndex::TRI_YES;
+   if (TransactionManager->MetaIndexParser->GetLoadedSuccessfully() != metaIndex::TRI_YES)
+      return false;
+   if (TargetIsAllowedToBe(Target, InsecureType::WEAK))
+   {
+      /* If we allow weak hashes, we check that we have some (weak) and then
+         declare hashes not needed. That will tip us in the right direction
+	 as if hashes exist, they will be used, even if not required */
+      auto const hsl = GetExpectedHashes();
+      if (hsl.usable())
+	 return true;
+      if (hsl.empty() == false)
+	 return false;
+   }
+   return true;
 }
 }
 HashStringList pkgAcqTransactionItem::GetExpectedHashes() const
 HashStringList pkgAcqTransactionItem::GetExpectedHashes() const
 {
 {
@@ -1333,7 +1368,7 @@ void pkgAcqMetaClearSig::QueueIndexes(bool const verify)			/*{{{*/
 	    auto const hashes = GetExpectedHashesFor(Target.MetaKey);
 	    auto const hashes = GetExpectedHashesFor(Target.MetaKey);
 	    if (hashes.empty() == false)
 	    if (hashes.empty() == false)
 	    {
 	    {
-	       if (hashes.usable() == false)
+	       if (hashes.usable() == false && TargetIsAllowedToBe(TransactionManager->Target, InsecureType::WEAK) == false)
 	       {
 	       {
 		  new CleanupItem(Owner, TransactionManager, Target);
 		  new CleanupItem(Owner, TransactionManager, Target);
 		  _error->Warning(_("Skipping acquire of configured file '%s' as repository '%s' provides only weak security information for it"),
 		  _error->Warning(_("Skipping acquire of configured file '%s' as repository '%s' provides only weak security information for it"),
@@ -1525,8 +1560,7 @@ pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire * const Owner,	/*{{{*/
       IndexTarget const &DetachedDataTarget, IndexTarget const &DetachedSigTarget,
       IndexTarget const &DetachedDataTarget, IndexTarget const &DetachedSigTarget,
       metaIndex * const MetaIndexParser) :
       metaIndex * const MetaIndexParser) :
    pkgAcqMetaIndex(Owner, this, ClearsignedTarget, DetachedSigTarget),
    pkgAcqMetaIndex(Owner, this, ClearsignedTarget, DetachedSigTarget),
-   d(NULL), ClearsignedTarget(ClearsignedTarget),
-   DetachedDataTarget(DetachedDataTarget),
+   d(NULL), DetachedDataTarget(DetachedDataTarget),
    MetaIndexParser(MetaIndexParser), LastMetaIndexParser(NULL)
    MetaIndexParser(MetaIndexParser), LastMetaIndexParser(NULL)
 {
 {
    // index targets + (worst case:) Release/Release.gpg
    // index targets + (worst case:) Release/Release.gpg
@@ -1640,7 +1674,7 @@ void pkgAcqMetaClearSig::Failed(string const &Message,pkgAcquire::MethodConfig c
       if(CheckStopAuthentication(this, Message))
       if(CheckStopAuthentication(this, Message))
          return;
          return;
 
 
-      if(AllowInsecureRepositories(InsecureType::UNSIGNED, ClearsignedTarget.Description, TransactionManager->MetaIndexParser, TransactionManager, this) == true)
+      if(AllowInsecureRepositories(InsecureType::UNSIGNED, Target.Description, TransactionManager->MetaIndexParser, TransactionManager, this) == true)
       {
       {
 	 Status = StatDone;
 	 Status = StatDone;
 
 

+ 2 - 3
apt-pkg/acquire-item.h

@@ -368,12 +368,13 @@ class APT_HIDDEN pkgAcqTransactionItem: public pkgAcquire::Item		/*{{{*/
 {
 {
    void * const d;
    void * const d;
    protected:
    protected:
-   IndexTarget const Target;
    HashStringList GetExpectedHashesFor(std::string const &MetaKey) const;
    HashStringList GetExpectedHashesFor(std::string const &MetaKey) const;
 
 
    bool QueueURI(pkgAcquire::ItemDesc &Item) APT_OVERRIDE;
    bool QueueURI(pkgAcquire::ItemDesc &Item) APT_OVERRIDE;
 
 
    public:
    public:
+   IndexTarget const Target;
+
    /** \brief storge name until a transaction is finished */
    /** \brief storge name until a transaction is finished */
    std::string PartialFile;
    std::string PartialFile;
 
 
@@ -559,8 +560,6 @@ class APT_HIDDEN pkgAcqMetaSig : public pkgAcqTransactionItem
 class APT_HIDDEN pkgAcqMetaClearSig : public pkgAcqMetaIndex
 class APT_HIDDEN pkgAcqMetaClearSig : public pkgAcqMetaIndex
 {
 {
    void * const d;
    void * const d;
-
-   IndexTarget const ClearsignedTarget;
    IndexTarget const DetachedDataTarget;
    IndexTarget const DetachedDataTarget;
 
 
  public:
  public:

+ 5 - 11
apt-pkg/acquire-worker.cc

@@ -378,6 +378,7 @@ bool pkgAcquire::Worker::RunMessages()
 
 
 	    bool const isIMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false) ||
 	    bool const isIMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false) ||
 	       StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false);
 	       StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false);
+	    auto const forcedHash = _config->Find("Acquire::ForceHash");
 	    for (auto const Owner: ItmOwners)
 	    for (auto const Owner: ItmOwners)
 	    {
 	    {
 	       HashStringList const ExpectedHashes = Owner->GetExpectedHashes();
 	       HashStringList const ExpectedHashes = Owner->GetExpectedHashes();
@@ -395,9 +396,10 @@ bool pkgAcquire::Worker::RunMessages()
 
 
 	       // decide if what we got is what we expected
 	       // decide if what we got is what we expected
 	       bool consideredOkay = false;
 	       bool consideredOkay = false;
-	       if (ExpectedHashes.usable())
+	       if ((forcedHash.empty() && ExpectedHashes.empty() == false) ||
+		     (forcedHash.empty() == false && ExpectedHashes.usable()))
 	       {
 	       {
-		  if (ReceivedHashes.usable() == false)
+		  if (ReceivedHashes.empty())
 		  {
 		  {
 		     /* IMS-Hits can't be checked here as we will have uncompressed file,
 		     /* IMS-Hits can't be checked here as we will have uncompressed file,
 			but the hashes for the compressed file. What we have was good through
 			but the hashes for the compressed file. What we have was good through
@@ -410,16 +412,8 @@ bool pkgAcquire::Worker::RunMessages()
 		     consideredOkay = false;
 		     consideredOkay = false;
 
 
 	       }
 	       }
-	       else if (Owner->HashesRequired() == true)
-		  consideredOkay = false;
 	       else
 	       else
-	       {
-		  consideredOkay = true;
-		  // even if the hashes aren't usable to declare something secure
-		  // we can at least use them to declare it an integrity failure
-		  if (ExpectedHashes.empty() == false && ReceivedHashes != ExpectedHashes && _config->Find("Acquire::ForceHash").empty())
-		     consideredOkay = false;
-	       }
+		  consideredOkay = !Owner->HashesRequired();
 
 
 	       if (consideredOkay == true)
 	       if (consideredOkay == true)
 		  consideredOkay = Owner->VerifyDone(Message, Config);
 		  consideredOkay = Owner->VerifyDone(Message, Config);

+ 87 - 31
apt-pkg/deb/debmetaindex.cc

@@ -51,8 +51,9 @@ class APT_HIDDEN debReleaseIndexPrivate					/*{{{*/
 
 
    std::vector<std::string> Architectures;
    std::vector<std::string> Architectures;
    std::vector<std::string> NoSupportForAll;
    std::vector<std::string> NoSupportForAll;
+   std::map<std::string, std::string> const ReleaseOptions;
 
 
-   debReleaseIndexPrivate() : CheckValidUntil(metaIndex::TRI_UNSET), ValidUntilMin(0), ValidUntilMax(0) {}
+   debReleaseIndexPrivate(std::map<std::string, std::string> const &Options) : CheckValidUntil(metaIndex::TRI_UNSET), ValidUntilMin(0), ValidUntilMax(0), ReleaseOptions(Options) {}
 };
 };
 									/*}}}*/
 									/*}}}*/
 // ReleaseIndex::MetaIndex* - display helpers				/*{{{*/
 // ReleaseIndex::MetaIndex* - display helpers				/*{{{*/
@@ -96,11 +97,11 @@ std::string debReleaseIndex::MetaIndexURI(const char *Type) const
 }
 }
 									/*}}}*/
 									/*}}}*/
 // ReleaseIndex Con- and Destructors					/*{{{*/
 // ReleaseIndex Con- and Destructors					/*{{{*/
-debReleaseIndex::debReleaseIndex(std::string const &URI, std::string const &Dist) :
-					metaIndex(URI, Dist, "deb"), d(new debReleaseIndexPrivate())
+debReleaseIndex::debReleaseIndex(std::string const &URI, std::string const &Dist, std::map<std::string, std::string> const &Options) :
+					metaIndex(URI, Dist, "deb"), d(new debReleaseIndexPrivate(Options))
 {}
 {}
-debReleaseIndex::debReleaseIndex(std::string const &URI, std::string const &Dist, bool const pTrusted) :
-					metaIndex(URI, Dist, "deb"), d(new debReleaseIndexPrivate())
+debReleaseIndex::debReleaseIndex(std::string const &URI, std::string const &Dist, bool const pTrusted, std::map<std::string, std::string> const &Options) :
+					metaIndex(URI, Dist, "deb"), d(new debReleaseIndexPrivate(Options))
 {
 {
    Trusted = pTrusted ? TRI_YES : TRI_NO;
    Trusted = pTrusted ? TRI_YES : TRI_NO;
 }
 }
@@ -112,17 +113,10 @@ debReleaseIndex::~debReleaseIndex() {
 // ReleaseIndex::GetIndexTargets					/*{{{*/
 // ReleaseIndex::GetIndexTargets					/*{{{*/
 static void GetIndexTargetsFor(char const * const Type, std::string const &URI, std::string const &Dist,
 static void GetIndexTargetsFor(char const * const Type, std::string const &URI, std::string const &Dist,
       std::vector<debReleaseIndexPrivate::debSectionEntry> const &entries,
       std::vector<debReleaseIndexPrivate::debSectionEntry> const &entries,
-      std::vector<IndexTarget> &IndexTargets)
+      std::vector<IndexTarget> &IndexTargets, std::map<std::string, std::string> const &ReleaseOptions)
 {
 {
    bool const flatArchive = (Dist[Dist.length() - 1] == '/');
    bool const flatArchive = (Dist[Dist.length() - 1] == '/');
-   std::string baseURI = URI;
-   if (flatArchive)
-   {
-      if (Dist != "/")
-         baseURI += Dist;
-   }
-   else
-      baseURI += "dists/" + Dist + "/";
+   std::string const baseURI = constructMetaIndexURI(URI, Dist, "");
    std::string const Release = (Dist == "/") ? "" : Dist;
    std::string const Release = (Dist == "/") ? "" : Dist;
    std::string const Site = ::URI::ArchiveOnly(URI);
    std::string const Site = ::URI::ArchiveOnly(URI);
 
 
@@ -292,8 +286,7 @@ static void GetIndexTargetsFor(char const * const Type, std::string const &URI,
 		  }
 		  }
 
 
 		  // not available in templates, but in the indextarget
 		  // not available in templates, but in the indextarget
-		  Options.insert(std::make_pair("BASE_URI", baseURI));
-		  Options.insert(std::make_pair("REPO_URI", URI));
+		  Options.insert(ReleaseOptions.begin(), ReleaseOptions.end());
 		  Options.insert(std::make_pair("IDENTIFIER", Identifier));
 		  Options.insert(std::make_pair("IDENTIFIER", Identifier));
 		  Options.insert(std::make_pair("TARGET_OF", Type));
 		  Options.insert(std::make_pair("TARGET_OF", Type));
 		  Options.insert(std::make_pair("CREATED_BY", *T));
 		  Options.insert(std::make_pair("CREATED_BY", *T));
@@ -317,7 +310,7 @@ static void GetIndexTargetsFor(char const * const Type, std::string const &URI,
 			MetaKey,
 			MetaKey,
 			ShortDesc,
 			ShortDesc,
 			LongDesc,
 			LongDesc,
-			Options.find("BASE_URI")->second + MetaKey,
+			baseURI + MetaKey,
 			IsOpt,
 			IsOpt,
 			KeepCompressed,
 			KeepCompressed,
 			Options
 			Options
@@ -344,8 +337,8 @@ static void GetIndexTargetsFor(char const * const Type, std::string const &URI,
 std::vector<IndexTarget> debReleaseIndex::GetIndexTargets() const
 std::vector<IndexTarget> debReleaseIndex::GetIndexTargets() const
 {
 {
    std::vector<IndexTarget> IndexTargets;
    std::vector<IndexTarget> IndexTargets;
-   GetIndexTargetsFor("deb-src", URI, Dist, d->DebSrcEntries, IndexTargets);
-   GetIndexTargetsFor("deb", URI, Dist, d->DebEntries, IndexTargets);
+   GetIndexTargetsFor("deb-src", URI, Dist, d->DebSrcEntries, IndexTargets, d->ReleaseOptions);
+   GetIndexTargetsFor("deb", URI, Dist, d->DebEntries, IndexTargets, d->ReleaseOptions);
    return IndexTargets;
    return IndexTargets;
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -542,11 +535,11 @@ bool debReleaseIndex::Load(std::string const &Filename, std::string * const Erro
 metaIndex * debReleaseIndex::UnloadedClone() const			/*{{{*/
 metaIndex * debReleaseIndex::UnloadedClone() const			/*{{{*/
 {
 {
    if (Trusted == TRI_NO)
    if (Trusted == TRI_NO)
-      return new debReleaseIndex(URI, Dist, false);
+      return new debReleaseIndex(URI, Dist, false, d->ReleaseOptions);
    else if (Trusted == TRI_YES)
    else if (Trusted == TRI_YES)
-      return new debReleaseIndex(URI, Dist, true);
+      return new debReleaseIndex(URI, Dist, true, d->ReleaseOptions);
    else
    else
-      return new debReleaseIndex(URI, Dist);
+      return new debReleaseIndex(URI, Dist, d->ReleaseOptions);
 }
 }
 									/*}}}*/
 									/*}}}*/
 bool debReleaseIndex::parseSumData(const char *&Start, const char *End,	/*{{{*/
 bool debReleaseIndex::parseSumData(const char *&Start, const char *End,	/*{{{*/
@@ -611,7 +604,7 @@ bool debReleaseIndex::parseSumData(const char *&Start, const char *End,	/*{{{*/
 
 
 bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool const &GetAll)/*{{{*/
 bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool const &GetAll)/*{{{*/
 {
 {
-#define APT_TARGET(X) IndexTarget("", X, MetaIndexInfo(X), MetaIndexURI(X), false, false, std::map<std::string,std::string>())
+#define APT_TARGET(X) IndexTarget("", X, MetaIndexInfo(X), MetaIndexURI(X), false, false, d->ReleaseOptions)
    pkgAcqMetaClearSig * const TransactionManager = new pkgAcqMetaClearSig(Owner,
    pkgAcqMetaClearSig * const TransactionManager = new pkgAcqMetaClearSig(Owner,
 	 APT_TARGET("InRelease"), APT_TARGET("Release"), APT_TARGET("Release.gpg"), this);
 	 APT_TARGET("InRelease"), APT_TARGET("Release"), APT_TARGET("Release.gpg"), this);
 #undef APT_TARGET
 #undef APT_TARGET
@@ -751,6 +744,10 @@ std::vector <pkgIndexFile *> *debReleaseIndex::GetIndexFiles()		/*{{{*/
    return Indexes;
    return Indexes;
 }
 }
 									/*}}}*/
 									/*}}}*/
+std::map<std::string, std::string> debReleaseIndex::GetReleaseOptions()
+{
+   return d->ReleaseOptions;
+}
 
 
 static bool ReleaseFileName(debReleaseIndex const * const That, std::string &ReleaseFile)/*{{{*/
 static bool ReleaseFileName(debReleaseIndex const * const That, std::string &ReleaseFile)/*{{{*/
 {
 {
@@ -900,7 +897,7 @@ class APT_HIDDEN debSLTypeDebian : public pkgSourceList::Type		/*{{{*/
       return metaIndex::TRI_DONTCARE;
       return metaIndex::TRI_DONTCARE;
    }
    }
 
 
-   time_t GetTimeOption(std::map<std::string, std::string>const &Options, char const * const name) const
+   static time_t GetTimeOption(std::map<std::string, std::string>const &Options, char const * const name)
    {
    {
       std::map<std::string, std::string>::const_iterator const opt = Options.find(name);
       std::map<std::string, std::string>::const_iterator const opt = Options.find(name);
       if (opt == Options.end())
       if (opt == Options.end())
@@ -908,12 +905,74 @@ class APT_HIDDEN debSLTypeDebian : public pkgSourceList::Type		/*{{{*/
       return strtoull(opt->second.c_str(), NULL, 10);
       return strtoull(opt->second.c_str(), NULL, 10);
    }
    }
 
 
+   static bool GetBoolOption(std::map<std::string, std::string> const &Options, char const * const name, bool const defVal)
+   {
+      std::map<std::string, std::string>::const_iterator const opt = Options.find(name);
+      if (opt == Options.end())
+	 return defVal;
+      return StringToBool(opt->second, defVal);
+   }
+
+   static std::vector<std::string> GetMapKeys(std::map<std::string, std::string> const &Options)
+   {
+      std::vector<std::string> ret;
+      ret.reserve(Options.size());
+      for (auto &&O: Options)
+	 ret.emplace_back(O.first);
+      std::sort(ret.begin(), ret.end());
+      return ret;
+   }
+
+   static bool MapsAreEqual(std::map<std::string, std::string> const &OptionsA,
+	 std::map<std::string, std::string> const &OptionsB,
+	 std::string const &URI, std::string const &Dist)
+   {
+      auto const KeysA = GetMapKeys(OptionsA);
+      auto const KeysB = GetMapKeys(OptionsB);
+      auto const m = std::mismatch(KeysA.begin(), KeysA.end(), KeysB.begin());
+      if (m.first != KeysA.end())
+      {
+	 if (std::find(KeysB.begin(), KeysB.end(), *m.first) == KeysB.end())
+	    return _error->Error(_("Conflicting values set for option %s regarding source %s %s"), m.first->c_str(), "<set>", "<unset>");
+	 else
+	    return _error->Error(_("Conflicting values set for option %s regarding source %s %s"), m.second->c_str(), "<set>", "<unset>");
+      }
+      if (m.second != KeysB.end())
+      {
+	 if (std::find(KeysA.begin(), KeysA.end(), *m.second) == KeysA.end())
+	    return _error->Error(_("Conflicting values set for option %s regarding source %s %s"), m.first->c_str(), "<set>", "<unset>");
+	 else
+	    return _error->Error(_("Conflicting values set for option %s regarding source %s %s"), m.second->c_str(), "<set>", "<unset>");
+      }
+      for (auto&& key: KeysA)
+      {
+	 if (key == "BASE_URI" || key == "REPO_URI")
+	    continue;
+	 auto const a = OptionsA.find(key);
+	 auto const b = OptionsB.find(key);
+	 if (unlikely(a == OptionsA.end() || b == OptionsB.end()) || a->second != b->second)
+	    return _error->Error(_("Conflicting values set for option %s regarding source %s %s"), key.c_str(), URI.c_str(), Dist.c_str());
+      }
+      return true;
+   }
+
    protected:
    protected:
 
 
    bool CreateItemInternal(std::vector<metaIndex *> &List, std::string const &URI,
    bool CreateItemInternal(std::vector<metaIndex *> &List, std::string const &URI,
 			   std::string const &Dist, std::string const &Section,
 			   std::string const &Dist, std::string const &Section,
 			   bool const &IsSrc, std::map<std::string, std::string> const &Options) const
 			   bool const &IsSrc, std::map<std::string, std::string> const &Options) const
    {
    {
+      std::map<std::string,std::string> ReleaseOptions = {{
+	 { "BASE_URI", constructMetaIndexURI(URI, Dist, "") },
+	 { "REPO_URI", URI },
+      }};
+      if (GetBoolOption(Options, "allow-insecure", _config->FindB("Acquire::AllowInsecureRepositories")))
+	 ReleaseOptions.emplace("ALLOW_INSECURE", "true");
+      if (GetBoolOption(Options, "allow-weak", _config->FindB("Acquire::AllowWeakRepositories")))
+	 ReleaseOptions.emplace("ALLOW_WEAK", "true");
+      if (GetBoolOption(Options, "allow-downgrade-to-insecure", _config->FindB("Acquire::AllowDowngradeToInsecureRepositories")))
+	 ReleaseOptions.emplace("ALLOW_DOWNGRADE_TO_INSECURE", "true");
+
       debReleaseIndex * Deb = nullptr;
       debReleaseIndex * Deb = nullptr;
       std::string const FileName = URItoFileName(constructMetaIndexURI(URI, Dist, "Release"));
       std::string const FileName = URItoFileName(constructMetaIndexURI(URI, Dist, "Release"));
       for (auto const &I: List)
       for (auto const &I: List)
@@ -931,6 +990,8 @@ class APT_HIDDEN debSLTypeDebian : public pkgSourceList::Type		/*{{{*/
 	    corresponds to. */
 	    corresponds to. */
 	 if (URItoFileName(D->MetaIndexURI("Release")) == FileName)
 	 if (URItoFileName(D->MetaIndexURI("Release")) == FileName)
 	 {
 	 {
+	    if (MapsAreEqual(ReleaseOptions, D->GetReleaseOptions(), URI, Dist) == false)
+	       return false;
 	    Deb = D;
 	    Deb = D;
 	    break;
 	    break;
 	 }
 	 }
@@ -939,7 +1000,7 @@ class APT_HIDDEN debSLTypeDebian : public pkgSourceList::Type		/*{{{*/
       // No currently created Release file indexes this entry, so we create a new one.
       // No currently created Release file indexes this entry, so we create a new one.
       if (Deb == nullptr)
       if (Deb == nullptr)
       {
       {
-	 Deb = new debReleaseIndex(URI, Dist);
+	 Deb = new debReleaseIndex(URI, Dist, ReleaseOptions);
 	 List.push_back(Deb);
 	 List.push_back(Deb);
       }
       }
 
 
@@ -993,12 +1054,7 @@ class APT_HIDDEN debSLTypeDebian : public pkgSourceList::Type		/*{{{*/
 	 }), mytargets.end());
 	 }), mytargets.end());
       }
       }
 
 
-      bool UsePDiffs = _config->FindB("Acquire::PDiffs", true);
-      {
-	 std::map<std::string, std::string>::const_iterator const opt = Options.find("pdiffs");
-	 if (opt != Options.end())
-	    UsePDiffs = StringToBool(opt->second);
-      }
+      bool const UsePDiffs = GetBoolOption(Options, "pdiffs", _config->FindB("Acquire::PDiffs", true));
 
 
       std::string UseByHash = _config->Find("APT::Acquire::By-Hash", "yes");
       std::string UseByHash = _config->Find("APT::Acquire::By-Hash", "yes");
       UseByHash = _config->Find("Acquire::By-Hash", UseByHash);
       UseByHash = _config->Find("Acquire::By-Hash", UseByHash);

+ 3 - 2
apt-pkg/deb/debmetaindex.h

@@ -34,8 +34,8 @@ class APT_HIDDEN debReleaseIndex : public metaIndex
    APT_HIDDEN std::string MetaIndexFile(const char *Types) const;
    APT_HIDDEN std::string MetaIndexFile(const char *Types) const;
    APT_HIDDEN std::string MetaIndexURI(const char *Type) const;
    APT_HIDDEN std::string MetaIndexURI(const char *Type) const;
 
 
-   debReleaseIndex(std::string const &URI, std::string const &Dist);
-   debReleaseIndex(std::string const &URI, std::string const &Dist, bool const Trusted);
+   debReleaseIndex(std::string const &URI, std::string const &Dist, std::map<std::string,std::string> const &Options);
+   debReleaseIndex(std::string const &URI, std::string const &Dist, bool const Trusted, std::map<std::string,std::string> const &Options);
    virtual ~debReleaseIndex();
    virtual ~debReleaseIndex();
 
 
    virtual std::string ArchiveURI(std::string const &File) const APT_OVERRIDE {return URI + File;};
    virtual std::string ArchiveURI(std::string const &File) const APT_OVERRIDE {return URI + File;};
@@ -56,6 +56,7 @@ class APT_HIDDEN debReleaseIndex : public metaIndex
    bool SetValidUntilMin(time_t const Valid);
    bool SetValidUntilMin(time_t const Valid);
    bool SetValidUntilMax(time_t const Valid);
    bool SetValidUntilMax(time_t const Valid);
    bool SetSignedBy(std::string const &SignedBy);
    bool SetSignedBy(std::string const &SignedBy);
+   std::map<std::string, std::string> GetReleaseOptions();
 
 
    virtual bool IsTrusted() const APT_OVERRIDE;
    virtual bool IsTrusted() const APT_OVERRIDE;
    bool IsArchitectureSupported(std::string const &arch) const;
    bool IsArchitectureSupported(std::string const &arch) const;

+ 1 - 1
apt-pkg/indexcopy.cc

@@ -550,7 +550,7 @@ bool SigVerify::CopyAndVerify(string CDROM,string Name,vector<string> &SigList,
       if(Debug)
       if(Debug)
 	 cout << "Signature verify for: " << *I << endl;
 	 cout << "Signature verify for: " << *I << endl;
 
 
-      metaIndex *MetaIndex = new debReleaseIndex("","");
+      metaIndex *MetaIndex = new debReleaseIndex("","", {});
       string prefix = *I; 
       string prefix = *I; 
 
 
       string const releasegpg = *I+"Release.gpg";
       string const releasegpg = *I+"Release.gpg";

+ 4 - 1
apt-pkg/indexfile.cc

@@ -147,6 +147,9 @@ std::string IndexTarget::Option(OptionKeys const EnumKey) const		/*{{{*/
       APT_CASE(SOURCESENTRY);
       APT_CASE(SOURCESENTRY);
       APT_CASE(BY_HASH);
       APT_CASE(BY_HASH);
       APT_CASE(KEEPCOMPRESSEDAS);
       APT_CASE(KEEPCOMPRESSEDAS);
+      APT_CASE(ALLOW_INSECURE);
+      APT_CASE(ALLOW_WEAK);
+      APT_CASE(ALLOW_DOWNGRADE_TO_INSECURE);
 #undef APT_CASE
 #undef APT_CASE
       case FILENAME: return _config->FindDir("Dir::State::lists") + URItoFileName(URI);
       case FILENAME: return _config->FindDir("Dir::State::lists") + URItoFileName(URI);
       case EXISTING_FILENAME:
       case EXISTING_FILENAME:
@@ -170,7 +173,7 @@ std::string IndexTarget::Option(OptionKeys const EnumKey) const		/*{{{*/
 									/*}}}*/
 									/*}}}*/
 bool IndexTarget::OptionBool(OptionKeys const EnumKey) const		/*{{{*/
 bool IndexTarget::OptionBool(OptionKeys const EnumKey) const		/*{{{*/
 {
 {
-   return StringToBool(Option(EnumKey));
+   return StringToBool(Option(EnumKey), false);
 }
 }
 									/*}}}*/
 									/*}}}*/
 std::string IndexTarget::Format(std::string format) const		/*{{{*/
 std::string IndexTarget::Format(std::string format) const		/*{{{*/

+ 3 - 0
apt-pkg/indexfile.h

@@ -93,6 +93,9 @@ class IndexTarget							/*{{{*/
       KEEPCOMPRESSEDAS,
       KEEPCOMPRESSEDAS,
       FALLBACK_OF,
       FALLBACK_OF,
       IDENTIFIER,
       IDENTIFIER,
+      ALLOW_INSECURE,
+      ALLOW_WEAK,
+      ALLOW_DOWNGRADE_TO_INSECURE,
    };
    };
    std::string Option(OptionKeys const Key) const;
    std::string Option(OptionKeys const Key) const;
    bool OptionBool(OptionKeys const Key) const;
    bool OptionBool(OptionKeys const Key) const;

+ 1 - 0
apt-pkg/init.cc

@@ -87,6 +87,7 @@ bool pkgInitConfig(Configuration &Cnf)
 
 
    // Repository security
    // Repository security
    Cnf.CndSet("Acquire::AllowInsecureRepositories", false);
    Cnf.CndSet("Acquire::AllowInsecureRepositories", false);
+   Cnf.CndSet("Acquire::AllowWeakRepositories", false);
    Cnf.CndSet("Acquire::AllowDowngradeToInsecureRepositories", false);
    Cnf.CndSet("Acquire::AllowDowngradeToInsecureRepositories", false);
 
 
    // Default cdrom mount point
    // Default cdrom mount point

+ 1 - 0
apt-private/private-cmndline.cc

@@ -265,6 +265,7 @@ static bool addArgumentsAPTGet(std::vector<CommandLine::Args> &Args, char const
    addArg(0,"arch-only","APT::Get::Arch-Only",0);
    addArg(0,"arch-only","APT::Get::Arch-Only",0);
    addArg(0,"allow-unauthenticated","APT::Get::AllowUnauthenticated",0);
    addArg(0,"allow-unauthenticated","APT::Get::AllowUnauthenticated",0);
    addArg(0,"allow-insecure-repositories","Acquire::AllowInsecureRepositories",0);
    addArg(0,"allow-insecure-repositories","Acquire::AllowInsecureRepositories",0);
+   addArg(0,"allow-weak-repositories","Acquire::AllowWeakRepositories",0);
    addArg(0,"install-recommends","APT::Install-Recommends",CommandLine::Boolean);
    addArg(0,"install-recommends","APT::Install-Recommends",CommandLine::Boolean);
    addArg(0,"install-suggests","APT::Install-Suggests",CommandLine::Boolean);
    addArg(0,"install-suggests","APT::Install-Suggests",CommandLine::Boolean);
    addArg(0,"fix-policy","APT::Get::Fix-Policy-Broken",0);
    addArg(0,"fix-policy","APT::Get::Fix-Policy-Broken",0);

+ 6 - 2
doc/apt-secure.8.xml

@@ -75,7 +75,10 @@
    <para>
    <para>
    You can force all APT clients to raise only warnings by setting the
    You can force all APT clients to raise only warnings by setting the
    configuration option <option>Acquire::AllowInsecureRepositories</option> to
    configuration option <option>Acquire::AllowInsecureRepositories</option> to
-   <literal>true</literal>. Note that this option will eventually be removed.
+   <literal>true</literal>. Individual repositories can also be allowed to be insecure
+   via the &sources-list; option <literal>allow-insecure=yes</literal>.
+   Note that insecure repositories are strongly discouraged and all options
+   to force apt to continue supporting them will eventually be removed.
    Users also have the <option>Trusted</option> option available to disable
    Users also have the <option>Trusted</option> option available to disable
    even the warnings, but be sure to understand the implications as detailed in
    even the warnings, but be sure to understand the implications as detailed in
    &sources-list;.
    &sources-list;.
@@ -87,7 +90,8 @@
    irrespective of the option to allow or forbid usage of insecure repositories.
    irrespective of the option to allow or forbid usage of insecure repositories.
    The error can be overcome by additionally setting
    The error can be overcome by additionally setting
    <option>Acquire::AllowDowngradeToInsecureRepositories</option>
    <option>Acquire::AllowDowngradeToInsecureRepositories</option>
-   to <literal>true</literal>.
+   to <literal>true</literal> or for Individual repositories with the &sources-list;
+   option <literal>allow-downgrade-to-insecure=yes</literal>.
    </para>
    </para>
 
 
    <para>
    <para>

+ 12 - 4
doc/apt.conf.5.xml

@@ -653,7 +653,17 @@ APT::Compressor::rev {
 	   Allow update operations to load data files from
 	   Allow update operations to load data files from
 	   repositories without sufficient security information.
 	   repositories without sufficient security information.
 	   The default value is "<literal>false</literal>".
 	   The default value is "<literal>false</literal>".
-	   Concept and implications of this are detailed in &apt-secure;.
+	   Concept, implications as well as alternatives are detailed in &apt-secure;.
+	 </para></listitem>
+     </varlistentry>
+
+     <varlistentry><term><option>AllowWeakRepositories</option></term>
+	 <listitem><para>
+	   Allow update operations to load data files from
+	   repositories which provide security information, but these
+	   are deemed no longer cryptographically strong enough.
+	   The default value is "<literal>false</literal>".
+	   Concept, implications as well as alternatives are detailed in &apt-secure;.
 	 </para></listitem>
 	 </para></listitem>
      </varlistentry>
      </varlistentry>
 
 
@@ -664,9 +674,7 @@ APT::Compressor::rev {
 	   for a previously trusted repository apt will refuse the update. This
 	   for a previously trusted repository apt will refuse the update. This
 	   option can be used to override this protection. You almost certainly
 	   option can be used to override this protection. You almost certainly
 	   never want to enable this. The default is <literal>false</literal>.
 	   never want to enable this. The default is <literal>false</literal>.
-
-	   Note that apt will still consider packages from this source
-	   untrusted and warns about them if you try to install them.
+	   Concept, implications as well as alternatives are detailed in &apt-secure;.
 	 </para></listitem>
 	 </para></listitem>
      </varlistentry>
      </varlistentry>
 
 

+ 8 - 0
doc/sources.list.5.xml

@@ -269,6 +269,14 @@ deb-src [ option1=value1 option2=value2 ] uri suite [component1] [component2] [.
        anomalies.
        anomalies.
 
 
        <itemizedlist>
        <itemizedlist>
+	  <listitem><para><option>Allow-Insecure</option> (<option>allow-insecure</option>),
+		<option>Allow-Weak</option> (<option>allow-weak</option>) and
+		<option>Allow-Downgrade-To-Insecure</option> (<option>allow-downgrade-to-insecure</option>)
+		are boolean values which all default to <literal>no</literal>.
+		If set to <literal>yes</literal> they circumvent parts of &apt-secure;
+		and should therefore not be used lightly!
+	  </para></listitem>
+
 	  <listitem><para><option>Trusted</option> (<option>trusted</option>)
 	  <listitem><para><option>Trusted</option> (<option>trusted</option>)
 		is a tri-state value which defaults to APT deciding if a source
 		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.
 		is considered trusted or if warnings should be raised before e.g.

+ 8 - 2
test/integration/test-apt-update-nofallback

@@ -93,10 +93,16 @@ test_from_inrelease_to_unsigned_with_override()
     find "$APTARCHIVE" -name '*Packages*' -exec touch -d '+2 hours' {} \;
     find "$APTARCHIVE" -name '*Packages*' -exec touch -d '+2 hours' {} \;
 
 
     # and ensure we can update to it (with enough force) 
     # and ensure we can update to it (with enough force) 
+    testfailure apt update
     testfailure aptget update
     testfailure aptget update
     testfailure aptget update --allow-insecure-repositories
     testfailure aptget update --allow-insecure-repositories
-    testwarning aptget update --allow-insecure-repositories \
-        -o Acquire::AllowDowngradeToInsecureRepositories=1 -o Debug::pkgAcquire::Worker=1 -o Debug::pkgAcquire::Auth=1
+    testfailure aptget update --no-allow-insecure-repositories
+    sed -i 's#^deb\(-src\)\? #deb\1 [allow-downgrade-to-insecure=yes] #' rootdir/etc/apt/sources.list.d/*
+    testfailure aptget update --no-allow-insecure-repositories
+    testfailure apt update
+    testwarning apt update --allow-insecure-repositories \
+        -o Debug::pkgAcquire::Worker=1 -o Debug::pkgAcquire::Auth=1
+    sed -i 's#^deb\(-src\)\? \[allow-downgrade-to-insecure=yes\] #deb\1 #' rootdir/etc/apt/sources.list.d/*
     # but that the individual packages are still considered untrusted
     # but that the individual packages are still considered untrusted
     testfailureequal "WARNING: The following packages cannot be authenticated!
     testfailureequal "WARNING: The following packages cannot be authenticated!
   evil
   evil

+ 22 - 7
test/integration/test-apt-update-weak-hashes

@@ -58,6 +58,16 @@ N: See apt-secure(8) manpage for repository creation and user configuration deta
 		testbadpkg 'foo'
 		testbadpkg 'foo'
 	fi
 	fi
 
 
+	msgmsg "$TYPE contains only weak hashes, but source allows weak"
+	sed -i 's#^deb\(-src\)\? #deb\1 [allow-weak=yes] #' rootdir/etc/apt/sources.list.d/*
+	genericprepare
+	testwarningmsg "W: No Hash entry in Release file ${MANGLED} which is considered strong enough for security purposes
+W: The repository 'file:${APTARCHIVE} unstable $(basename "$FILENAME")' provides only weak security information.
+N: Data from such a repository can't be authenticated and is therefore potentially dangerous to use.
+N: See apt-secure(8) manpage for repository creation and user configuration details." apt update "$@"
+	testbadpkg 'foo'
+	sed -i 's#^deb\(-src\)\? \[allow-weak=yes\] #deb\1 #' rootdir/etc/apt/sources.list.d/*
+
 	msgmsg "$TYPE contains no hashes"
 	msgmsg "$TYPE contains no hashes"
 	generatereleasefiles
 	generatereleasefiles
 	sed -i -e '/^ / d' -e '/^MD5Sum:/ d' "$APTARCHIVE/dists/unstable/Release"
 	sed -i -e '/^ / d' -e '/^MD5Sum:/ d' "$APTARCHIVE/dists/unstable/Release"
@@ -85,10 +95,15 @@ N: See apt-secure(8) manpage for repository creation and user configuration deta
 	sed -i '/^ [0-9a-fA-Z]\{64\} .*Sources$/d' "$APTARCHIVE/dists/unstable/Release"
 	sed -i '/^ [0-9a-fA-Z]\{64\} .*Sources$/d' "$APTARCHIVE/dists/unstable/Release"
 	signreleasefiles
 	signreleasefiles
 	preparetest
 	preparetest
-	# trust is a repository property, so individual files can't be insecure
-	testwarningmsg "W: Skipping acquire of configured file 'main/source/Sources' as repository 'file:${APTARCHIVE} unstable InRelease' provides only weak security information for it" apt update "$@"
+	if [ -z "$1" ]; then
+		testwarningmsg "W: Skipping acquire of configured file 'main/source/Sources' as repository 'file:${APTARCHIVE} unstable InRelease' provides only weak security information for it" apt update
+		testnosrcpackage foo
+	else
+		rm -f rootdir/var/lib/apt/lists/partial/*
+		testsuccess apt update "$@"
+		testnotempty apt showsrc foo
+	fi
 	testsuccess apt show foo
 	testsuccess apt show foo
-	testnosrcpackage foo
 }
 }
 
 
 genericprepare() {
 genericprepare() {
@@ -107,14 +122,14 @@ preparetest() {
 	genericprepare
 	genericprepare
 }
 }
 testrun 'InRelease' "${APTARCHIVE}/dists/unstable/InRelease"
 testrun 'InRelease' "${APTARCHIVE}/dists/unstable/InRelease"
-testrun 'InRelease' "${APTARCHIVE}/dists/unstable/InRelease" --allow-insecure-repositories -o APT::Get::List-Cleanup=0
+testrun 'InRelease' "${APTARCHIVE}/dists/unstable/InRelease" --allow-weak-repositories -o APT::Get::List-Cleanup=0
 
 
 preparetest() {
 preparetest() {
 	rm -f "${APTARCHIVE}/dists/unstable/InRelease"
 	rm -f "${APTARCHIVE}/dists/unstable/InRelease"
 	genericprepare
 	genericprepare
 }
 }
 testrun 'Release+Release.gpg' "${APTARCHIVE}/dists/unstable/Release"
 testrun 'Release+Release.gpg' "${APTARCHIVE}/dists/unstable/Release"
-testrun 'Release+Release.gpg' "${APTARCHIVE}/dists/unstable/Release" --allow-insecure-repositories -o APT::Get::List-Cleanup=0
+testrun 'Release+Release.gpg' "${APTARCHIVE}/dists/unstable/Release" --allow-weak-repositories -o APT::Get::List-Cleanup=0
 
 
 preparetest() {
 preparetest() {
 	rm -f "${APTARCHIVE}/dists/unstable/InRelease" "${APTARCHIVE}/dists/unstable/Release.gpg"
 	rm -f "${APTARCHIVE}/dists/unstable/InRelease" "${APTARCHIVE}/dists/unstable/Release.gpg"
@@ -128,7 +143,7 @@ generatereleasefiles 'now - 7 days'
 signreleasefiles
 signreleasefiles
 testfailure apt update
 testfailure apt update
 testnopkg 'foo'
 testnopkg 'foo'
-testwarning apt update --allow-insecure-repositories
+testwarning apt update --allow-weak-repositories
 testbadpkg 'foo'
 testbadpkg 'foo'
 
 
 confighashes 'MD5' 'SHA256'
 confighashes 'MD5' 'SHA256'
@@ -153,7 +168,7 @@ testnopkg foo3
 testnotempty find rootdir/var/lib/apt/lists -maxdepth 1 -name '*InRelease' -o -name '*Release.gpg'
 testnotempty find rootdir/var/lib/apt/lists -maxdepth 1 -name '*InRelease' -o -name '*Release.gpg'
 testnotempty apt show foo2
 testnotempty apt show foo2
 testnotempty apt showsrc foo2
 testnotempty apt showsrc foo2
-testwarning apt update --allow-insecure-repositories
+testwarning apt update --allow-weak-repositories
 testnopkg foo2
 testnopkg foo2
 testbadpkg foo3
 testbadpkg foo3
 
 

+ 5 - 0
test/integration/test-releasefile-verification

@@ -414,6 +414,11 @@ runfailure() {
 		testnopackage 'apt'
 		testnopackage 'apt'
 		testwarning aptget update --allow-insecure-repositories -o Debug::pkgAcquire::Worker=1 -o Debug::Acquire::gpgv=1
 		testwarning aptget update --allow-insecure-repositories -o Debug::pkgAcquire::Worker=1 -o Debug::Acquire::gpgv=1
 		failaptold
 		failaptold
+		rm -rf rootdir/var/lib/apt/lists
+		sed -i 's#^deb\(-src\)\? #deb\1 [allow-insecure=yes] #' rootdir/etc/apt/sources.list.d/*
+		testwarning aptget update --no-allow-insecure-repositories -o Debug::pkgAcquire::Worker=1 -o Debug::Acquire::gpgv=1
+		failaptold
+		sed -i 's#^deb\(-src\)\? \[allow-insecure=yes\] #deb\1 #' rootdir/etc/apt/sources.list.d/*
 
 
 		msgmsg 'Cold archive signed by' 'Marvin Paranoid'
 		msgmsg 'Cold archive signed by' 'Marvin Paranoid'
 		prepare "${PKGFILE}"
 		prepare "${PKGFILE}"