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

Contents of /bin/tracker_service.py

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:mime-type text/script

  ViewVC Help
Powered by ViewVC 1.1.5