/[secure-testing]/bin/tracker_service.py
ViewVC logotype

Contents of /bin/tracker_service.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 11220 - (show annotations) (download) (as text)
Sun Feb 15 13:29:11 2009 UTC (4 years, 4 months ago) by fw
File MIME type: text/script
File size: 50876 byte(s)
bin/tracker_service.py: provide a link to the oldstable page
1 #!/usr/bin/python
2
3 import sys
4 sys.path.insert(0,'../lib/python')
5
6 if len(sys.argv) <> 3:
7 print "usage: python tracker_serivce.py SOCKET-PATH DATABASE-PATH"
8 sys.exit(1)
9 socket_name = sys.argv[1]
10 db_name = sys.argv[2]
11
12 import bugs
13 import re
14 import security_db
15 from web_support import *
16
17 class BugFilter:
18 default_action_list = [("hide_medium_urgency", "lower urgencies"),
19 ("hide_non_remote", "local vulnerabilities")]
20 def __init__(self, params, action_list=None):
21 if action_list is None:
22 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):
30 """Returns a HTML snippet which can be used to change the filter."""
31
32 l = []
33 for (prop, desc) in self.action_list:
34 if self.params[prop]:
35 a = A(url.updateParamsDict({prop : None}),
36 'Show ' + desc)
37 else:
38 a = A(url.updateParamsDict({prop : '1'}),
39 'Hide ' + desc)
40 l.append(a)
41 l.append(' ')
42
43 return apply(P, l[:-1])
44
45 def urgencyFiltered(self, urg):
46 """Returns True if the urgency urg is filtered."""
47 return self.params['hide_medium_urgency'] \
48 and urg not in ("high", "unknown", "")
49
50 def remoteFiltered(self, remote):
51 """Returns True if the attack range is filtered."""
52 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):
66 head_contents = compose(STYLE(
67 """h1 { font-size : 144%; }
68 h2 { font-size : 120%; }
69 h3 { font-size : 100%; }
70
71 table { padding-left : 1.5em }
72 td, th { text-align : left;
73 padding-left : 0.25em;
74 padding-right : 0.25em; }
75 td { vertical-align: baseline }
76 span.red { color: red; }
77 span.dangerous { color: rgb(191,127,0); }
78 """), SCRIPT('''var old_query_value = "";
79
80 function selectSearch() {
81 document.searchForm.query.focus();
82 }
83
84 function onSearch(query) {
85 if (old_query_value == "") {
86 if (query.length > 5) {
87 old_query_value = query;
88 document.searchForm.submit();
89 } else {
90 old_query_value = query;
91 }
92 }
93 }
94 ''')).toHTML()
95
96 def __init__(self, socket_name, db_name):
97 WebService.__init__(self, socket_name)
98 self.db = security_db.DB(db_name)
99 self.register('', self.page_home)
100 self.register('*', self.page_object)
101 self.register('redirect/*', self.page_redirect)
102 self.register('source-package/*', self.page_source_package)
103 self.register('binary-package/*', self.page_binary_package)
104 self.register('status/release/oldstable',
105 self.page_status_release_oldstable)
106 self.register('status/release/stable', self.page_status_release_stable)
107 self.register('status/release/stable-backports',
108 self.page_status_release_stable_backports)
109 self.register('status/release/testing',
110 self.page_status_release_testing)
111 self.register('status/release/unstable',
112 self.page_status_release_unstable)
113 self.register('status/dtsa-candidates',
114 self.page_status_dtsa_candidates)
115 self.register('status/todo', self.page_status_todo)
116 self.register('status/itp', self.page_status_itp)
117 self.register('data/unknown-packages', self.page_data_unknown_packages)
118 self.register('data/missing-epochs', self.page_data_missing_epochs)
119 self.register('data/latently-vulnerable',
120 self.page_data_latently_vulnerable)
121 self.register('data/releases', self.page_data_releases)
122 self.register('data/funny-versions', self.page_data_funny_versions)
123 self.register('data/fake-names', self.page_data_fake_names)
124 self.register('debsecan/**', self.page_debsecan)
125 self.register('data/report', self.page_report)
126
127 def page_home(self, path, params, url):
128 query = params.get('query', ('',))[0]
129 if query:
130 if '/' in query:
131 return self.page_not_found(url, query)
132 else:
133 return RedirectResult(url.scriptRelativeFull(query))
134
135 return self.create_page(
136 url, 'Security Bug Tracker',
137 [P(
138 """The data in this tracker comes solely from the bug database maintained
139 by Debian's security team located in the testing-security Subversion """,
140 A("http://svn.debian.org/wsvn/secure-testing/data", "repository"),
141 """. The data represented here is derived from: """,
142 A("http://www.debian.org/security/#DSAS", "DSAs"),
143 """ issued by the Security Team; issues tracked in the """,
144 A("http://cve.mitre.org/cve/", "CVE database"),
145 """, issues tracked in the """,
146 A("http://nvd.nist.gov/", "National Vulnerability Database"),
147 """ (NVD), maintained by NIST; and security issues
148 discovered in Debian packages as reported in the BTS."""),
149 P("""All external data (including Debian bug reports and official Debian
150 security advisories) must be added to this database before it appears
151 here. Please help us keep this information up-to-date by """,
152 A(url.scriptRelative("data/report"), "reporting"),
153 """ any discrepancies or change of states that you are
154 aware of and/or help us improve the quality of this information by """,
155 A(url.scriptRelative("data/report"), "participating"),
156 "."),
157 make_menu(
158 url.scriptRelative,
159 ('status/release/unstable',
160 'Vulnerable packages in the unstable suite'),
161 ('status/release/testing',
162 'Vulnerable packages in the testing suite'),
163 ('status/release/stable',
164 'Vulnerable packages in the stable suite'),
165 ('status/release/oldstable',
166 'Vulnerable packages in the old stable suite'),
167 ('status/release/stable-backports',
168 'Vulnerable packages in backports for stable'),
169 ('status/dtsa-candidates', "Candidates for DTSAs"),
170 ('status/todo', 'TODO items'),
171 ('status/itp', 'ITPs with potential security issues'),
172 ('data/unknown-packages',
173 'Packages names not found in the archive'),
174 ('data/fake-names', 'Tracked issues without a CVE name'),
175 ('data/missing-epochs',
176 'Package versions which might lack an epoch'),
177 ('data/latently-vulnerable',
178 'Packages which are latently vulnerable in unstable'),
179 ('data/funny-versions',
180 'Packages with strange version numbers'),
181 ('data/releases',
182 'Covered Debian releases and architectures (slow)'),
183 self.make_search_button(url)),
184 P("""(You can enter CVE names, Debian bug numbers and package
185 names in the search forms.)"""),
186
187 H2("External interfaces"),
188 P("""If you want to automatically open a relevant web page for
189 some object, use the """,
190 CODE(str(url.scriptRelative("redirect/")), EM("object")),
191 """ URL. If no information is contained in this database,
192 the browser is automatically redirected to the corresponding external
193 data source.""")],
194 search_in_page=True)
195
196 def page_object(self, path, params, url):
197 obj = path[0]
198 return self.page_object_or_redirect(url, obj, False)
199
200 def page_redirect(self, path, params, url):
201 obj = path[0]
202 return self.page_object_or_redirect(url, obj, True)
203
204 def page_object_or_redirect(self, url, obj, redirect):
205 c = self.db.cursor()
206
207 if not obj:
208 # Redirect to start page.
209 return RedirectResult(url.scriptRelativeFull(""))
210
211 # Attempt to decode a bug number. TEMP-nnn bugs (but not
212 # TEMP-nnn-mmm bugs) are treated as bug references, too.
213 bugnumber = 0
214 fake_bug = False
215 try:
216 if obj[0:5] == 'FAKE-' or obj[0:5] == 'TEMP-':
217 bugnumber = int(obj[5:])
218 fake_bug = True
219 else:
220 bugnumber = int(obj)
221 except ValueError:
222 pass
223 if bugnumber:
224 buglist = list(self.db.getBugsFromDebianBug(c, bugnumber))
225 if buglist:
226 return self.page_debian_bug(url, bugnumber, buglist, fake_bug)
227 if redirect:
228 return RedirectResult(self.url_debian_bug(url, str(bugnumber)),
229 permanent=False)
230
231 if 'A' <= obj[0] <= 'Z':
232 # Bug names start with a capital letter.
233 return self.page_bug(url, obj, redirect)
234
235 if self.db.isSourcePackage(c, obj):
236 return RedirectResult(self.url_source_package(url, obj, full=True))
237 if self.db.isBinaryPackage(c, obj):
238 return RedirectResult(self.url_binary_package(url ,obj, full=True))
239
240 return self.page_not_found(url, obj)
241
242 def page_bug(self, url, name, redirect):
243 # FIXME: Normalize CAN-* to CVE-* when redirecting. Too many
244 # people still use CAN.
245 if redirect and name[0:4] == 'CAN-':
246 name = 'CVE-' + name[4:]
247
248 cursor = self.db.cursor()
249 try:
250 bug = bugs.BugFromDB(cursor, name)
251 except ValueError:
252 if redirect:
253 if name[0:4] == 'CVE-':
254 return RedirectResult(self.url_cve(url, name),
255 permanent=False)
256 return self.page_not_found(url, name)
257 if bug.name <> name or redirect:
258 # Show the normalized bug name in the browser address bar.
259 return RedirectResult(url.scriptRelativeFull(bug.name))
260
261 page = []
262
263 def gen_header():
264 yield B("Name"), bug.name
265
266 source = bug.name.split('-')[0]
267 if source == 'CVE':
268 source_xref = compose(self.make_cve_ref(url, bug.name, 'CVE'),
269 " (",
270 self.make_nvd_ref(url, bug.name,
271 'in NVD'),
272 ")")
273 elif source == 'DSA':
274 source_xref = self.make_dsa_ref(url, bug.name, 'Debian')
275 elif source == 'DTSA':
276 source_xref = 'Debian Testing Security Team'
277 elif source == 'TEMP':
278 source_xref = (
279 'Automatically generated temporary name. Not for external reference.')
280 else:
281 source_xref = None
282
283 if source_xref:
284 yield B("Source"), source_xref
285
286 nvd = self.db.getNVD(cursor, bug.name)
287
288 if nvd and nvd.cve_desc:
289 yield B("Description"), nvd.cve_desc
290 elif bug.description:
291 yield B("Description"), bug.description
292
293 xref = list(self.db.getBugXrefs(cursor, bug.name))
294 if xref:
295 yield B("References"), self.make_xref_list(url, xref)
296
297 if nvd:
298 nvd_range = nvd.rangeString()
299 if nvd.severity:
300 nvd_severity = nvd.severity.lower()
301 if nvd_range:
302 nvd_severity = "%s (attack range: %s)" \
303 % (nvd_severity, nvd_range)
304 yield B("NVD severity"), nvd_severity
305
306 debian_bugs = bug.getDebianBugs(cursor)
307 if debian_bugs:
308 yield (B("Debian Bugs"),
309 self.make_debian_bug_list(url, debian_bugs))
310
311 if not bug.not_for_us:
312 for (release, status, reason) in bug.getStatus(cursor):
313 if status <> 'fixed':
314 reason = self.make_red(reason)
315 yield B('Debian/%s' % release), reason
316
317 page.append(make_table(gen_header()))
318
319 if bug.notes:
320 page.append(H2("Vulnerable and fixed packages"))
321
322 def gen_source():
323 old_pkg = ''
324 for (package, release, version, vulnerable) \
325 in self.db.getSourcePackages(cursor, bug.name):
326 if package == old_pkg:
327 package = ''
328 else:
329 old_pkg = package
330 package = compose(
331 self.make_source_package_ref(url, package),
332 " (", self.make_pts_ref(url, package, 'PTS'), ")")
333 if vulnerable:
334 vuln = self.make_red('vulnerable')
335 version = self.make_red(version)
336 else:
337 vuln = 'fixed'
338
339 yield package, ', '.join(release), version, vuln
340
341 page.append(make_table(gen_source(),
342 caption=("Source Package", "Release", "Version", "Status"),
343 introduction=P('The table below lists information on source packages.')))
344
345 def gen_binary():
346 old_pkg = ''
347 for (packages, releases, version, archs, vulnerable) \
348 in self.db.getBinaryPackages(cursor, bug.name):
349 pkg = ', '.join(packages)
350 if pkg == old_pkg:
351 packages = ''
352 else:
353 old_pkg = pkg
354 packages = self.make_binary_packages_ref(url, packages)
355
356 if vulnerable:
357 vuln = self.make_red('vulnerable')
358 version = self.make_red(version)
359 else:
360 vuln = 'fixed'
361 yield (packages,
362 ', '.join(releases),
363 version, vuln,
364 ', '.join(archs))
365
366 page.append(make_table(gen_binary(),
367 caption=("Binary Package", "Release", "Version", "Status",
368 "Architecures"),
369 introduction=P("The next table lists affected binary packages.")))
370
371 def gen_data():
372 notes_sorted = bug.notes[:]
373 notes_sorted.sort(lambda a, b: cmp(a.package, b.package))
374 for n in notes_sorted:
375 if n.release:
376 rel = str(n.release)
377 else:
378 rel = '(unstable)'
379 urgency = str(n.urgency)
380 if n.fixed_version:
381 ver = str(n.fixed_version)
382 if ver == '0':
383 ver = '(not affected)'
384 urgency = ''
385 else:
386 ver = self.make_red('(unfixed)')
387
388 pkg = n.package
389 pkg_kind = n.package_kind
390 if pkg_kind == 'source':
391 pkg = self.make_source_package_ref(url, pkg)
392 elif pkg_kind == 'binary':
393 pkg = self.make_binary_package_ref(url, pkg)
394 elif pkg_kind == 'itp':
395 pkg_kind = 'ITP'
396 rel = ''
397 ver = ''
398 urgency = ''
399
400 bugs = n.bugs
401 bugs.sort()
402 bugs = make_list(
403 map(lambda x: self.make_debian_bug(url, x), bugs))
404 if n.bug_origin:
405 origin = self.make_xref(url, n.bug_origin)
406 else:
407 origin = ''
408 yield (pkg, pkg_kind, rel, ver, urgency, origin, bugs)
409
410 page.append(
411 make_table(gen_data(),
412 caption=("Package", "Type", "Release", "Fixed Version",
413 "Urgency", "Origin", "Debian Bugs"),
414 introduction=P("The information above is based on the following data on fixed versions.")))
415
416 if bug.comments:
417 page.append(H2("Notes"))
418 def gen_comments():
419 for (t, c) in bug.comments:
420 yield c
421 page.append(make_pre(gen_comments()))
422
423 return self.create_page(url, bug.name, page)
424
425 def page_debian_bug(self, url, bugnumber, buglist, fake_bug):
426 if fake_bug:
427 new_buglist = []
428 for b in buglist:
429 (bug_name, urgency, description) = b
430 if bug_name[0:5] == 'FAKE-' or bug_name[0:5] == 'TEMP-':
431 new_buglist.append(b)
432 if len(new_buglist) > 0:
433 # Only replace the bug list if there are still fake
434 # bug reports.
435 buglist = new_buglist
436
437 if len(buglist) == 1:
438 # Single issue, redirect.
439 return RedirectResult(url.scriptRelativeFull(buglist[0][0]))
440
441 def gen():
442 for (name, urgency, description) in buglist:
443 if urgency == "unknown":
444 urgency = ""
445 yield self.make_xref(url, name), urgency, description
446
447 if fake_bug:
448 intro = """The URL you used contained a non-stable name
449 based on a Debian bug number. This name cannot be mapped to a specific
450 issue. """
451 else:
452 intro = ""
453
454 return self.create_page(
455 url, "Information related to Debian bug #%d" % bugnumber,
456 [P(intro + "The following issues reference to Debian bug ",
457 self.make_debian_bug(url, bugnumber), ":"),
458 make_table(gen(),
459 caption=("Name", "Urgency", "Description"))])
460
461 def page_not_found(self, url, query):
462 return self.create_page(url, 'Not found',
463 [P('Your query ',
464 CODE(query),
465 ' matched no results.')],
466 status=404)
467
468 def page_report(self, path, params, url):
469 return self.create_page(
470 url, 'Reporting discrepancies in the data',
471 [P("""The data in this tracker is always in flux, as bugs are fixed and new
472 issues disclosed, the data contained herein is updated. We strive to
473 maintain complete and accurate state information, and appreciate any
474 updates in status, information or new issues."""),
475 P("There are three ways that you can report updates to this information:"),
476 make_numbered_list(
477 [P("""IRC: We can be found at """,
478 CODE("irc.oftc.net"),
479 ", ",
480 CODE("#debian-security"),
481 """. If you have information to report, please go ahead and join
482 the channel and tell us. Please feel free to state the issue,
483 regardless if there is someone who has acknowledged you. Many of us
484 idle on this channel and may not be around when you join, but we read
485 the backlog and will see what you have said. If you require a
486 response, do not forget to let us know how to get a hold of you."""),
487 P("Mailing list: Our mailing list is: ",
488 A("mailto:debian-security-tracker@lists.debian.org",
489 "debian-security-tracker@lists.debian.org")),
490 P("""Helping out: We welcome people who wish to join us in tracking
491 issues. The process is designed to be easy to learn and participate,
492 please read our """,
493 A("http://svn.debian.org/wsvn/secure-testing/doc/narrative_introduction?op=file&rev=0&sc=0",
494 "Introduction"),
495 """ to get familiar with how things work. Join us on
496 our mailing list, and on IRC and request to be added to the Alioth """,
497 A("http://alioth.debian.org/projects/secure-testing/", "project"),
498 """. We are really quite friendly. If you have a
499 question about how things work, don't be afraid to ask, we would like
500 to improve our documentation and procedures, so feedback is welcome.""")])])
501
502 def page_source_package(self, path, params, url):
503 pkg = path[0]
504
505 def gen_versions():
506 for (releases, version) in self.db.getSourcePackageVersions(
507 self.db.cursor(), pkg):
508 yield ', '.join(releases), version
509 def gen_binary():
510 for (packages, releases, archs, version) \
511 in self.db.getBinaryPackagesForSource(
512 self.db.cursor(), pkg):
513 yield (self.make_binary_packages_ref(url, packages),
514 ', '.join(releases), version, ', '.join(archs))
515 def gen_bug_list(lst):
516 for (bug, description) in lst:
517 yield self.make_xref(url, bug), description
518
519 return self.create_page(
520 url, "Information on source package " + pkg,
521 [make_menu(lambda x: x,
522 (self.url_pts(url, pkg),
523 pkg + ' in the Package Tracking System'),
524 (self.url_debian_bug_pkg(url, pkg),
525 pkg + ' in the Bug Tracking System'),
526 (self.url_testing_status(url, pkg),
527 pkg + ' in the testing migration checker')),
528 H2("Available versions"),
529 make_table(gen_versions(), caption=("Release", "Version")),
530
531 H2("Available binary packages"),
532 make_table(gen_binary(),
533 caption=('Package', 'Release', 'Version', 'Architectures'),
534 replacement="""No binary packages are recorded in this database.
535 This probably means that the package is architecture-specific, and the
536 architecture is currently not tracked."""),
537
538 H2("Open issues"),
539 make_table(gen_bug_list(self.db.getBugsForSourcePackage
540 (self.db.cursor(), pkg, True)),
541 caption=('Bug', 'Description'),
542 replacement='No known open issues.'),
543
544 H2("Resolved issues"),
545 make_table(gen_bug_list(self.db.getBugsForSourcePackage
546 (self.db.cursor(), pkg, False)),
547 caption=('Bug', 'Description'),
548 replacement='No known resolved issues.')])
549
550 def page_binary_package(self, path, params, url):
551 pkg = path[0]
552
553 def gen_versions():
554 for (releases, source, version, archs) \
555 in self.db.getBinaryPackageVersions(self.db.cursor(), pkg):
556 yield (', '.join(releases),
557 self.make_source_package_ref(url, source),
558 version, ', '.join(archs))
559 def gen_bug_list(lst):
560 for (bug, description) in lst:
561 yield self.make_xref(url, bug), description
562
563 return self.create_page(
564 url, "Information on binary package " + pkg,
565 [make_menu(lambda x: x,
566 (self.url_debian_bug_pkg(url, pkg),
567 pkg + ' in the Bug Tracking System')),
568 H2("Available versions"),
569 make_table(gen_versions(),
570 caption=("Release", "Source", "Version", "Architectures")),
571
572 H2("Open issues"),
573 make_table(gen_bug_list(self.db.getBugsForBinaryPackage
574 (self.db.cursor(), pkg, True)),
575 caption=('Bug', 'Description'),
576 replacement='No known open issues.'),
577
578 H2("Resolved issues"),
579 make_table(gen_bug_list(self.db.getBugsForBinaryPackage
580 (self.db.cursor(), pkg, False)),
581 caption=('Bug', 'Description'),
582 replacement='No known resolved issues.'),
583
584 H2("Non-issues"),
585 make_table(gen_bug_list(self.db.getNonBugsForBinaryPackage
586 (self.db.cursor(), pkg)),
587 caption=('Bug', 'Description'),
588 replacement="""No known issues which do not affect
589 this package, but still reference it.""")])
590
591 def page_status_release_stable_oldstable(self, release, params, url):
592 assert release in ('stable', 'oldstable')
593
594 bf = BugFilterNoDSA(params)
595
596 def gen():
597 old_pkg_name = ''
598 for (pkg_name, bug_name, archive, urgency, remote, no_dsa) in \
599 self.db.cursor().execute(
600 """SELECT package, bug, section, urgency, remote, no_dsa
601 FROM %s_status""" % release):
602 if bf.urgencyFiltered(urgency):
603 continue
604 if bf.remoteFiltered(remote):
605 continue
606 if bf.nodsaFiltered(no_dsa):
607 continue
608
609 if pkg_name == old_pkg_name:
610 pkg_name = ''
611 else:
612 old_pkg_name = pkg_name
613 if archive <> 'main':
614 pkg_name = "%s (%s)" % (pkg_name, archive)
615
616 if remote is None:
617 remote = ''
618 elif remote:
619 remote = 'yes'
620 else:
621 remote = 'no'
622
623 if urgency == 'unknown':
624 if no_dsa:
625 urgency = 'no DSA'
626 else:
627 urgency = ''
628 elif urgency == 'high':
629 urgency = self.make_red(urgency)
630 else:
631 if no_dsa:
632 urgency = urgency + '*'
633
634 yield pkg_name, self.make_xref(url, bug_name), urgency, remote
635
636 return self.create_page(
637 url, 'Vulnerable source packages in the %s suite' % release,
638 [bf.actions(url),
639 make_table(gen(), caption=("Package", "Bug", "Urgency",
640 "Remote")),
641 P('''(If a "*" is included in the urgency field, no DSA is planned
642 for this vulnerability.)''')])
643
644 def page_status_release_stable(self, path, params, url):
645 return self.page_status_release_stable_oldstable('stable', params, url)
646 def page_status_release_oldstable(self, path, params, url):
647 return self.page_status_release_stable_oldstable('oldstable',
648 params, url)
649
650 def page_status_release_testing(self, path, params, url):
651 bf = BugFilterNoDSA(params)
652
653 def gen():
654 old_pkg_name = ''
655 for (pkg_name, bug_name, archive, urgency,
656 sid_vulnerable, ts_fixed, remote, no_dsa) \
657 in self.db.cursor().execute(
658 """SELECT package, bug, section, urgency, unstable_vulnerable,
659 testing_security_fixed, remote, no_dsa
660 FROM testing_status"""):
661 if bf.urgencyFiltered(urgency):
662 continue
663 if bf.remoteFiltered(remote):
664 continue
665 if bf.nodsaFiltered(no_dsa):
666 continue
667
668 if pkg_name == old_pkg_name:
669 pkg_name = ''
670 else:
671 old_pkg_name = pkg_name
672 if archive <> 'main':
673 pkg_name = "%s (%s)" % (pkg_name, archive)
674
675 if remote is None:
676 remote = ''
677 elif remote:
678 remote = 'yes'
679 else:
680 remote = 'no'
681
682 if ts_fixed:
683 status = 'fixed in testing-security'
684 else:
685 if sid_vulnerable:
686 status = self.make_red('unstable is vulnerable')
687 else:
688 status = self.make_dangerous('fixed in unstable')
689
690 if urgency == 'unknown':
691 urgency = ''
692
693 yield (pkg_name, self.make_xref(url, bug_name),
694 urgency, remote, status)
695
696 return self.create_page(
697 url, 'Vulnerable source packages in the testing suite',
698 [make_menu(url.scriptRelative,
699 ("status/dtsa-candidates", "Candidates for DTSAs")),
700 bf.actions(url),
701 make_table(gen(), caption=("Package", "Bug", "Urgency",
702 "Remote"))])
703
704 def page_status_release_unstable_like(self, path, params, url,
705 rel, title):
706 bf = BugFilter(params)
707
708 def gen():
709 old_pkg_name = ''
710 for (pkg_name, bug_name, section, urgency, remote) \
711 in self.db.cursor().execute(
712 """SELECT DISTINCT sp.name, st.bug_name,
713 sp.archive, st.urgency,
714 (SELECT range_remote FROM nvd_data
715 WHERE cve_name = st.bug_name)
716 FROM source_package_status AS st, source_packages AS sp
717 WHERE st.vulnerable AND st.urgency <> 'unimportant'
718 AND sp.rowid = st.package AND sp.release = ?
719 AND sp.subrelease = ''
720 ORDER BY sp.name, st.bug_name""", (rel,)):
721 if bf.urgencyFiltered(urgency):
722 continue
723 if bf.remoteFiltered(remote):
724 continue
725
726 if pkg_name == old_pkg_name:
727 pkg_name = ''
728 else:
729 old_pkg_name = pkg_name
730 if section <> 'main':
731 pkg_name = "%s (%s)" % (pkg_name, section)
732 else:
733 pkg_name = self.make_xref(url, pkg_name)
734
735 if remote is None:
736 remote = ''
737 elif remote:
738 remote = 'yes'
739 else:
740 remote = 'no'
741
742 if urgency == 'unknown':
743 urgency = ''
744 elif urgency == 'high':
745 urgency = self.make_red(urgency)
746
747 yield pkg_name, self.make_xref(url, bug_name), urgency, remote
748 return self.create_page(
749 url, title,
750 [P("""Note that the list below is based on source packages.
751 This means that packages are not listed here once a new,
752 fixed source version has been uploaded to the archive, even
753 if there are still some vulnerably binary packages present
754 in the archive."""),
755 bf.actions(url),
756 make_table(gen(), caption=('Package', 'Bug', 'Urgency',
757 'Remote'))])
758
759 def page_status_release_unstable(self, path, params, url):
760 return self.page_status_release_unstable_like(
761 path, params, url,
762 title='Vulnerable source packages in the unstable suite',
763 rel='sid')
764
765 def page_status_release_stable_backports(self, path, params, url):
766 return self.page_status_release_unstable_like(
767 path, params, url,
768 title='Vulnerable source packages among backports for stable',
769 rel='lenny-backports')
770
771 def page_status_dtsa_candidates(self, path, params, url):
772 bf = BugFilter(params)
773
774 def gen():
775 old_pkg_name = ''
776 for (pkg_name, bug_name, archive, urgency, stable_later,
777 remote) \
778 in self.db.cursor().execute(
779 """SELECT package, bug, section, urgency,
780 (SELECT testing.version_id < stable.version_id
781 FROM source_packages AS testing, source_packages AS stable
782 WHERE testing.name = testing_status.package
783 AND testing.release = 'squeeze'
784 AND testing.subrelease = ''
785 AND testing.archive = testing_status.section
786 AND stable.name = testing_status.package
787 AND stable.release = 'lenny'
788 AND stable.subrelease = 'security'
789 AND stable.archive = testing_status.section),
790 (SELECT range_remote FROM nvd_data
791 WHERE cve_name = bug)
792 FROM testing_status
793 WHERE (NOT unstable_vulnerable)
794 AND (NOT testing_security_fixed)"""):
795 if bf.urgencyFiltered(urgency):
796 continue
797 if bf.remoteFiltered(remote):
798 continue
799
800 if pkg_name == old_pkg_name:
801 pkg_name = ''
802 migration = ''
803 else:
804 old_pkg_name = pkg_name
805 migration = A(self.url_testing_status(url, pkg_name),
806 "check")
807 if archive <> 'main':
808 pkg_name = "%s (%s)" % (pkg_name, archive)
809 else:
810 pkg_name = self.make_source_package_ref(url, pkg_name)
811
812 if remote is None:
813 remote = ''
814 elif remote:
815 remote = 'yes'
816 else:
817 remote = 'no'
818
819 if urgency == 'unknown':
820 urgency = ''
821 elif urgency == 'high':
822 urgency = self.make_red(urgency)
823
824 if stable_later:
825 notes = "(fixed in stable?)"
826 else:
827 notes = ''
828
829 yield (pkg_name, migration, self.make_xref(url, bug_name),
830 urgency, remote, notes)
831
832 return self.create_page(
833 url, "Candidates for DTSAs",
834 [P("""The table below lists packages which are fixed
835 in unstable, but unfixed in testing. Use the testing migration
836 checker to find out why they have not entered testing yet."""),
837 make_menu(url.scriptRelative,
838 ("status/release/testing",
839 "List of vulnerable packages in testing")),
840 bf.actions(url),
841 make_table(gen(),
842 caption=("Package", "Migration", "Bug", "Urgency",
843 "Remote"))])
844
845 def page_status_todo(self, path, params, url):
846 hide_check = params.get('hide_check', False)
847 if hide_check:
848 flags = A(url.updateParamsDict({'hide_check' : None}),
849 'Show "check" TODOs')
850 else:
851 flags = A(url.updateParamsDict({'hide_check' : '1'}),
852 'Hide "check" TODOs')
853
854 def gen():
855 for (bug, description) in self.db.getTODOs(hide_check=hide_check):
856 yield self.make_xref(url, bug), description
857 return self.create_page(
858 url, "Bugs with TODO items",
859 [P(flags),
860 make_table(gen(),
861 caption=("Bug", "Description"))])
862
863 def page_status_itp(self, path, params, url):
864 def gen():
865 old_pkg = ''
866 for pkg, bugs, debian_bugs in self.db.getITPs(self.db.cursor()):
867 if pkg == old_pkg:
868 pkg = ''
869 else:
870 old_pkg = pkg
871 yield (pkg, self.make_xref_list(url, bugs),
872 self.make_debian_bug_list(url, debian_bugs))
873 return self.create_page(
874 url, "ITPs with potential security issues",
875 [make_table(gen(), caption=("Package", "Issue", "Debian Bugs"),
876 replacement="No ITP bugs are currently known.")])
877
878 def page_data_unknown_packages(self, path, params, url):
879 def gen():
880 for name, bugs in self.db.getUnknownPackages(self.db.cursor()):
881 yield name, self.make_xref_list(url, bugs)
882 return self.create_page(
883 url, "Unknown packages",
884 [P("""Sometimes, a package referenced in a bug report
885 cannot be found in the database. This can be the result of a spelling
886 error, or a historic entry refers to a
887 package which is no longer in the archive."""),
888 make_table(gen(), caption=("Package", "Bugs"),
889 replacement="No unknown packages are referenced in the database.")])
890
891 def page_data_missing_epochs(self, path, params, url):
892 def gen():
893 old_bug = ''
894 old_pkg = ''
895 for bug, pkg, ver1, ver2 in self.db.cursor().execute(
896 """SELECT DISTINCT bug_name, n.package,
897 n.fixed_version, sp.version
898 FROM package_notes AS n, source_packages AS sp
899 WHERE n.package_kind = 'source'
900 AND n.fixed_version NOT LIKE '%:%'
901 AND n.fixed_version <> '0'
902 AND n.bug_origin = ''
903 AND sp.name = n.package
904 AND sp.version LIKE '%:%'
905 ORDER BY bug_name, package"""):
906 if bug == old_bug:
907 bug = ''
908 else:
909 old_bug = bug
910 old_pkg = ''
911 bug = self.make_xref(url, bug)
912 if pkg == old_pkg:
913 pkg = ''
914 else:
915 old_pkg = pkg
916 pkg = self.make_source_package_ref(url, pkg)
917 yield bug, pkg, ver1, ver2
918
919 return self.create_page(
920 url, "Missing epochs in package versions",
921 [make_table(gen(),
922 caption=("Bug", "Package", "Version 1", "Version 2"),
923 replacement="No source package version with missing epochs.")])
924
925 def page_data_latently_vulnerable(self, path, params, url):
926 def gen():
927 for pkg, bugs in self.db.cursor().execute(
928 """SELECT package, string_set(bug_name)
929 FROM package_notes AS p1
930 WHERE release <> ''
931 AND (bug_name LIKE 'CVE-%' OR bug_name LIKE 'TEMP-%')
932 AND NOT EXISTS (SELECT 1 FROM package_notes AS p2
933 WHERE p2.bug_name = p1.bug_name
934 AND p2.package = p1.package
935 AND release = '')
936 AND EXISTS (SELECT 1 FROM source_packages
937 WHERE name = p1.package AND release = 'sid')
938 GROUP BY package
939 ORDER BY package"""):
940 pkg = self.make_source_package_ref(url, pkg)
941 bugs = bugs.split(',')
942 yield pkg, self.make_xref_list(url, bugs)
943
944 def gen_unimportant():
945 for pkg, bugs in self.db.cursor().execute(
946 """SELECT package, string_set(bug_name)
947 FROM package_notes AS p1
948 WHERE release <> ''
949 AND urgency <> 'unimportant'
950 AND (bug_name LIKE 'CVE-%' OR bug_name LIKE 'TEMP-%')
951 AND EXISTS (SELECT 1 FROM package_notes AS p2
952 WHERE p2.bug_name = p1.bug_name
953 AND p2.package = p1.package
954 AND release = '')
955 AND NOT EXISTS (SELECT 1 FROM package_notes AS p2
956 WHERE p2.bug_name = p1.bug_name
957 AND p2.package = p1.package
958 AND urgency <> 'unimportant'
959 AND release = '')
960 AND EXISTS (SELECT 1 FROM source_packages
961 WHERE name = p1.package AND release = 'sid')
962 GROUP BY package
963 ORDER BY package"""):
964 pkg = self.make_source_package_ref(url, pkg)
965 bugs = bugs.split(',')
966 yield pkg, self.make_xref_list(url, bugs)
967
968 return self.create_page(
969 url, "Latently vulnerable packages in unstable",
970 [P(
971 """A package is latently vulnerable in unstable if it is vulnerable in
972 any release, and there is no package note for the same vulnerability
973 and package in unstable (and the package is still available in
974 unstable, of course)."""),
975 make_table(gen(),
976 caption=("Package", "Bugs"),
977 replacement="No latently vulnerable packages were found."),
978 P(
979 """The next table lists issues which are marked unimportant for
980 unstable, but for which release-specific annotations exist which are
981 not unimportant."""),
982 make_table(gen_unimportant(),
983 caption=("Package", "Bugs"),
984 replacement=
985 "No packages with unimportant latent vulnerabilities were found."),
986 ])
987
988 def page_data_releases(self, path, params, url):
989 def gen():
990 for (rel, subrel, archive, sources, archs) \
991 in self.db.availableReleases():
992 if sources:
993 sources = 'yes'
994 else:
995 sources = 'no'
996 yield rel, subrel, archive, sources, make_list(archs)
997 return self.create_page(
998 url, "Available releases",
999 [P("""The security issue database is checked against
1000 the Debian releases listed in the table below."""),
1001 make_table(gen(),
1002 caption=("Release", "Subrelease", "Archive",
1003 "Sources", "Architectures"))])
1004
1005 def page_data_funny_versions(self, path, params, url):
1006 def gen():
1007 for name, release, archive, version, source_version \
1008 in self.db.getFunnyPackageVersions():
1009 yield name, release, archive, source_version, version
1010
1011 return self.create_page(
1012 url, "Version conflicts between source/binary packages",
1013 [P("""The table below lists source packages
1014 which have a binary package of the same name, but with a different
1015 version. This means that extra care is necessary to determine
1016 the version of a package which has been fixed. (Note that
1017 the bug tracker prefers source versions to binary versions
1018 in this case.)"""),
1019 make_table(gen(),
1020 caption=("Package",
1021 "Release",
1022 "Archive",
1023 "Source Version",
1024 "Binary Version")),
1025 P("""Technically speaking, these version numbering is fine,
1026 but it makes version-based bug tracking quite difficult for these packages."""),
1027 P("""There are many binary packages which are built from source
1028 packages with different version numbering schemes. However, as
1029 long as none of the binary packages carries the same name as the
1030 source package, most confusion is avoided or can be easily
1031 explained.""")])
1032
1033 def page_data_fake_names(self, path, params, url):
1034 def gen():
1035 for (bug, description) in self.db.getFakeBugs():
1036 yield self.make_xref(url, bug), description
1037 return self.create_page(
1038 url, "Automatically generated issue names",
1039 [P("""Some issues have not been assigned CVE names, but are still
1040 tracked by this database. In this case, the system automatically assigns
1041 a unique name. These names are not stable and can change when the database
1042 is updated, so they should not be used in external references."""),
1043 P('''The automatically generated names come in two flavors:
1044 the first kind starts with the string "''', CODE("TEMP-000000-"),
1045 '''". This means that no Debian bug has been assigned to this
1046 issue (or a bug has been created and is not recorded in this database).
1047 In the second kind of names, there is a Debian bug for the issue, and the "''',
1048 CODE("000000"), '''"part of the name is replaced with the
1049 Debian bug number.'''),
1050 make_table(gen(),
1051 caption=("Bug", "Description"))])
1052
1053 def page_debsecan(self, path, params, url):
1054 obj = '/'.join(path)
1055 data = self.db.getDebsecan(obj)
1056 if data:
1057 return BinaryResult(data)
1058 else:
1059 return self.create_page(
1060 url, "Object not found",
1061 [P("The requested debsecan object has not been found.")],
1062 status=404)
1063
1064 def create_page(self, url, title, body, search_in_page=False, status=200):
1065 append = body.append
1066 append(HR())
1067 if not search_in_page:
1068 append(self.make_search_button(url))
1069 append(P(A(url.scriptRelative(""), "Home"),
1070 " - ", A(url.absolute("http://secure-testing.debian.net/"),
1071 "Testing Security Team"),
1072 " - ", A(url.absolute("http://www.debian.org/security/"),
1073 "Debian Security"),
1074 " - ", A(url.absolute
1075 ("http://www.enyo.de/fw/impressum.html"),
1076 "Imprint")))
1077 if search_in_page:
1078 on_load = "selectSearch()"
1079 else:
1080 on_load = None
1081 return HTMLResult(self.add_title(title, body,
1082 head_contents=self.head_contents,
1083 body_attribs={'onload': on_load}),
1084 doctype=self.html_dtd(),
1085 status=status)
1086
1087 def make_search_button(self, url):
1088 return FORM("Search for package or bug name: ",
1089 INPUT(type='text', name='query',
1090 onkeyup="onSearch(this.value)",
1091 onmousemove="onSearch(this.value)"),
1092 INPUT(type='submit', value='Go'),
1093 ' ',
1094 A(url.scriptRelative("data/report"), "Reporting problems"),
1095 method='get',
1096 action=url.scriptRelative(''))
1097
1098 def url_cve(self, url, name):
1099 return url.absolute("http://cve.mitre.org/cgi-bin/cvename.cgi",
1100 name=name)
1101 def url_nvd(self, url, name):
1102 return url.absolute("http://web.nvd.nist.gov/view/vuln/detail",
1103 vulnId=name)
1104
1105 def url_dsa(self, url, dsa, re_dsa=re.compile(r'^DSA-(\d+)(?:-\d+)?$')):
1106 match = re_dsa.match(dsa)
1107 if match:
1108 # We must determine the year because there is no generic URL.
1109 (number,) = match.groups()
1110 for (date,) in self.db.cursor().execute(
1111 "SELECT release_date FROM bugs WHERE name = ?", (dsa,)):
1112 (y, m, d) = date.split('-')
1113 return url.absolute("http://www.debian.org/security/%d/dsa-%d"
1114 % (int(y), int(number)))
1115 return None
1116
1117 def url_debian_bug(self, url, debian):
1118 return url.absolute("http://bugs.debian.org/cgi-bin/bugreport.cgi",
1119 bug=str(debian))
1120 def url_debian_bug_pkg(self, url, debian):
1121 return url.absolute("http://bugs.debian.org/cgi-bin/pkgreport.cgi",
1122 pkg=debian)
1123 def url_pts(self, url, package):
1124 return url.absolute("http://packages.qa.debian.org/common/index.html",
1125 src=package)
1126 def url_testing_status(self, url, package):
1127 return url.absolute("http://release.debian.org/migration/testing.pl",
1128 package=package)
1129 def url_source_package(self, url, package, full=False):
1130 if full:
1131 return url.scriptRelativeFull("source-package/" + package)
1132 else:
1133 return url.scriptRelative("source-package/" + package)
1134 def url_binary_package(self, url, package, full=False):
1135 if full:
1136 return url.scriptRelativeFull("binary-package/" + package)
1137 else:
1138 return url.scriptRelative("binary-package/" + package)
1139
1140 def make_xref(self, url, name):
1141 return A(url.scriptRelative(name), name)
1142
1143 def make_xref_list(self, url, lst, separator=', '):
1144 return make_list(map(lambda x: self.make_xref(url, x), lst), separator)
1145
1146 def make_debian_bug(self, url, debian):
1147 return A(self.url_debian_bug(url, debian), str(debian))
1148 def make_debian_bug_list(self, url, lst):
1149 return make_list(map(lambda x: self.make_debian_bug(url, x), lst))
1150
1151 def make_cve_ref(self, url, cve, name=None):
1152 if name is None:
1153 name = cve
1154 return A(self.url_cve(url, cve), name)
1155
1156 def make_nvd_ref(self, url, cve, name=None):
1157 if name is None:
1158 name = cve
1159 return A(self.url_nvd(url, cve), name)
1160
1161 def make_dsa_ref(self, url, dsa, name=None):
1162 if name is None:
1163 name = dsa
1164 u = self.url_dsa(url, dsa)
1165 if u:
1166 return A(u, name)
1167 else:
1168 return name
1169
1170 def make_pts_ref(self, url, pkg, name=None):
1171 if name is None:
1172 name = pkg
1173 return A(self.url_pts(url, pkg), name)
1174
1175 def make_source_package_ref(self, url, pkg, title=None):
1176 if title is None:
1177 title = pkg
1178 return A(self.url_source_package(url, pkg), title)
1179 def make_binary_package_ref(self, url, pkg, title=None):
1180 if title is None:
1181 title = pkg
1182 return A(self.url_binary_package(url, pkg), title)
1183 def make_binary_packages_ref(self, url, lst):
1184 assert type(lst) <> types.StringType
1185 return make_list(map(lambda x: self.make_binary_package_ref(url, x),
1186 lst))
1187
1188 def make_red(self, contents):
1189 return SPAN(contents, _class="red")
1190
1191 def make_dangerous(self, contents):
1192 return SPAN(contents, _class="dangerous")
1193
1194 def pre_dispatch(self):
1195 self.db.refresh()
1196
1197 TrackerService(socket_name, db_name).run()

Properties

Name Value
svn:mime-type text/script

  ViewVC Help
Powered by ViewVC 1.1.5