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

Contents of /bin/tracker_service.py

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:mime-type text/script

  ViewVC Help
Powered by ViewVC 1.1.5