Browse Source

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 7 years ago
parent
commit
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;
    strprintf(m, msg, repo.c_str());
@@ -195,7 +195,28 @@ static bool MessageInsecureRepository(bool const isError, char const * const msg
 									/*}}}*/
 // AllowInsecureRepositories						/*{{{*/
 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)
 {
    // 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::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
 	    // 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;
    }
 
-   if (_config->FindB("Acquire::AllowInsecureRepositories") == true)
+   if (TargetIsAllowedToBe(TransactionManager->Target, msg) == true)
    {
       MessageInsecureRepository(false, msgstr, repo);
       return true;
@@ -277,7 +299,20 @@ APT_CONST bool pkgAcqTransactionItem::HashesRequired() const
       we can at least trust them for integrity of the download itself.
       Only repositories without a Release file can (obviously) not have
       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
 {
@@ -1333,7 +1368,7 @@ void pkgAcqMetaClearSig::QueueIndexes(bool const verify)			/*{{{*/
 	    auto const hashes = GetExpectedHashesFor(Target.MetaKey);
 	    if (hashes.empty() == false)
 	    {
-	       if (hashes.usable() == false)
+	       if (hashes.usable() == false && TargetIsAllowedToBe(TransactionManager->Target, InsecureType::WEAK) == false)
 	       {
 		  new CleanupItem(Owner, TransactionManager, Target);
 		  _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,
       metaIndex * const MetaIndexParser) :
    pkgAcqMetaIndex(Owner, this, ClearsignedTarget, DetachedSigTarget),
-   d(NULL), ClearsignedTarget(ClearsignedTarget),
-   DetachedDataTarget(DetachedDataTarget),
+   d(NULL), DetachedDataTarget(DetachedDataTarget),
    MetaIndexParser(MetaIndexParser), LastMetaIndexParser(NULL)
 {
    // index targets + (worst case:) Release/Release.gpg
@@ -1640,7 +1674,7 @@ void pkgAcqMetaClearSig::Failed(string const &Message,pkgAcquire::MethodConfig c
       if(CheckStopAuthentication(this, Message))
          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;
 

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

@@ -368,12 +368,13 @@ class APT_HIDDEN pkgAcqTransactionItem: public pkgAcquire::Item		/*{{{*/
 {
    void * const d;
    protected:
-   IndexTarget const Target;
    HashStringList GetExpectedHashesFor(std::string const &MetaKey) const;
 
    bool QueueURI(pkgAcquire::ItemDesc &Item) APT_OVERRIDE;
 
    public:
+   IndexTarget const Target;
+
    /** \brief storge name until a transaction is finished */
    std::string PartialFile;
 
@@ -559,8 +560,6 @@ class APT_HIDDEN pkgAcqMetaSig : public pkgAcqTransactionItem
 class APT_HIDDEN pkgAcqMetaClearSig : public pkgAcqMetaIndex
 {
    void * const d;
-
-   IndexTarget const ClearsignedTarget;
    IndexTarget const DetachedDataTarget;
 
  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) ||
 	       StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false);
+	    auto const forcedHash = _config->Find("Acquire::ForceHash");
 	    for (auto const Owner: ItmOwners)
 	    {
 	       HashStringList const ExpectedHashes = Owner->GetExpectedHashes();
@@ -395,9 +396,10 @@ bool pkgAcquire::Worker::RunMessages()
 
 	       // decide if what we got is what we expected
 	       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,
 			but the hashes for the compressed file. What we have was good through
@@ -410,16 +412,8 @@ bool pkgAcquire::Worker::RunMessages()
 		     consideredOkay = false;
 
 	       }
-	       else if (Owner->HashesRequired() == true)
-		  consideredOkay = false;
 	       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)
 		  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> 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				/*{{{*/
@@ -96,11 +97,11 @@ std::string debReleaseIndex::MetaIndexURI(const char *Type) const
 }
 									/*}}}*/
 // 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;
 }
@@ -112,17 +113,10 @@ debReleaseIndex::~debReleaseIndex() {
 // ReleaseIndex::GetIndexTargets					/*{{{*/
 static void GetIndexTargetsFor(char const * const Type, std::string const &URI, std::string const &Dist,
       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] == '/');
-   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 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
-		  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("TARGET_OF", Type));
 		  Options.insert(std::make_pair("CREATED_BY", *T));
@@ -317,7 +310,7 @@ static void GetIndexTargetsFor(char const * const Type, std::string const &URI,
 			MetaKey,
 			ShortDesc,
 			LongDesc,
-			Options.find("BASE_URI")->second + MetaKey,
+			baseURI + MetaKey,
 			IsOpt,
 			KeepCompressed,
 			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> 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;
 }
 									/*}}}*/
@@ -542,11 +535,11 @@ bool debReleaseIndex::Load(std::string const &Filename, std::string * const Erro
 metaIndex * debReleaseIndex::UnloadedClone() const			/*{{{*/
 {
    if (Trusted == TRI_NO)
-      return new debReleaseIndex(URI, Dist, false);
+      return new debReleaseIndex(URI, Dist, false, d->ReleaseOptions);
    else if (Trusted == TRI_YES)
-      return new debReleaseIndex(URI, Dist, true);
+      return new debReleaseIndex(URI, Dist, true, d->ReleaseOptions);
    else
-      return new debReleaseIndex(URI, Dist);
+      return new debReleaseIndex(URI, Dist, d->ReleaseOptions);
 }
 									/*}}}*/
 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)/*{{{*/
 {
-#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,
 	 APT_TARGET("InRelease"), APT_TARGET("Release"), APT_TARGET("Release.gpg"), this);
 #undef APT_TARGET
@@ -751,6 +744,10 @@ std::vector <pkgIndexFile *> *debReleaseIndex::GetIndexFiles()		/*{{{*/
    return Indexes;
 }
 									/*}}}*/
+std::map<std::string, std::string> debReleaseIndex::GetReleaseOptions()
+{
+   return d->ReleaseOptions;
+}
 
 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;
    }
 
-   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);
       if (opt == Options.end())
@@ -908,12 +905,74 @@ class APT_HIDDEN debSLTypeDebian : public pkgSourceList::Type		/*{{{*/
       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:
 
    bool CreateItemInternal(std::vector<metaIndex *> &List, std::string const &URI,
 			   std::string const &Dist, std::string const &Section,
 			   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;
       std::string const FileName = URItoFileName(constructMetaIndexURI(URI, Dist, "Release"));
       for (auto const &I: List)
@@ -931,6 +990,8 @@ class APT_HIDDEN debSLTypeDebian : public pkgSourceList::Type		/*{{{*/
 	    corresponds to. */
 	 if (URItoFileName(D->MetaIndexURI("Release")) == FileName)
 	 {
+	    if (MapsAreEqual(ReleaseOptions, D->GetReleaseOptions(), URI, Dist) == false)
+	       return false;
 	    Deb = D;
 	    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.
       if (Deb == nullptr)
       {
-	 Deb = new debReleaseIndex(URI, Dist);
+	 Deb = new debReleaseIndex(URI, Dist, ReleaseOptions);
 	 List.push_back(Deb);
       }
 
@@ -993,12 +1054,7 @@ class APT_HIDDEN debSLTypeDebian : public pkgSourceList::Type		/*{{{*/
 	 }), 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");
       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 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 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 SetValidUntilMax(time_t const Valid);
    bool SetSignedBy(std::string const &SignedBy);
+   std::map<std::string, std::string> GetReleaseOptions();
 
    virtual bool IsTrusted() const APT_OVERRIDE;
    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)
 	 cout << "Signature verify for: " << *I << endl;
 
-      metaIndex *MetaIndex = new debReleaseIndex("","");
+      metaIndex *MetaIndex = new debReleaseIndex("","", {});
       string prefix = *I; 
 
       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(BY_HASH);
       APT_CASE(KEEPCOMPRESSEDAS);
+      APT_CASE(ALLOW_INSECURE);
+      APT_CASE(ALLOW_WEAK);
+      APT_CASE(ALLOW_DOWNGRADE_TO_INSECURE);
 #undef APT_CASE
       case FILENAME: return _config->FindDir("Dir::State::lists") + URItoFileName(URI);
       case EXISTING_FILENAME:
@@ -170,7 +173,7 @@ std::string IndexTarget::Option(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		/*{{{*/

+ 3 - 0
apt-pkg/indexfile.h

@@ -93,6 +93,9 @@ class IndexTarget							/*{{{*/
       KEEPCOMPRESSEDAS,
       FALLBACK_OF,
       IDENTIFIER,
+      ALLOW_INSECURE,
+      ALLOW_WEAK,
+      ALLOW_DOWNGRADE_TO_INSECURE,
    };
    std::string Option(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
    Cnf.CndSet("Acquire::AllowInsecureRepositories", false);
+   Cnf.CndSet("Acquire::AllowWeakRepositories", false);
    Cnf.CndSet("Acquire::AllowDowngradeToInsecureRepositories", false);
 
    // 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,"allow-unauthenticated","APT::Get::AllowUnauthenticated",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-suggests","APT::Install-Suggests",CommandLine::Boolean);
    addArg(0,"fix-policy","APT::Get::Fix-Policy-Broken",0);

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

@@ -75,7 +75,10 @@
    <para>
    You can force all APT clients to raise only warnings by setting the
    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
    even the warnings, but be sure to understand the implications as detailed in
    &sources-list;.
@@ -87,7 +90,8 @@
    irrespective of the option to allow or forbid usage of insecure repositories.
    The error can be overcome by additionally setting
    <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>

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

@@ -653,7 +653,17 @@ APT::Compressor::rev {
 	   Allow update operations to load data files from
 	   repositories without sufficient security information.
 	   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>
      </varlistentry>
 
@@ -664,9 +674,7 @@ APT::Compressor::rev {
 	   for a previously trusted repository apt will refuse the update. This
 	   option can be used to override this protection. You almost certainly
 	   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>
      </varlistentry>
 

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

@@ -269,6 +269,14 @@ deb-src [ option1=value1 option2=value2 ] uri suite [component1] [component2] [.
        anomalies.
 
        <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>)
 		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.

+ 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' {} \;
 
     # and ensure we can update to it (with enough force) 
+    testfailure apt update
     testfailure aptget update
     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
     testfailureequal "WARNING: The following packages cannot be authenticated!
   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'
 	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"
 	generatereleasefiles
 	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"
 	signreleasefiles
 	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
-	testnosrcpackage foo
 }
 
 genericprepare() {
@@ -107,14 +122,14 @@ preparetest() {
 	genericprepare
 }
 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() {
 	rm -f "${APTARCHIVE}/dists/unstable/InRelease"
 	genericprepare
 }
 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() {
 	rm -f "${APTARCHIVE}/dists/unstable/InRelease" "${APTARCHIVE}/dists/unstable/Release.gpg"
@@ -128,7 +143,7 @@ generatereleasefiles 'now - 7 days'
 signreleasefiles
 testfailure apt update
 testnopkg 'foo'
-testwarning apt update --allow-insecure-repositories
+testwarning apt update --allow-weak-repositories
 testbadpkg 'foo'
 
 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 apt show foo2
 testnotempty apt showsrc foo2
-testwarning apt update --allow-insecure-repositories
+testwarning apt update --allow-weak-repositories
 testnopkg foo2
 testbadpkg foo3
 

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

@@ -414,6 +414,11 @@ runfailure() {
 		testnopackage 'apt'
 		testwarning aptget update --allow-insecure-repositories -o Debug::pkgAcquire::Worker=1 -o Debug::Acquire::gpgv=1
 		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'
 		prepare "${PKGFILE}"