| 15 |
from web_support import * |
from web_support import * |
| 16 |
|
|
| 17 |
class BugFilter: |
class BugFilter: |
| 18 |
def __init__(self, params): |
default_action_list = [("hide_medium_urgency", "lower urgencies"), |
| 19 |
self.hide_medium_urgency = int(params.get('hide_medium_urgency', |
("hide_non_remote", "local vulnerabilities")] |
| 20 |
(0,))[0]) |
def __init__(self, params, action_list=None): |
| 21 |
self.hide_non_remote = int(params.get('hide_non_remote', |
if action_list is None: |
| 22 |
(0,))[0]) |
self.action_list = self.default_action_list |
| 23 |
|
else: |
| 24 |
|
self.action_list = action_list |
| 25 |
|
self.params = {} |
| 26 |
|
for (prop, desc) in self.action_list: |
| 27 |
|
self.params[prop] = int(params.get(prop, (0,))[0]) |
| 28 |
|
|
| 29 |
def actions(self, url): |
def actions(self, url): |
| 30 |
"""Returns a HTML snippet which can be used to change the filter.""" |
"""Returns a HTML snippet which can be used to change the filter.""" |
| 31 |
if self.hide_medium_urgency: |
|
| 32 |
urg = A(url.updateParams(hide_medium_urgency=None), |
l = [] |
| 33 |
'Show lower urgencies') |
for (prop, desc) in self.action_list: |
| 34 |
else: |
if self.params[prop]: |
| 35 |
urg = A(url.updateParams(hide_medium_urgency='1'), |
a = A(url.updateParamsDict({prop : None}), |
| 36 |
'Hide lower urgencies') |
'Show ' + desc) |
| 37 |
if self.hide_non_remote: |
else: |
| 38 |
rem = A(url.updateParams(hide_non_remote=None), |
a = A(url.updateParamsDict({prop : '1'}), |
| 39 |
'Show local vulnerabilities') |
'Hide ' + desc) |
| 40 |
else: |
l.append(a) |
| 41 |
rem = A(url.updateParams(hide_non_remote='1'), |
l.append(' ') |
| 42 |
'Hide local vulnerabilities') |
|
| 43 |
return P(urg, ' ', rem) |
return apply(P, l[:-1]) |
| 44 |
|
|
| 45 |
def urgencyFiltered(self, urg): |
def urgencyFiltered(self, urg): |
| 46 |
"""Returns True if the urgency urg is filtered.""" |
"""Returns True if the urgency urg is filtered.""" |
| 47 |
return self.hide_medium_urgency and urg not in ("high", "unknown", "") |
return self.params['hide_medium_urgency'] \ |
| 48 |
|
and urg not in ("high", "unknown", "") |
| 49 |
|
|
| 50 |
def remoteFiltered(self, remote): |
def remoteFiltered(self, remote): |
| 51 |
"""Returns True if the attack range is filtered.""" |
"""Returns True if the attack range is filtered.""" |
| 52 |
return remote is not None and self.hide_non_remote and not remote |
return remote is not None and self.params['hide_non_remote'] \ |
| 53 |
|
and not remote |
| 54 |
|
|
| 55 |
|
class BugFilterNoDSA(BugFilter): |
| 56 |
|
def __init__(self, params): |
| 57 |
|
BugFilter.__init__(self, params, self.default_action_list |
| 58 |
|
+ [('hide_nodsa', 'non-DSA vulnerabilities')]) |
| 59 |
|
self.hide_nodsa = int(params.get('hide_nodsa',(0,))[0]) |
| 60 |
|
|
| 61 |
|
def nodsaFiltered(self, nodsa): |
| 62 |
|
"""Returns True if no DSA will be issued for the bug.""" |
| 63 |
|
return nodsa and self.params['hide_nodsa'] |
| 64 |
|
|
| 65 |
class TrackerService(WebService): |
class TrackerService(WebService): |
| 66 |
head_contents = compose(STYLE( |
head_contents = compose(STYLE( |
| 120 |
self.register('data/funny-versions', self.page_data_funny_versions) |
self.register('data/funny-versions', self.page_data_funny_versions) |
| 121 |
self.register('data/fake-names', self.page_data_fake_names) |
self.register('data/fake-names', self.page_data_fake_names) |
| 122 |
self.register('debsecan/**', self.page_debsecan) |
self.register('debsecan/**', self.page_debsecan) |
| 123 |
|
self.register('data/report', self.page_report) |
| 124 |
|
|
| 125 |
def page_home(self, path, params, url): |
def page_home(self, path, params, url): |
| 126 |
query = params.get('query', ('',))[0] |
query = params.get('query', ('',))[0] |
| 133 |
return self.create_page( |
return self.create_page( |
| 134 |
url, 'Security Bug Tracker', |
url, 'Security Bug Tracker', |
| 135 |
[P( |
[P( |
| 136 |
"""This is the experimental issue tracker for Debian's testing |
"""The data in this tracker comes solely from the bug database maintained |
| 137 |
security team. Keep in mind that this is merely a prototype. |
by Debian's security team located in the testing-security Subversion """, |
| 138 |
Please report any problems to """, |
A("http://svn.debian.org/wsvn/secure-testing/data", "repository"), |
| 139 |
A("mailto:fw@deneb.enyo.de", "Florian Weimer"), |
""". The data represented here is derived from: """, |
| 140 |
""".Note that some of the data presented here is known |
A("http://www.debian.org/security/#DSAS", "DSAs"), |
| 141 |
to be wrong (see below), but the data for the testing suite |
""" issued by the Security Team; issues tracked in the """, |
| 142 |
should be fine."""), |
A("http://www.cve.mitre.org/cve/index.html", "CVE database"), |
| 143 |
make_menu( |
""", issues tracked in the """, |
| 144 |
|
A("http://nvd.nist.gov/", "National Vulnerability Database"), |
| 145 |
|
""" (NVD), maintained by NIST; and security issues |
| 146 |
|
discovered in Debian packages as reported in the BTS."""), |
| 147 |
|
P("""All exteral data (including Debian bug reports and official Debian |
| 148 |
|
security advisories) must be added to this database before it appears |
| 149 |
|
here. Please help us keep this information up-to-date by """, |
| 150 |
|
A(url.scriptRelative("data/report"), "reporting"), |
| 151 |
|
""" any discrepancies or change of states that you are |
| 152 |
|
aware of and/or help us improve the quality of this information by """, |
| 153 |
|
A(url.scriptRelative("data/report"), "participating"), |
| 154 |
|
"."), |
| 155 |
|
make_menu( |
| 156 |
url.scriptRelative, |
url.scriptRelative, |
| 157 |
('status/release/unstable', |
('status/release/unstable', |
| 158 |
'Vulnerable packages in the unstable suite'), |
'Vulnerable packages in the unstable suite'), |
| 180 |
P("""(You can enter CVE names, Debian bug numbers and package |
P("""(You can enter CVE names, Debian bug numbers and package |
| 181 |
names in the search forms.)"""), |
names in the search forms.)"""), |
| 182 |
|
|
|
H2("Data sources"), |
|
|
P("""Data in this tracker comes solely from the bug database |
|
|
which is maintained by Debian's testing security team in their |
|
|
Subversion repository. All external data (this includes |
|
|
Debian bug reports and official Debian security advisories) |
|
|
must be added to this database before it appears here, and there |
|
|
can be some delay before this happens."""), |
|
|
P("""At the moment, the database only contains information which is |
|
|
relevant for tracking the security status of the stable, testing and |
|
|
unstable suites. This means that data for oldstable is likely wrong."""), |
|
|
P('Data marked "NVD" comes from the ', |
|
|
A(url.absolute('http://nvd.nist.gov/'), |
|
|
'National Vulnerability Database'), |
|
|
' maintained by NIST.'), |
|
|
|
|
| 183 |
H2("External interfaces"), |
H2("External interfaces"), |
| 184 |
P("""If you want to automatically open a relevant web page for |
P("""If you want to automatically open a relevant web page for |
| 185 |
some object, use the """, |
some object, use the """, |
| 203 |
if not obj: |
if not obj: |
| 204 |
# Redirect to start page. |
# Redirect to start page. |
| 205 |
return RedirectResult(url.scriptRelativeFull("")) |
return RedirectResult(url.scriptRelativeFull("")) |
|
|
|
|
if 'A' <= obj[0] <= 'Z': |
|
|
# Bug names start with a capital letter. |
|
|
return self.page_bug(url, obj, redirect) |
|
| 206 |
|
|
| 207 |
|
# Attempt to decode a bug number. FAKE-nnn bugs (but not |
| 208 |
|
# FAKE-nnn-mmm bugs) are treated as bug references, too. |
| 209 |
bugnumber = 0 |
bugnumber = 0 |
| 210 |
|
fake_bug = False |
| 211 |
try: |
try: |
| 212 |
bugnumber = int(obj) |
if obj[0:5] == 'FAKE-': |
| 213 |
|
bugnumber = int(obj[5:]) |
| 214 |
|
fake_bug = True |
| 215 |
|
else: |
| 216 |
|
bugnumber = int(obj) |
| 217 |
except ValueError: |
except ValueError: |
| 218 |
pass |
pass |
| 219 |
if bugnumber: |
if bugnumber: |
| 220 |
buglist = list(self.db.getBugsFromDebianBug(c, bugnumber)) |
buglist = list(self.db.getBugsFromDebianBug(c, bugnumber)) |
| 221 |
if buglist: |
if buglist: |
| 222 |
return self.page_debian_bug(url, bugnumber, buglist) |
return self.page_debian_bug(url, bugnumber, buglist, fake_bug) |
| 223 |
if redirect: |
if redirect: |
| 224 |
return RedirectResult(self.url_debian_bug(url, str(bugnumber)), |
return RedirectResult(self.url_debian_bug(url, str(bugnumber)), |
| 225 |
permanent=False) |
permanent=False) |
| 226 |
|
|
| 227 |
|
if 'A' <= obj[0] <= 'Z': |
| 228 |
|
# Bug names start with a capital letter. |
| 229 |
|
return self.page_bug(url, obj, redirect) |
| 230 |
|
|
| 231 |
if self.db.isSourcePackage(c, obj): |
if self.db.isSourcePackage(c, obj): |
| 232 |
return RedirectResult(self.url_source_package(url, obj, full=True)) |
return RedirectResult(self.url_source_package(url, obj, full=True)) |
| 233 |
if self.db.isBinaryPackage(c, obj): |
if self.db.isBinaryPackage(c, obj): |
| 418 |
|
|
| 419 |
return self.create_page(url, bug.name, page) |
return self.create_page(url, bug.name, page) |
| 420 |
|
|
| 421 |
def page_debian_bug(self, url, bugnumber, buglist): |
def page_debian_bug(self, url, bugnumber, buglist, fake_bug): |
| 422 |
|
if fake_bug: |
| 423 |
|
new_buglist = [] |
| 424 |
|
for b in buglist: |
| 425 |
|
(bug_name, urgency, description) = b |
| 426 |
|
if bug_name[0:5] == "FAKE-": |
| 427 |
|
new_buglist.append(b) |
| 428 |
|
if len(new_buglist) > 0: |
| 429 |
|
# Only replace the bug list if there are still fake |
| 430 |
|
# bug reports. |
| 431 |
|
buglist = new_buglist |
| 432 |
|
|
| 433 |
if len(buglist) == 1: |
if len(buglist) == 1: |
| 434 |
# Single issue, redirect. |
# Single issue, redirect. |
| 435 |
return RedirectResult(url.scriptRelativeFull(buglist[0][0])) |
return RedirectResult(url.scriptRelativeFull(buglist[0][0])) |
| 440 |
urgency = "" |
urgency = "" |
| 441 |
yield self.make_xref(url, name), urgency, description |
yield self.make_xref(url, name), urgency, description |
| 442 |
|
|
| 443 |
|
if fake_bug: |
| 444 |
|
intro = """The URL you used contained a non-stable name |
| 445 |
|
based on a Debian bug number. This name cannot be mapped to a specific |
| 446 |
|
issue. """ |
| 447 |
|
else: |
| 448 |
|
intro = "" |
| 449 |
|
|
| 450 |
return self.create_page( |
return self.create_page( |
| 451 |
url, "Information related to Debian bug #%d" % bugnumber, |
url, "Information related to Debian bug #%d" % bugnumber, |
| 452 |
[P("The following issues reference to Debian bug ", |
[P(intro + "The following issues reference to Debian bug ", |
| 453 |
self.make_debian_bug(url, bugnumber), ":"), |
self.make_debian_bug(url, bugnumber), ":"), |
| 454 |
make_table(gen(), |
make_table(gen(), |
| 455 |
caption=("Name", "Urgency", "Description"))]) |
caption=("Name", "Urgency", "Description"))]) |
| 461 |
' matched no results.')], |
' matched no results.')], |
| 462 |
status=404) |
status=404) |
| 463 |
|
|
| 464 |
|
def page_report(self, path, params, url): |
| 465 |
|
return self.create_page( |
| 466 |
|
url, 'Reporting discrepancies in the data', |
| 467 |
|
[P("""The data in this tracker is always in flux, as bugs are fixed and new |
| 468 |
|
issues disclosed, the data contained herein is updated. We strive to |
| 469 |
|
maintain complete and accurate state information, and appreciate any |
| 470 |
|
updates in status, information or new issues."""), |
| 471 |
|
P("There are three ways that you can report updates to this information:"), |
| 472 |
|
make_numbered_list( |
| 473 |
|
[P("""IRC: We can be found at """, |
| 474 |
|
CODE("irc.oftc.net"), |
| 475 |
|
", ", |
| 476 |
|
CODE("#debian-security"), |
| 477 |
|
""". If you have information to report, please go ahead and join |
| 478 |
|
the channel and tell us. Please feel free to state the issue, |
| 479 |
|
regardless if there is someone who has acknowledged you. Many of us |
| 480 |
|
idle on this channel and may not be around when you join, but we read |
| 481 |
|
the backlog and will see what you have said. If you require a |
| 482 |
|
response, do not forget to let us know how to get a hold of you."""), |
| 483 |
|
P("Mailing list: Our mailing list is: ", |
| 484 |
|
A("mailto:secure-testing-team@lists.alioth.debian.org", |
| 485 |
|
"secure-testing-team@lists.alioth.debian.org")), |
| 486 |
|
P("""Helping out: We welcome people who wish to join us in tracking |
| 487 |
|
issues. The process is designed to be easy to learn and participate, |
| 488 |
|
please read our """, |
| 489 |
|
A("http://svn.debian.org/wsvn/secure-testing/doc/narrative_introduction?op=file&rev=0&sc=0", |
| 490 |
|
"Introduction"), |
| 491 |
|
""" to get familiar with how things work. Join us on |
| 492 |
|
our mailing list, and on IRC and request to be added to the Alioth """, |
| 493 |
|
A("http://alioth.debian.org/projects/secure-testing/", "project"), |
| 494 |
|
""". We are really quite friendly. If you have a |
| 495 |
|
question about how things work, don't be afraid to ask, we would like |
| 496 |
|
to improve our documentation and procedures, so feedback is welcome.""")])]) |
| 497 |
|
|
| 498 |
def page_source_package(self, path, params, url): |
def page_source_package(self, path, params, url): |
| 499 |
pkg = path[0] |
pkg = path[0] |
| 500 |
|
|
| 587 |
def page_status_release_stable_oldstable(self, release, params, url): |
def page_status_release_stable_oldstable(self, release, params, url): |
| 588 |
assert release in ('stable', 'oldstable') |
assert release in ('stable', 'oldstable') |
| 589 |
|
|
| 590 |
bf = BugFilter(params) |
bf = BugFilterNoDSA(params) |
| 591 |
|
|
| 592 |
def gen(): |
def gen(): |
| 593 |
old_pkg_name = '' |
old_pkg_name = '' |
| 594 |
for (pkg_name, bug_name, archive, urgency, remote) in \ |
for (pkg_name, bug_name, archive, urgency, remote, no_dsa) in \ |
| 595 |
self.db.cursor().execute( |
self.db.cursor().execute( |
| 596 |
"""SELECT package, bug, section, urgency, remote |
"""SELECT package, bug, section, urgency, remote, no_dsa |
| 597 |
FROM %s_status""" % release): |
FROM %s_status""" % release): |
| 598 |
if bf.urgencyFiltered(urgency): |
if bf.urgencyFiltered(urgency): |
| 599 |
continue |
continue |
| 600 |
if bf.remoteFiltered(remote): |
if bf.remoteFiltered(remote): |
| 601 |
continue |
continue |
| 602 |
|
if bf.nodsaFiltered(no_dsa): |
| 603 |
|
continue |
| 604 |
|
|
| 605 |
if pkg_name == old_pkg_name: |
if pkg_name == old_pkg_name: |
| 606 |
pkg_name = '' |
pkg_name = '' |
| 617 |
remote = 'no' |
remote = 'no' |
| 618 |
|
|
| 619 |
if urgency == 'unknown': |
if urgency == 'unknown': |
| 620 |
urgency = '' |
if no_dsa: |
| 621 |
|
urgency = 'no DSA' |
| 622 |
|
else: |
| 623 |
|
urgency = '' |
| 624 |
elif urgency == 'high': |
elif urgency == 'high': |
| 625 |
urgency = self.make_red(urgency) |
urgency = self.make_red(urgency) |
| 626 |
|
else: |
| 627 |
|
if no_dsa: |
| 628 |
|
urgency = urgency + '*' |
| 629 |
|
|
| 630 |
yield pkg_name, self.make_xref(url, bug_name), urgency, remote |
yield pkg_name, self.make_xref(url, bug_name), urgency, remote |
| 631 |
|
|
| 633 |
url, 'Vulnerable source packages in the %s suite' % release, |
url, 'Vulnerable source packages in the %s suite' % release, |
| 634 |
[bf.actions(url), |
[bf.actions(url), |
| 635 |
make_table(gen(), caption=("Package", "Bug", "Urgency", |
make_table(gen(), caption=("Package", "Bug", "Urgency", |
| 636 |
"Remote"))]) |
"Remote")), |
| 637 |
|
P('''(If a "*" is included in the urgency field, no DSA is planned |
| 638 |
|
for this vulnerability.)''')]) |
| 639 |
|
|
| 640 |
def page_status_release_stable(self, path, params, url): |
def page_status_release_stable(self, path, params, url): |
| 641 |
return self.page_status_release_stable_oldstable('stable', params, url) |
return self.page_status_release_stable_oldstable('stable', params, url) |
| 825 |
"Remote"))]) |
"Remote"))]) |
| 826 |
|
|
| 827 |
def page_status_todo(self, path, params, url): |
def page_status_todo(self, path, params, url): |
| 828 |
|
hide_check = params.get('hide_check', False) |
| 829 |
|
if hide_check: |
| 830 |
|
flags = A(url.updateParamsDict({'hide_check' : None}), |
| 831 |
|
'Show "check" TODOs') |
| 832 |
|
else: |
| 833 |
|
flags = A(url.updateParamsDict({'hide_check' : '1'}), |
| 834 |
|
'Hide "check" TODOs') |
| 835 |
|
|
| 836 |
def gen(): |
def gen(): |
| 837 |
for (bug, description) in self.db.getTODOs(): |
for (bug, description) in self.db.getTODOs(hide_check=hide_check): |
| 838 |
yield self.make_xref(url, bug), description |
yield self.make_xref(url, bug), description |
| 839 |
return self.create_page( |
return self.create_page( |
| 840 |
url, "Bugs with TODO items", |
url, "Bugs with TODO items", |
| 841 |
[make_table(gen(), |
[P(flags), |
| 842 |
|
make_table(gen(), |
| 843 |
caption=("Bug", "Description"))]) |
caption=("Bug", "Description"))]) |
| 844 |
|
|
| 845 |
def page_status_itp(self, path, params, url): |
def page_status_itp(self, path, params, url): |
| 1072 |
onkeyup="onSearch(this.value)", |
onkeyup="onSearch(this.value)", |
| 1073 |
onmousemove="onSearch(this.value)"), |
onmousemove="onSearch(this.value)"), |
| 1074 |
INPUT(type='submit', value='Go'), |
INPUT(type='submit', value='Go'), |
| 1075 |
|
' ', |
| 1076 |
|
A(url.scriptRelative("data/report"), "Reporting problems"), |
| 1077 |
method='get', |
method='get', |
| 1078 |
action=url.scriptRelative('')) |
action=url.scriptRelative('')) |
| 1079 |
|
|