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

Contents of /bin/tracker_service.py

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:mime-type text/script

  ViewVC Help
Powered by ViewVC 1.1.5