aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Danny van Dyk <dvandyk@exherbo.org> 2006-04-29 16:08:22 +0000
committerAvatar Danny van Dyk <dvandyk@exherbo.org> 2006-04-29 16:08:22 +0000
commit9e0bd974303aca32e0df2396886c83441d0a1006 (patch)
tree5adb02f59f6d2fd81cbbd891e1cc8d7fb6b10cb3
parentee9c364bb694848554c38bd7cc9ae9d596e9cd8a (diff)
downloadpaludis-9e0bd974303aca32e0df2396886c83441d0a1006.tar.gz
paludis-9e0bd974303aca32e0df2396886c83441d0a1006.tar.xz
Rework of the built-in security set.
-rw-r--r--paludis/config_file.cc34
-rw-r--r--paludis/config_file.hh106
-rw-r--r--paludis/portage_repository.cc143
-rw-r--r--paludis/portage_repository.hh2
4 files changed, 258 insertions, 27 deletions
diff --git a/paludis/config_file.cc b/paludis/config_file.cc
index 0633e8e..918e5f6 100644
--- a/paludis/config_file.cc
+++ b/paludis/config_file.cc
@@ -23,6 +23,7 @@
#include <paludis/util/exception.hh>
#include <paludis/util/stringify.hh>
#include <paludis/util/strip.hh>
+#include <paludis/util/tokeniser.hh>
/** \file
* Implementation for config_file.hh classes.
@@ -309,6 +310,31 @@ KeyValueConfigFile::strip_quotes(const std::string & s) const
return s;
}
+AdvisoryLine::AdvisoryLine(const std::string & s) :
+ _line(s),
+ _is_range(false)
+{
+ Tokeniser<delim_kind::AnyOfTag, delim_mode::DelimiterTag> tokeniser(" \t");
+ tokeniser.tokenise(s, std::back_inserter(_tokens));
+
+ if ((_tokens.size() < 1) || (_tokens.size() > 2))
+ throw AdvisoryFileError("Wrong count of atoms on line.");
+
+ if (_tokens.size() == 2)
+ {
+ if (!(is_range_token(0) && is_range_token(1)))
+ throw AdvisoryFileError("Line must exactly contain 1 non-range atom or 2 range atoms.");
+
+ if (is_range_bigger(0) && is_range_bigger(1))
+ throw AdvisoryFileError("Broken range: Two bigger/bigger than atoms.");
+
+ if (is_range_smaller(0) && is_range_smaller(1))
+ throw AdvisoryFileError("Broken range: Two smaller/smaller than atoms.");
+
+ _is_range = true;
+ }
+}
+
AdvisoryFileError::AdvisoryFileError(const std::string & msg,
const std::string & filename) throw () :
ConfigurationError("Advisory file error" +
@@ -346,7 +372,6 @@ AdvisoryFile::AdvisoryFile(std::istream * const s,
_entries(m.begin(), m.end()),
_end_of_header(false)
{
- _end_of_header = false;
need_lines();
sanitise();
}
@@ -393,6 +418,11 @@ AdvisoryFile::accept_line(const std::string & line) const
if ((key == "Affected") || (key == "Unaffected") || (key == "Bug-Id") || (key == "Url")
|| (key == "Reviewed-By"))
{
+ if (key == "Affected")
+ _affected.push_back(AdvisoryLine(value));
+ else if (key == "Unaffected")
+ _unaffected.push_back(AdvisoryLine(value));
+
if (!_entries[key].empty())
value = "\n" + value;
_entries[key] += value;
@@ -402,7 +432,7 @@ AdvisoryFile::accept_line(const std::string & line) const
if (_entries[key].empty())
_entries[key] = value;
else
- throw ConfigFileError("When adding value for key '" + key + "': Duplicate key found.");
+ throw AdvisoryFileError("When adding value for key '" + key + "': Duplicate key found.");
}
}
}
diff --git a/paludis/config_file.hh b/paludis/config_file.hh
index e971caf..d923534 100644
--- a/paludis/config_file.hh
+++ b/paludis/config_file.hh
@@ -27,6 +27,7 @@
#include <paludis/util/fs_entry.hh>
#include <paludis/util/instantiation_policy.hh>
#include <string>
+#include <vector>
/** \file
* Declarations for the ConfigFile classes.
@@ -307,6 +308,56 @@ namespace paludis
};
/**
+ * An AdvisoryLine represents one of the Affected: or Unaffected: lines in an AdvisoryFile.
+ *
+ * \ingroup grpadvisoryconfigfile
+ */
+ class AdvisoryLine
+ {
+ private:
+ enum RangeChars {
+ rc_is_bigger = '>',
+ rc_is_smaller = '<'
+ };
+ std::string _line;
+ std::vector<std::string> _tokens;
+ bool _is_range;
+
+ protected:
+ bool is_range_bigger(int i) const
+ {
+ return _tokens[i][0] == rc_is_bigger;
+ }
+
+ bool is_range_smaller(int i) const
+ {
+ return _tokens[i][0] == rc_is_smaller;
+ }
+
+ bool is_range_token(int i) const
+ {
+ return is_range_smaller(i) || is_range_bigger(i);
+ }
+
+ public:
+ AdvisoryLine(const std::string & s);
+ const std::string operator[] (int i) const
+ {
+ return _tokens[i];
+ }
+
+ const std::string & line() const
+ {
+ return _line;
+ }
+
+ bool is_range() const
+ {
+ return _is_range;
+ }
+ };
+
+ /**
* An AdvisoryFile is a file containing all necessary information to
* update one or more packages in order to avoid a security problem.
*
@@ -323,9 +374,15 @@ namespace paludis
{
private:
mutable std::map<std::string, std::string> _entries;
+ mutable std::list<AdvisoryLine> _affected;
+ mutable std::list<AdvisoryLine> _unaffected;
mutable bool _end_of_header;
+
protected:
void accept_line(const std::string &) const;
+ /**
+ * Ensure that the AdvisoryFile contains all mandatory items.
+ */
void sanitise();
public:
@@ -370,12 +427,13 @@ namespace paludis
/**
* Iterator over our lines.
*/
- typedef std::map<std::string, std::string>::const_iterator Iterator;
+ typedef std::map<std::string, std::string>::const_iterator EntriesIterator;
+ typedef std::list<AdvisoryLine>::const_iterator LineIterator;
/**
* Iterator to the start of our lines.
*/
- Iterator begin() const
+ EntriesIterator begin() const
{
return _entries.begin();
}
@@ -383,18 +441,60 @@ namespace paludis
/**
* Iterator to past the end of our lines.
*/
- Iterator end() const
+ EntriesIterator end() const
{
return _entries.end();
}
/**
+ * Iterator to the start of our Affected: lines.
+ */
+ LineIterator begin_affected() const
+ {
+ return _affected.begin();
+ }
+
+ /**
+ * Iterator to past the end of our Affected: lines.
+ */
+ LineIterator end_affected() const
+ {
+ return _affected.end();
+ }
+
+ /**
+ * Iterator to the start of our Unaffected: lines.
+ */
+ LineIterator begin_unaffected() const
+ {
+ return _unaffected.begin();
+ }
+
+ /**
+ * Iterator to past the end of our Unaffected: lines.
+ */
+ LineIterator end_unaffected() const
+ {
+ return _unaffected.end();
+ }
+
+ /**
* Fetch the specified key, or a blank string.
*/
std::string get(const std::string & key) const
{
return _entries[key];
}
+
+ std::list<AdvisoryLine> & affected() const
+ {
+ return _affected;
+ }
+
+ std::list<AdvisoryLine> & unaffected() const
+ {
+ return _unaffected;
+ }
};
}
diff --git a/paludis/portage_repository.cc b/paludis/portage_repository.cc
index 9dc2df9..306e9ee 100644
--- a/paludis/portage_repository.cc
+++ b/paludis/portage_repository.cc
@@ -27,6 +27,7 @@
#include <paludis/hashed_containers.hh>
#include <paludis/config_file.hh>
#include <paludis/match_package.hh>
+#include <paludis/package_database_entry.hh>
#include <paludis/package_database.hh>
#include <paludis/portage_repository.hh>
#include <paludis/syncer.hh>
@@ -1372,6 +1373,57 @@ PortageRepository::do_install(const QualifiedPackageName & q, const VersionSpec
install_cmd();
}
+namespace
+{
+ inline
+ PackageDepAtom::Pointer make_atom(const PackageDatabaseEntry & e)
+ {
+ QualifiedPackageName n(e.get<pde_name>());
+ VersionSpec v(e.get<pde_version>());
+
+ std::string s("=" + stringify(n) + "-" + stringify(v));
+ return PackageDepAtom::Pointer(new PackageDepAtom(s));
+ }
+
+ struct IsNotMemberOfCollection
+ {
+ PackageDatabaseEntryCollection::ConstPointer _c;
+ IsNotMemberOfCollection(const PackageDatabaseEntryCollection::ConstPointer & c) :
+ _c(c)
+ {
+ }
+
+ bool operator() (const PackageDatabaseEntry & e) const
+ {
+ bool result = (_c->find(e) == _c->end());
+ return result;
+ }
+ };
+}
+
+PackageDatabaseEntryCollection::Iterator
+PortageRepository::find_best(PackageDatabaseEntryCollection::Pointer & c, const PackageDatabaseEntry & e) const
+{
+ Context local("When finding best update for '" + stringify(e.get<pde_name>()) + "-" + stringify(e.get<pde_version>()) + "':");
+ //Find an entry in c that matches e best. e is not in c.
+ QualifiedPackageName n(e.get<pde_name>());
+ std::string s(_imp->env->package_database()->fetch_metadata(e)->get(vmk_slot));
+ PackageDatabaseEntryCollection::Iterator i(c->begin()), i_end(c->end()), i_best(c->end());
+ for ( ; i != i_end; ++i)
+ {
+ if (n != i->get<pde_name>())
+ continue;
+ if (s != _imp->env->package_database()->fetch_metadata(*i)->get(vmk_slot))
+ {
+ continue;
+ }
+
+ i_best = i;
+ }
+
+ return i_best;
+}
+
DepAtom::Pointer
PortageRepository::do_security_set() const
{
@@ -1398,34 +1450,81 @@ PortageRepository::do_security_set() const
GLSADepTag::Pointer advisory_tag(new GLSADepTag(advisory.get("Id"),
advisory.get("Title")));
- bool is_affected = false;
-
- std::list<std::string> a_list, u_list;
- Tokeniser<delim_kind::AnyOfTag, delim_mode::DelimiterTag> tokeniser("\n");
- tokeniser.tokenise(advisory.get("Affected"), std::back_inserter(a_list));
- tokeniser.tokenise(advisory.get("Unaffected"), std::back_inserter(u_list));
- if (a_list.size() != u_list.size())
- throw AdvisoryFileError("Number of affected packages does not match number of unaffected packages.");
+ PackageDatabaseEntryCollection::Pointer affected(new PackageDatabaseEntryCollection),
+ unaffected(new PackageDatabaseEntryCollection);
+ std::list<AdvisoryLine>::const_iterator u(advisory.begin_unaffected()), u_end(advisory.end_unaffected());
+ for ( ; u != u_end ; ++u)
+ {
+ Context c("When parsing 'Unaffected:' line '" + u->line() + "':");
+ if (u->is_range())
+ {
+ PackageDepAtom::Pointer p(new PackageDepAtom((*u)[0]));
+ PackageDatabaseEntryCollection::ConstPointer c_one = _imp->db->query(p, is_either);
+ p.assign(new PackageDepAtom((*u)[1]));
+ PackageDatabaseEntryCollection::ConstPointer c_two = _imp->db->query(p, is_either);
+ std::set_intersection(c_one->begin(), c_one->end(), c_two->begin(), c_two->end(),
+ filter_inserter(unaffected->inserter(), IsNotMemberOfCollection(unaffected)));
+ }
+ else
+ {
+ PackageDepAtom::Pointer p(new PackageDepAtom((*u)[0]));
+ PackageDatabaseEntryCollection::ConstPointer c = _imp->db->query(p, is_either);
+ std::copy(c->begin(), c->end(), filter_inserter(unaffected->inserter(), IsNotMemberOfCollection(unaffected)));
+ }
+ }
- std::list<std::string>::const_iterator a(a_list.begin()), a_end(a_list.end());
- std::list<std::string>::const_iterator u(u_list.begin()), u_end(u_list.end());
- while ((a != a_end) && (u != u_end))
+ std::list<AdvisoryLine>::const_iterator a(advisory.begin_affected()), a_end(advisory.end_affected());
+ for ( ; a != a_end ; ++a)
{
- PackageDepAtom::Pointer affected(new PackageDepAtom(*a)),
- unaffected(new PackageDepAtom(*u));
- ++a; ++u;
+ Context c("When parsing 'Affected:' line '" + a->line() + "':");
+ if (a->is_range())
+ {
+ PackageDepAtom::Pointer p(new PackageDepAtom((*a)[0]));
+ PackageDatabaseEntryCollection::ConstPointer installed_one = _imp->db->query(p, is_installed_only);
+ PackageDatabaseEntryCollection::ConstPointer either_one = _imp->db->query(p, is_either);
+ p.assign(new PackageDepAtom((*a)[1]));
+ PackageDatabaseEntryCollection::ConstPointer installed_two = _imp->db->query(p, is_installed_only);
+ PackageDatabaseEntryCollection::ConstPointer either_two = _imp->db->query(p, is_either);
+ std::set_intersection(installed_one->begin(), installed_one->end(), installed_two->begin(), installed_two->end(),
+ filter_inserter(affected->inserter(), IsNotMemberOfCollection(affected)));
+ PackageDatabaseEntryCollection::Iterator e(either_one->begin()), e_end(either_one->end());
+ for ( ; e != e_end; ++e)
+ {
+ IsNotMemberOfCollection f(either_two);
+ if (f(*e))
+ continue;
- if (affected->package() != unaffected->package())
- throw AdvisoryFileError("Affected and unaffected items are out of sync.");
+ if (unaffected->find(*e) != unaffected->end())
+ unaffected->erase(*e);
+ }
+ }
+ else
+ {
+ PackageDepAtom::Pointer p(new PackageDepAtom((*a)[0]));
+ PackageDatabaseEntryCollection::ConstPointer c = _imp->db->query(p, is_installed_only);
+ std::copy(c->begin(), c->end(), filter_inserter(affected->inserter(), IsNotMemberOfCollection(affected)));
+ PackageDatabaseEntryCollection::Iterator e(c->begin()), e_end(c->end());
+ for ( ; e != e_end; ++e)
+ {
+ if (unaffected->find(*e) != unaffected->end())
+ unaffected->erase(*e);
+ }
+ }
+ }
- if ((_imp->db->query(affected, is_installed_only))->empty())
- continue;
+ PackageDatabaseEntryCollection::Iterator i(affected->begin()), i_end(affected->end());
+ for ( ; i != i_end ; ++i)
+ {
+ Context c("When finding best update for package '" + stringify(*i) + "':");
- is_affected = true;
- unaffected->set_tag(advisory_tag);
- security_packages->add_child(unaffected);
- }
+ PackageDatabaseEntryCollection::Iterator e = find_best(unaffected, *i);
+ if (e == unaffected->end())
+ throw AllMaskedError("No best update available for package '" + stringify(*i) + "':");
+ PackageDepAtom::Pointer p(make_atom(*e));
+ p->set_tag(advisory_tag);
+ security_packages->add_child(make_atom(*e));
+ }
}
return security_packages;
diff --git a/paludis/portage_repository.hh b/paludis/portage_repository.hh
index e42390e..7600ad2 100644
--- a/paludis/portage_repository.hh
+++ b/paludis/portage_repository.hh
@@ -101,6 +101,8 @@ namespace paludis
void need_category_names() const;
void need_version_names(const QualifiedPackageName &) const;
void need_virtual_names() const;
+ PackageDatabaseEntryCollection::Iterator find_best(PackageDatabaseEntryCollection::Pointer & c,
+ const PackageDatabaseEntry & e) const;
DepAtom::Pointer do_security_set() const;
protected: